C, 618 564 ไบต์
d,M,N,A[9999][2];char*(R[9999][20]),b[1000];L(char**s,n){char*j[20],c,a=0;int x[n],y=n-1,z,i,t,m=0,w=1;for(;y;)x[y--]=999;for(;y<N;y++){for(i=0;i<n&&s[i]==R[y][i];i++);if(i/n){a=A[y][0];m=A[y][1];w=0;if(m+d<M||!a)goto J;else{c=a;goto K;}}}for(c=97;w&&c<'{';c++){K:t=1,y=1,z=1;for(i=0;i<n;j[i++]++){for(j[i]=s[i];*j[i]-c;j[i]++)t&=!!*j[i];y&=j[i]-s[i]>x[i]?z=0,1:0;}t&=!y;I:if(t){if(z)for(i=0;i<n;i++)x[i]=j[i]-s[i];d++,t+=L(j,n),d--,m=t>m?a=c,t:m;}}if(w){for(y=0;y<n;y++)R[N][y]=s[y];A[N][0]=a;A[N++][1]=m;}J:if(d+m>=M)M=d+m,b[d]=a;if(!d)N=0,M=0,puts(b);return m;}
และนี่มัน unraveled สำหรับ "อ่าน":
d,M,N,A[9999][2];
char*(R[9999][20]),b[1000];
L(char**s,n){
    char*j[20],c,a=0;
    int x[n],y=n-1,z,i,t,m=0,w=1;
    for(;y;)
        x[y--]=999;
    for(;y<N;y++){
        for(i=0;i<n&&s[i]==R[y][i];i++);
        if(i/n){
            a=A[y][0];
            m=A[y][1];
            w=0;
            if(m+d<M||!a)
                goto J;
            else{
                c=a;
                goto K;
            }
        }
    }
    for(c=97;w&&c<'{';c++){
        K:
        t=1,
        y=1,
        z=1;
        for(i=0;i<n;j[i++]++){
            for(j[i]=s[i];*j[i]-c;j[i]++)
                t&=!!*j[i];
            y&=j[i]-s[i]>x[i]?z=0,1:0;
        }
        t&=!y;
        I:
        if(t){
            if(z)
                for(i=0;i<n;i++)
                    x[i]=j[i]-s[i];
            d++,
            t+=L(j,n),
            d--,
            m=t>m?a=c,t:m;
        }
    }
    if(w){
        for(y=0;y<n;y++)R[N][y]=s[y];
        A[N][0]=a;
        A[N++][1]=m;
    }
    J:
    if(d+m>=M)
        M=d+m,b[d]=a;
    if(!d)
        N=0,M=0,puts(b);
    return m;
}
ท่านสุภาพบุรุษและสุภาพสตรีฉันทำผิดพลาดอย่างน่ากลัว มันใช้จะเป็นสวย ... และกลับไปข้างน้อย ... อย่างน้อยตอนนี้ก็เป็นไปอย่างรวดเร็ว
เรากำหนดฟังก์ชั่นวนซ้ำLที่ใช้เป็นอาร์เรย์sของอาร์เรย์ของตัวละครและจำนวนnของสตริง ฟังก์ชันส่งออกสตริงผลลัพธ์ไปที่ stdout และส่งคืนขนาดเป็นอักขระของสตริงนั้นโดยบังเอิญ
วิธีการ
แม้ว่ารหัสจะซับซ้อน แต่กลยุทธ์ที่นี่ไม่ซับซ้อนเกินไป เราเริ่มต้นด้วยอัลกอริทึมแบบเรียกซ้ำที่ค่อนข้างไร้เดียงสาซึ่งฉันจะอธิบายด้วย pseudocode:
Function L (array of strings s, number of strings n), returns length:
Create array of strings j of size n;
For each character c in "a-z",
    For each integer i less than n,
         Set the i'th string of j to the i'th string of s, starting at the first appearance of c in s[i]. (e.g. j[i][0] == c)
         If c does not occur in the i'th string of s, continue on to the next c.
    end For
    new_length := L( j, n ) + 1; // (C) t = new_length
    if new_length > best_length
        best_character := c; // (C) a = best_character
        best_length := new_length; // (C) m = best_length
    end if
end For
// (C) d = current_depth_in_recursion_tree
if best_length + current_depth_in_recursion_tree >= best_found
     prepend best_character to output_string // (C) b = output_string
     // (C) M = best_found, which represents the longest common substring found at any given point in the execution.
     best_found = best_length + current_depth;
