Java中,99.04 98.46 97.66 LCS()调用
怎么运行的
例如:我们要重建的线是00101
。首先,通过将零与仅零字符串进行比较(在这里=将lcs与原始字符串进行比较),找出有多少个零00000
。然后我们遍历每个位置,将其翻转0
到a 1
并检查我们现在是否具有更长的公共子字符串。如果是,则接受并转到下一个位置;如果否,则将当前值翻转1
回a 0
并转到下一个位置:
For our example of "00101" we get following steps:
input lcs prev.'best'
00000 3 0 //number of zeros
̲10000 3 3 //reject
0̲1000 3 3 //reject
00̲100 4 3 //accept
001̲10 4 4 //reject
0010̲1 5 4 //accept
最佳化
这仅仅是“天真”的实现,也许有可能找到一次更复杂的算法来一次检查多个位置。但我不知道是否有真的是一个更好的(例如,基于类似海明码奇偶校验位计算),你可以永远只是评估长度的共同子串的。
对于一个给定的数字行,此算法需要精确#ofDigitsUntilTheLastOccurenceOf1 + 1
检查。(如果最后一位是,请减去一个1
。)
编辑:一个小的优化:如果我们只是检查了倒数第二位,并且我们仍然需要插入a 1
,我们肯定会知道它必须在最后一个位置,并且可以省略相应的检查。
EDIT2:我刚刚注意到您可以将上述想法应用到最后k
一个想法。
当然,通过首先对所有行进行重新排序,使用此优化程序当然可能会获得稍低的分数,因为这样可以使您最终获得更多行,但显然这是当前的优化测试用例,这不再是有趣的。
运行
上限为O(#NumberOfBits)
。
完整代码
这里是完整的代码:
package jcodegolf;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
// http://codegolf.stackexchange.com/questions/69799/know-a-sequence-by-its-subsequences
public class SequenceReconstructor {
public static int counter = 0;
public static int lcs(String a, String b) { //stolen from http://rosettacode.org/wiki/Longest_common_subsequence#Java
int[][] lengths = new int[a.length()+1][b.length()+1];
// row 0 and column 0 are initialized to 0 already
for (int i = 0; i < a.length(); i++)
for (int j = 0; j < b.length(); j++)
if (a.charAt(i) == b.charAt(j))
lengths[i+1][j+1] = lengths[i][j] + 1;
else
lengths[i+1][j+1] =
Math.max(lengths[i+1][j], lengths[i][j+1]);
// read the substring out from the matrix
StringBuffer sb = new StringBuffer();
for (int x = a.length(), y = b.length();
x != 0 && y != 0; ) {
if (lengths[x][y] == lengths[x-1][y])
x--;
else if (lengths[x][y] == lengths[x][y-1])
y--;
else {
assert a.charAt(x-1) == b.charAt(y-1);
sb.append(a.charAt(x-1));
x--;
y--;
}
}
counter ++;
return sb.reverse().toString().length();
}
public static String reconstruct(String secretLine, int lineLength){
int current_lcs = 0;
int previous_lcs = 0;
char [] myGuess = new char[lineLength];
for (int k=0; k<lineLength; k++){
myGuess[k] = '0';
}
//find the number of zeros:
int numberOfZeros = lcs(secretLine, String.valueOf(myGuess));
current_lcs = numberOfZeros;
previous_lcs = numberOfZeros;
if(current_lcs == lineLength){ //were done
return String.valueOf(myGuess);
}
int numberOfOnes = lineLength - numberOfZeros;
//try to greedily insert ones at the positions where they maximize the common substring length
int onesCounter = 0;
for(int n=0; n < lineLength && onesCounter < numberOfOnes; n++){
myGuess[n] = '1';
current_lcs = lcs(secretLine, String.valueOf(myGuess));
if(current_lcs > previous_lcs){ //accept
previous_lcs = current_lcs;
onesCounter ++;
} else { // do not accept
myGuess[n]='0';
}
if(n == lineLength-(numberOfOnes-onesCounter)-1 && onesCounter < numberOfOnes){ //lets test if we have as many locations left as we have ones to insert
// then we know that the rest are ones
for(int k=n+1;k<lineLength;k++){
myGuess[k] = '1';
}
break;
}
}
return String.valueOf(myGuess);
}
public static void main(String[] args) {
try {
//read the file
BufferedReader br;
br = new BufferedReader(new FileReader("PATH/TO/YOUR/FILE/LOCATION/subsequence_data.txt"));
String line;
//iterate over each line
while ( (line = br.readLine()) != null){
String r = reconstruct(line, line.length());
System.out.println(line); //print original line
System.out.println(r); //print current line
System.out.println(counter/100.0); //print current number of calls
if (! line.equals(r)){
System.out.println("SOMETHING WENT HORRIBLY WRONG!!!");
System.exit(1);
}
}
} catch(Exception e){
e.printStackTrace();;
}
}
}