Jawaban ini saat ini rusak karena bug. Memperbaiki segera ...
C, 2 string dalam ~ 35 detik
Ini sangat banyak pekerjaan yang sedang berlangsung (seperti yang ditunjukkan oleh kekacauan yang mengerikan), tetapi mudah-mudahan itu memicu beberapa jawaban yang bagus!
Kode:
#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;
}
Fungsi yang relevan yang melakukan semua perhitungan LCS adalah fungsi LCS
. Kode di atas akan mengatur waktu panggilannya sendiri ke fungsi ini.
Simpan sebagai main.c
dan kompilasi dengan:gcc -Ofast main.c -o FLCS
Kode dapat dijalankan dengan argumen baris perintah atau melalui stdin. Saat menggunakan stdin, ia mengharapkan sejumlah string diikuti oleh string itu sendiri.
~ Me$ ./FLCS "12345" "23456"
2345
Size: 4
Elapsed time on LCS call: 0.000056 s
Atau:
~ Me$ ./FLCS
6
2341582491248123139182371298371239813
2348273123412983476192387461293472793
1234123948719873491234120348723412349
1234129388234888234812834881423412373
1111111112341234128469128377293477377
1234691237419274737912387476371777273
1241231212323
Size: 13
Elapsed time on LCS call: 0.001594 s
Pada kotak Mac OS X dengan 1.7Ghz Intel Core i7 dan test case yang disediakan Dennis, kami mendapatkan output berikut untuk 2 string:
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
Pendekatannya sangat mirip dengan pendekatan saya dengan tantangan sebelumnya, di sini . Selain pengoptimalan sebelumnya, kami sekarang memeriksa jumlah total karakter yang dibagi antara string di setiap rekursi dan keluar lebih awal jika tidak ada cara untuk mendapatkan substring yang lebih lama daripada yang sudah ada.
Untuk saat ini, ia menangani 2 string, tetapi cenderung mengalami crash-y pada lebih banyak. Lebih banyak peningkatan dan penjelasan yang lebih baik untuk datang!