end if
if current_depth_in_recursion_tree == 0
    reset all variables, print output_string
end if 
return best_length
ตอนนี้อัลกอริทึมของตัวเองมันค่อนข้างโหดเหี้ยม (แต่สามารถอยู่ได้ประมาณ 230 ไบต์ฉันพบ) นี่ไม่ใช่วิธีการที่ได้รับผลลัพธ์ที่รวดเร็ว อัลกอริทึมนี้ปรับขนาดได้ไม่ดีอย่างเหลือเชื่อด้วยความยาวสตริง อย่างไรก็ตามอัลกอริทึมนี้สามารถปรับขนาดได้ค่อนข้างดีกับสตริงจำนวนมากขึ้น กรณีทดสอบสุดท้ายจะได้รับการแก้ไขทันทีในทันทีเนื่องจากไม่มีสายอักขระsใดที่cเหมือนกัน มีสองเทคนิคหลักที่ฉันได้นำไปใช้ข้างต้นทำให้ความเร็วเพิ่มขึ้นอย่างไม่น่าเชื่อ:
ทุกครั้งที่โทรไปLตรวจสอบว่าเราได้รับอินพุตเดียวกันนี้มาก่อนหรือไม่ เนื่องจากในทางปฏิบัติข้อมูลจะถูกส่งไปรอบ ๆ ผ่านตัวชี้ไปยังชุดเดียวกันของสตริงเราไม่จริงต้องเปรียบเทียบสตริงสถานที่เพียงซึ่งเป็นที่ดี หากเราพบว่าเราได้รับข้อมูลนี้มาก่อนไม่จำเป็นต้องผ่านการคำนวณ (ส่วนใหญ่ แต่การเอาท์พุททำให้สิ่งนี้ซับซ้อนขึ้นอีกเล็กน้อย) และเราสามารถหนีไปได้ด้วยการส่งความยาวกลับมา หากเราไม่พบข้อมูลที่ตรงกันให้บันทึกชุดอินพุต / เอาต์พุตนี้เพื่อเปรียบเทียบกับการโทรในอนาคต ในรหัส C forวงที่สองพยายามค้นหาการจับคู่กับอินพุต พอยน์เตอร์อินพุตที่ทราบจะถูกบันทึกRและความยาวและค่าเอาต์พุตอักขระที่สอดคล้องกันจะถูกเก็บไว้A. แผนนี้มีผลอย่างมากต่อรันไทม์โดยเฉพาะกับสตริงที่ยาวกว่า
 
ทุกครั้งที่เราหาสถานที่ของcในsมีโอกาสที่เรารู้ทันทีทันใดว่าสิ่งที่เราได้พบไม่ได้ดีที่สุด หากตำแหน่งทั้งหมดcปรากฏขึ้นหลังจากตำแหน่งที่ทราบของตัวอักษรอื่นเรารู้โดยอัตโนมัติว่าสิ่งนี้cไม่นำไปสู่สตริงย่อยที่ดีที่สุดเพราะคุณสามารถใส่ตัวอักษรอีกหนึ่งตัวในนั้นได้ ซึ่งหมายความว่าสำหรับค่าใช้จ่ายเล็กน้อยเราอาจลบการโทรหลายร้อยครั้งLสำหรับสายใหญ่ ในรหัส C ด้านบนyเป็นชุดธงหากเรารู้โดยอัตโนมัติว่าตัวละครนี้นำไปสู่สตริงย่อยและzเป็นชุดธงหากเราพบว่าตัวละครที่มีลักษณะก่อนหน้านี้เฉพาะกว่าตัวละครอื่น ๆ ที่รู้จักกัน อักขระที่ปรากฏเร็วสุดในปัจจุบันจะถูกเก็บไว้ในx. การนำแนวคิดนี้ไปปฏิบัติในปัจจุบันค่อนข้างยุ่งเหยิง แต่มีประสิทธิภาพเพิ่มขึ้นเกือบสองเท่าในหลาย ๆ กรณี
 
