Java、99.04 98.46 97.66 LCS()の呼び出し
使い方
例:再構築されるラインは00101
です。最初に、ゼロのみのstringと比較することにより、ゼロの数を調べます(ここでは、=オリジナルの文字列と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
最適化
これは単なる「単純な」実装です。おそらく、複数の位置を一度にチェックするより洗練されたアルゴリズムを見つけることができるでしょう。しかし、本当にあるかどうかはわかりませんあなたは常にだけ評価できるように、(例えばハミングコードに似たパリティビットの計算に基づいて)、より良い1 の長さを、共通部分文字列のを。
与えられた1行の数字に対して、このアルゴリズムは正確に必要です #ofDigitsUntilTheLastOccurenceOf1 + 1
チェックます。(最後の桁がの場合は、1を減算し1
ます。)
編集:1つの小さな最適化:最後の2番目の数字をチェックしただけで、まだ挿入する必要がある場合 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();;
}
}
}