現在、この答えはバグが原因で壊れています。すぐに修正しています...
C、最大35秒で2つのストリング
これは非常に進行中の作業です(恐ろしい混乱によって示されているように)が、うまくいけば、いくつかの良い答えが得られます!
コード:
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
#include "time.h"
/* For the versatility */
#define MIN_CODEPOINT 0x30
#define MAX_CODEPOINT 0x3F
#define NUM_CODEPOINT (MAX_CODEPOINT - MIN_CODEPOINT + 1)
#define CTOI(c) (c - MIN_CODEPOINT)
#define SIZE_ARRAY(x) (sizeof(x) / sizeof(*x))
int LCS(char** str, int num);
int getshared(char** str, int num);
int strcount(char* str, char c);
int main(int argc, char** argv) {
char** str = NULL;
int num = 0;
int need_free = 0;
if (argc > 1) {
str = &argv[1];
num = argc - 1;
}
else {
scanf(" %d", &num);
str = malloc(sizeof(char*) * num);
if (!str) {
printf("Allocation error!\n");
return 1;
}
int i;
for (i = 0; i < num; i++) {
/* No string will exceed 1000 characters */
str[i] = malloc(1001);
if (!str[i]) {
printf("Allocation error!\n");
return 1;
}
scanf(" %1000s", str[i]);
str[i][1000] = '\0';
}
need_free = 1;
}
clock_t start = clock();
/* The call to LCS */
int size = LCS(str, num);
double dt = ((double)(clock() - start)) / CLOCKS_PER_SEC;
printf("Size: %d\n", size);
printf("Elapsed time on LCS call: %lf s\n", dt);
if (need_free) {
int i;
for (i = 0; i < num; i++) {
free(str[i]);
}
free(str);
}
return 0;
}
/* Some terribly ugly global variables... */
int depth, maximum, mapsize, lenmap[999999][2];
char* (strmap[999999][20]);
char outputstr[1000];
/* Solves the LCS problem on num strings str of lengths len */
int LCS(char** str, int num) {
/* Counting variables */
int i, j;
if (depth + getshared(str, num) <= maximum) {
return 0;
}
char* replace[num];
char match;
char best_match = 0;
int earliest_set = 0;
int earliest[num];
int all_late;
int all_early;
int future;
int best_future = 0;
int need_future = 1;
for (j = 0; j < mapsize; j++) {
for (i = 0; i < num; i++)
if (str[i] != strmap[j][i])
break;
if (i == num) {
best_match = lenmap[j][0];
best_future = lenmap[j][1];
need_future = 0;
if (best_future + depth < maximum || !best_match)
goto J;
else {
match = best_match;
goto K;
}
}
}
for (match = MIN_CODEPOINT; need_future && match <= MAX_CODEPOINT; match++) {
K:
future = 1;
all_late = earliest_set;
all_early = 1;
for (i = 0; i < num; replace[i++]++) {
replace[i] = strchr(str[i], match);
if (!replace[i]) {
future = 0;
break;
}
if (all_early && earliest_set && replace[i] - str[i] > earliest[i])
all_early = 0;
if (all_late && replace[i] - str[i] < earliest[i])
all_late = 0;
}
if (all_late) {
future = 0;
}
I:
if (future) {
if (all_early || !earliest_set) {
for (i = 0; i < num; i++) {
earliest[i] = (int)(replace[i] - str[i]);
}
}
/* The recursive bit */
depth++;
future += LCS(replace, num);
depth--;
best_future = future > best_future ? (best_match = match), future : best_future;
}
}
if (need_future) {
for (i = 0; i < num; i++)
strmap[mapsize][i] = str[i];
lenmap[mapsize][0] = best_match;
lenmap[mapsize++][1] = best_future;
}
J:
if (depth + best_future >= maximum) {
maximum = depth + best_future;
outputstr[depth] = best_match;
}
if (!depth) {
mapsize = 0;
maximum = 0;
puts(outputstr);
}
return best_future;
}
/* Return the number of characters total (not necessarily in order) that the strings all share */
int getshared(char** str, int num) {
int c, i, tot = 0, min;
for (c = MIN_CODEPOINT; c <= MAX_CODEPOINT; c++) {
min = strcount(str[0], c);
for (i = 1; i < num; i++) {
int count = strcount(str[i], c);
if (count < min) {
min = count;
}
}
tot += min;
}
return tot;
}
/* Count the number of occurrences of c in str */
int strcount(char* str, char c) {
int tot = 0;
while ((str = strchr(str, c))) {
str++, tot++;
}
return tot;
}
すべてのLCS計算を実行する関連関数は関数LCS
です。上記のコードは、この関数への独自の呼び出しのタイミングを取ります。
名前を付けて保存しmain.c
てコンパイル:gcc -Ofast main.c -o FLCS
コードは、コマンドライン引数を使用するか、stdinを使用して実行できます。stdinを使用する場合、多くの文字列に続いて文字列自体が必要です。
~ Me$ ./FLCS "12345" "23456"
2345
Size: 4
Elapsed time on LCS call: 0.000056 s
または:
~ Me$ ./FLCS
6
2341582491248123139182371298371239813
2348273123412983476192387461293472793
1234123948719873491234120348723412349
1234129388234888234812834881423412373
1111111112341234128469128377293477377
1234691237419274737912387476371777273
1241231212323
Size: 13
Elapsed time on LCS call: 0.001594 s
1.7Ghz Intel Core i7を搭載したMac OS Xボックスとデニスが提供したテストケースでは、2つの文字列に対して次の出力が得られます。
16638018800200>3??32322701784=4240;24331395?<;=99=?;178675;866002==23?87?>978891>=9<66=381992>>7030829?25265804:=3>:;60<9384=081;08?66=51?0;509072488>2>924>>>3175?::<9199;330:494<51:>748571?153994<45<??20>=3991=<962508?7<2382?489
Size: 386
Elapsed time on LCS call: 33.245087 s
ここでのアプローチは、以前の課題に対する私のアプローチと非常によく似ています。以前の最適化に加えて、すべての再帰で文字列間の共有文字の総数を確認し、既存のものよりも長い部分文字列を取得する方法がない場合は早期に終了します。
現時点では、2つの文字列を処理できますが、さらにクラッシュする傾向があります。より多くの改善と今後のより良い説明!