ด้วยแนวคิดทั้งสองนี้สิ่งที่ไม่เสร็จในหนึ่งชั่วโมงใช้เวลาประมาณ 0.015 วินาที
อาจมีลูกเล่นเล็ก ๆ น้อย ๆ มากมายที่สามารถเร่งความเร็วการแสดงได้ แต่ ณ จุดนี้ฉันเริ่มกังวลเกี่ยวกับความสามารถในการเล่นกอล์ฟของฉันทุกอย่าง ฉันยังไม่พอใจกับกอล์ฟดังนั้นฉันจะกลับมาที่นี่อีกในภายหลัง!
การกำหนดเวลา
นี่คือโค้ดทดสอบบางตัวที่ฉันเชิญให้คุณลองออนไลน์ :
#include "stdio.h"
#include "time.h"
#define SIZE_ARRAY(x) (sizeof(x) / sizeof(*x))
int main(int argc, char** argv) {
    /* Our test case */
    char* test7[] = {
        "nqrualgoedlf",
        "jgqorzglfnpa",
        "fgttvnogldfx",
        "pgostsulyfug",
        "sgnhoyjlnfvr",
        "wdttgkolfkbt"
    };
    printf("Test 7:\n\t");
    clock_t start = clock();
    /* The call to L */
    int size = L(test7, SIZE_ARRAY(test7));
    double dt = ((double)(clock() - start)) / CLOCKS_PER_SEC;
    printf("\tSize: %d\n", size);
    printf("\tElapsed time: %lf s\n", dt);
    return 0;
}
ฉันใช้เคสทดสอบของ OP บนแล็ปท็อปที่ติดตั้งชิป 1.7 GHz Intel Core i7 พร้อมการตั้งค่าที่เหมาะสม-Ofastที่สุด การจำลองรายงานว่าต้องการสูงสุด 712KB นี่คือตัวอย่างการดำเนินการของแต่ละกรณีทดสอบโดยมีการกำหนดเวลา:
Test 1:
    a
    Size: 1
    Elapsed time: 0.000020 s
Test 2:
    x
    Size: 1
    Elapsed time: 0.000017 s
Test 3:
    hecbpyhogntqppcqgkxchpsieuhbmcbhuqdjbrqmclchqyfhtdvdoysuhrrl
    Size: 60
    Elapsed time: 0.054547 s
Test 4:
    ihicvaoodsnktkrar
    Size: 17
    Elapsed time: 0.007459 s
Test 5:
    krkk
    Size: 4
    Elapsed time: 0.000051 s
Test 6:
    code
    Size: 4
    Elapsed time: 0.000045 s
Test 7:
    golf
    Size: 4
    Elapsed time: 0.000040 s
Test 8:
    Size: 0
    Elapsed time: 0.000029 s
Total time: 0.062293 s
ในการตีกอล์ฟฉันตีการแสดงค่อนข้างมากและเนื่องจากคนดูเหมือนจะชอบความเร็วเดรัจฉาน (0.013624 วินาทีเพื่อทำกรณีทดสอบทั้งหมดรวมกัน) ของโซลูชัน 618 ไบต์ก่อนหน้าของฉันฉันจะปล่อยไว้ที่นี่เพื่ออ้างอิง:
d,M,N,A[9999][2];char*(R[9999][20]),b[1000];L(char**s,n){char*j[20],c,a=0;int x[n],y,z,i,t,m=0,w=1;for(y=0;y<n;y++)x[y]=999;for(y=0;y<N;y++){for(i=0;i<n;i++)if(s[i]!=R[y][i])break;if(i==n){a=A[y][0];m=A[y][1];w=0;if(m+d<M||!a)goto J;else{c=a;goto K;}}}for(c=97;w&&c<'{';c++){K:t=1,y=1,z=1;for(i=0;i<n;j[i++]++){for(j[i]=s[i];*j[i]-c;j[i]++)if(!*j[i]){t=0;goto I;}if(j[i]-s[i]>x[i])z=0;if(j[i]-s[i]<x[i])y=0;}if(y){t=0;}I:if(t){if(z){for(i=0;i<n;i++){x[i]=j[i]-s[i];}}d++,t+=L(j,n),d--,m=t>m?(a=c),t:m;}}if(w){for(y=0;y<n;y++)R[N][y]=s[y];A[N][0]=a;A[N++][1]=m;}J:if(d+m>=M)M=d+m,b[d]=a;if(!d)N=0,M=0,puts(b);return m;}
อัลกอริธึมเองนั้นไม่เปลี่ยนแปลง แต่รหัสใหม่นั้นขึ้นอยู่กับหน่วยงานและการใช้งานระดับบิตที่ซับซ้อนซึ่งจะทำให้ทุกอย่างช้าลง