การเพิ่มประสิทธิภาพหน่วยความจำที่ จำกัด


9

ระยะห่างของการแก้ไข (หรือ Levenshtein)ระหว่างสองสายคือจำนวนที่น้อยที่สุดของการแทรกอักขระเดียวการลบและการแทนที่ที่จำเป็นในการแปลงสตริงหนึ่งเป็นอีกสตริงหนึ่ง หากทั้งสองสตริงมีความยาว n แต่ละตัวเป็นที่ทราบกันดีว่าสิ่งนี้สามารถทำได้ในเวลา O (n ^ 2) โดยการโปรแกรมแบบไดนามิก รหัสงูใหญ่ต่อไปดำเนินการคำนวณนี้สำหรับสองสายและs1s2

def edit_distance(s1, s2):
    l1 = len(s1)
    l2 = len(s2)

    matrix = [range(l1 + 1)] * (l2 + 1)
    for zz in range(l2 + 1):
      matrix[zz] = range(zz,zz + l1 + 1)
    for zz in range(0,l2):
      for sz in range(0,l1):
        if s1[sz] == s2[zz]:
          matrix[zz+1][sz+1] = min(matrix[zz+1][sz] + 1, matrix[zz][sz+1] + 1, matrix[zz][sz])
        else:
          matrix[zz+1][sz+1] = min(matrix[zz+1][sz] + 1, matrix[zz][sz+1] + 1, matrix[zz][sz] + 1)
    return matrix[l2][l1]

ในภารกิจนี้คุณต้องเข้าใกล้มากที่สุดเท่าที่จะทำได้เพื่อคำนวณระยะทางแก้ไข แต่ด้วยการ จำกัด หน่วยความจำอย่างรุนแรง รหัสของคุณได้รับอนุญาตให้กำหนดหนึ่งอาร์เรย์ที่มีจำนวนเต็ม 1,000 32- บิต 32 บิตและนี่จะเป็นที่เก็บข้อมูลชั่วคราวเพียงอย่างเดียวที่คุณใช้ในการคำนวณของคุณ ตัวแปรและโครงสร้างข้อมูลทั้งหมดจะต้องมีอยู่ในอาร์เรย์นี้ โดยเฉพาะอย่างยิ่งคุณจะไม่สามารถใช้อัลกอริทึมด้านบนสำหรับสตริงที่มีความยาว 1,000 ซึ่งจะทำให้คุณต้องเก็บอย่างน้อย 1,000,000 หมายเลข ในกรณีที่ภาษาของคุณไม่มีจำนวนเต็ม 32 บิต (เช่น Python) ตามธรรมชาติคุณต้องตรวจสอบให้แน่ใจว่าคุณไม่เคยเก็บตัวเลขที่มีขนาดใหญ่กว่า 2 ^ 32-1 ไว้ในอาร์เรย์

คุณสามารถอ่านข้อมูลโดยใช้ไลบรารีมาตรฐานที่คุณเลือกโดยไม่ต้องกังวลเกี่ยวกับข้อ จำกัด ของหน่วยความจำในส่วนนั้น เพื่อให้การแข่งขันมีความยุติธรรมสำหรับส่วนหลักของรหัสของคุณคุณสามารถใช้การดำเนินการที่เทียบเท่ากับการทำงานในภาษาการเขียนโปรแกรม C และไม่สามารถใช้ไลบรารีภายนอกใด ๆ

เพื่อความชัดเจนเป็นพิเศษหน่วยความจำสำหรับจัดเก็บข้อมูลอินพุตหรือใช้โดยล่ามภาษา JVM ของคุณเป็นต้นไม่นับรวมถึงขีด จำกัด ของคุณและคุณไม่สามารถเขียนอะไรลงดิสก์ คุณต้องถือว่าข้อมูลอินพุตเป็นแบบอ่านอย่างเดียวเมื่ออยู่ในหน่วยความจำดังนั้นคุณจึงไม่สามารถนำข้อมูลนั้นกลับมาใช้เพื่อให้มีพื้นที่ทำงานมากขึ้น

ฉันต้องใช้อะไรบ้าง

รหัสของคุณควรอ่านเป็นไฟล์ในรูปแบบต่อไปนี้ มันจะมีสามบรรทัด บรรทัดแรกคือระยะแก้ไขที่แท้จริง ประการที่สองคือสตริงที่ 1 และที่สามคือสตริง 2. ฉันจะทดสอบกับข้อมูลตัวอย่างที่https://bpaste.net/show/6905001d52e8ที่สายมีความยาว 10,000 แต่มันไม่ควรจะพิเศษสำหรับข้อมูลนี้ มันควรจะส่งออกระยะแก้ไขที่เล็กที่สุดที่สามารถหาได้ระหว่างสองสาย

คุณจะต้องพิสูจน์ระยะทางในการแก้ไขของคุณจริง ๆ แล้วมาจากชุดการแก้ไขที่ถูกต้อง รหัสของคุณควรมีสวิตช์ซึ่งเปลี่ยนเป็นโหมดที่อาจใช้หน่วยความจำมากขึ้น (เท่าที่คุณต้องการ) และส่งออกการดำเนินการแก้ไขที่ให้ระยะทางแก้ไขของคุณ

คะแนน

(optimal edit distance/divided by the edit distance you find) * 100คะแนนของคุณจะเป็น ในการเริ่มต้นสิ่งต่าง ๆ สังเกตว่าคุณสามารถรับคะแนนได้โดยนับจำนวนการจับคู่ที่ไม่ตรงกันระหว่างสองสาย

คุณสามารถใช้ภาษาใดก็ได้ที่คุณชอบซึ่งสามารถใช้งานได้อย่างอิสระและติดตั้งง่ายใน Linux

เน็คไททำลาย

ในกรณีที่ไทเบรคฉันจะรันโค้ดของคุณบนเครื่อง Linux และรหัสที่เร็วที่สุดจะเป็นผู้ชนะ


จะfor(int i=0;i<=5;i++)อนุญาตให้ใช้เพราะเก็บข้อมูลไว้iหรือไม่
สลายตัวเบต้า

2
@BetaDecay ใช่แม้ว่าจะปฏิบัติตามกฎอย่างใกล้ชิดคุณจะทำอะไรเช่น{ uint32_t foo[1000]; for (foo[0] = 0; foo[0] < 5; ++foo[0]) printf("%d ", foo[0]); } นี้คือสมมติอาร์เรย์ของคุณ 32 fooจำนวนเต็มบิตจะถูกเรียกว่า

อะไรคือจุดที่มีระยะทางแก้ไขที่แท้จริงในไฟล์? จริง ๆ แล้วโปรแกรมควรอ่านหรือไม่ หรือ (ดูเหมือนว่ามีเหตุผลมากกว่านี้) เป็นเพียงแค่มีให้คุณเห็นว่าโปรแกรมประสบความสำเร็จหรือไม่
feersum

@feersum อย่างแน่นอน มันอยู่ตรงนั้นเพื่อให้คุณสามารถดูว่าคะแนนของคุณนั้นง่ายแค่ไหน

bpaste.net/show/6905001d52e8หน้า 404 ให้ฉัน!
sergiol

คำตอบ:


4

C ++, คะแนน 92.35

การประมาณอัลกอริทึม: อัลกอริทึมค้นหาตำแหน่งแรกที่ทั้งสองสตริงแตกต่างกันและจากนั้นลองการเปลี่ยนลำดับการดำเนินการ N ที่เป็นไปได้ทั้งหมด (แทรกลบแทนที่ - อักขระที่ตรงกันจะถูกข้ามโดยไม่ต้องใช้การดำเนินการ) มันให้คะแนนชุดการดำเนินการที่เป็นไปได้แต่ละชุดโดยขึ้นอยู่กับว่าชุดการดำเนินการไกลออกไปเท่าไรประสบความสำเร็จในการจับคู่ทั้งสองสายรวมถึงความยาวของสตริงที่จะมาบรรจบกัน หลังจากพิจารณาชุดการให้คะแนนสูงสุดของการดำเนินการ N การดำเนินการครั้งแรกในชุดจะพบการไม่ตรงกันถัดไปและกระบวนการทำซ้ำจนกว่าจะถึงจุดสิ้นสุดของสตริง

โปรแกรมจะลองใช้ค่าทั้งหมดของ N ตั้งแต่ 1-10 และเลือกระดับที่ให้ผลลัพธ์ที่ดีที่สุด โดยทั่วไปแล้ว N = 10 เป็นวิธีที่ดีที่สุดในขณะนี้ที่วิธีการให้คะแนนพิจารณาความยาวของสตริง ค่าที่สูงขึ้นของ N อาจจะดีกว่านี้ แต่ใช้เวลามากขึ้นในการอธิบาย

การใช้หน่วยความจำ: เนื่องจากโปรแกรมซ้ำอย่างหมดจดจึงต้องการหน่วยความจำน้อยมาก ใช้ตัวแปรเพียง 19 ตัวเพื่อติดตามสถานะของโปรแกรม สิ่งเหล่านี้ถูกกำหนดโดย #defines เพื่อทำหน้าที่เป็นตัวแปรระดับโลก

การใช้งาน: โปรแกรมนี้ใช้เช่นเดียวกับ feersum's: พารามิเตอร์แรกจะถือว่าเป็นไฟล์และพารามิเตอร์เพิ่มเติมใด ๆ บ่งชี้ว่าการแก้ไขควรจะแสดง โปรแกรมจะพิมพ์ระยะแก้ไขโดยประมาณและคะแนนเสมอ

เอาต์พุตการตรวจสอบ: ผลลัพธ์การตรวจสอบที่จัดรูปแบบในสามแถว:

11011111100101100111100110100 110 0 0000   0 01101
R I          IR     R        D   D D    DDD D     D
01 1111110010 0001110001101000110101000011101011010

แถวบนสุดคือสตริงเป้าหมายตรงกลางคือการดำเนินการและด้านล่างคือสตริงที่กำลังแก้ไข ช่องว่างในสายการปฏิบัติการบ่งชี้ว่าตัวละครที่ตรงกัน 'R' ระบุว่าสตริงการแก้ไขมีอักขระอยู่ในตำแหน่งนั้นแทนที่ด้วยอักขระของสตริงเป้าหมาย 'I' หมายถึงว่าสตริงการแก้ไขมีอักขระของสตริงเป้าหมายแทรกอยู่ที่ตำแหน่งนั้น 'D' หมายถึงว่าสตริงการแก้ไขมีตัวอักษรอยู่ในตำแหน่งนั้นถูกลบ สตริงการแก้ไขและเป้าหมายจะมีช่องว่างเมื่อมีการแทรกหรือลบอักขระอื่นเพื่อให้เข้าแถว

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <math.h>
#include <fstream>

int memory[1000];
#define first (*(const char **)&memory[0])
#define second (*(const char **)&memory[1])
#define block_ia memory[2]
#define block_ib memory[3]
#define block_n memory[4]
#define block_op memory[5]
#define block_o memory[6]
#define block_x memory[7]
#define n memory[8]
#define opmax memory[9]
#define best_op memory[10]
#define best_score memory[11]
#define score memory[12]
#define best_counter memory[13]
#define la memory[14]
#define lb memory[15]
#define best memory[16]
#define bestn memory[17]
#define total memory[18]

// verification variables
char printline1[0xffff]={};
char *p1=printline1;
char printline2[0xffff]={};
char *p2=printline2;
char printline3[0xffff]={};
char *p3=printline3;


// determine how many characters match after a set of operations
int block(){
    block_ia=0;
    block_ib=0;
    for ( block_x=0;block_x<block_n;block_x++){
        block_o = block_op%3;
        block_op /= 3;
        if ( block_o == 0 ){ // replace
            block_ia++;
            block_ib++;
        } else if ( block_o == 1 ){ // delete
            block_ib++;
        } else { // insert
            if ( first[block_ia] ){ 
                block_ia++;
            }
        }
        while ( first[block_ia] && first[block_ia]==second[block_ib] ){ // find next mismatch
            block_ia++;
            block_ib++;
        }
        if ( first[block_ia]==0 ){
            return block_x;
        }
    }
    return block_n;
}

// find the highest-scoring set of N operations for the current string position
void bestblock(){
    best_op=0;
    best_score=0;
    la = strlen(first);
    lb = strlen(second);
    block_n = n;
    for(best_counter=0;best_counter<opmax;best_counter++){
        block_op=best_counter;
        score = n-block();
        score += block_ia-abs((la-block_ia)-(lb-block_ib));
        if ( score > best_score ){
            best_score = score;
            best_op = best_counter;
        }
    }
}

// prepare edit confirmation record
void printedit(const char * a, const char * b, int o){
    o%=3;
    if ( o == 0 ){ // replace
        *p1 = *a;
        if ( *b ){
            *p2 = 'R';
            *p3 = *b;
            b++;
        } else {
            *p2 = 'I';
            *p3 = ' ';
        }
        a++;
    } else if ( o == 1 ){ // delete
        *p1 = ' ';
        *p2 = 'D';
        *p3 = *b;
        b++;
    } else { // insert
        *p1 = *a;
        *p2 = 'I';
        *p3 = ' ';
        a++;
    }
    p1++;
    p2++;
    p3++;
    while ( *a && *a==*b ){
        *p1 = *a;
        *p2 = ' ';
        *p3 = *b;
        p1++;
        p2++;
        p3++;
        a++;
        b++;
    }
}


int main(int argc, char * argv[]){

    if ( argc < 2 ){
        printf("No file name specified\n");
        return 0;
    }

    std::ifstream file(argv[1]);
    std::string line0,line1,line2;
    std::getline(file,line0);
    std::getline(file,line1);
    std::getline(file,line2);

    // begin estimating Levenshtein distance
    best = 0;
    bestn = 0;
    for ( n=1;n<=10;n++){ // n is the number of operations that can be in a test set
        opmax = (int)pow(3.0,n);
        first = line1.c_str();
        second = line2.c_str();
        while ( *first && *first == *second ){
            first++;
            second++;
        }
        total=0;
        while ( *first && *second ){
            bestblock();
            block_n=1;
            block_op=best_op;
            block();
            total ++;
            first += block_ia;
            second += block_ib;
        }
        // when one string is exhausted, all following ops must be insert or delete
        while(*second){
            total++;
            second++;
        }
        while(*first){
            total++;
            first++;
        }
        if ( !best || total < best ){
            best = total;
            bestn = n;
        }
    }
    // done estimating Levenshtein distance

    // dump info to prove the edit distance actually comes from a valid set of edits
    if ( argc >= 3 ){
        p1 = printline1;
        p2 = printline2;
        p3 = printline3;
        n = bestn;
        opmax = (int)pow(3.0,n);
        first = line1.c_str();
        second = line2.c_str();
        while ( *first && *first == *second ){
            *p1 = *first;
            *p2 = ' ';
            *p3 = *second;
            p1++;
            p2++;
            p3++;
            first++;
            second++;
        }
        while ( *first && *second){
            bestblock();
            block_n=1;
            block_op=best_op;
            block();
            printedit(first,second,best_op);
            first += block_ia;
            second += block_ib;
        }
        while(*second){
            *p1=' ';
            *p2='D';
            *p3=*second;
            p1++;
            p2++;
            p3++;
            second++;
        }
        while(*first){
            *p1=*first;
            *p2='I';
            *p3=' ';
            p1++;
            p2++;
            p3++;
            first++;
        }

        p1 = printline1;
        p2 = printline2;
        p3 = printline3;
        int ins=0;
        int del=0;
        int rep=0;
        while ( *p1 ){
            int a;
            for ( a=0;a<79&&p1[a];a++)
                printf("%c",p1[a]);
            printf("\n");
            p1+=a;
            for ( a=0;a<79&&p2[a];a++){
                ins += ( p2[a] == 'I' );
                del += ( p2[a] == 'D' );
                rep += ( p2[a] == 'R' );
                printf("%c",p2[a]);
            }
            printf("\n");
            p2+=a;
            for ( a=0;a<79&&p3[a];a++)
                printf("%c",p3[a]);
            printf("\n\n");
            p3+=a;
        }
        printf("Best N=%d\n",bestn);
        printf("Inserted = %d, Deleted = %d, Replaced=%d, Total = %d\nLength(line1)=%d, Length(Line2)+ins-del=%d\n",ins,del,rep,ins+del+rep,line1.length(),line2.length()+ins-del);
    }

    printf("%d, Score = %0.2f\n",best,2886*100.0/best);
    system("pause");
    return 0;
}

7

C ++ 75.0

โปรแกรมถูกออกแบบมาเพื่อทำงานกับสตริงข้อความโดยพลการ สามารถมีความยาวต่างกันได้ตราบใดที่มีความยาวไม่เกิน 13824 อักขระ มันใช้จำนวนเต็ม 1,897 16 บิตซึ่งเทียบเท่ากับจำนวนเต็ม 949 32 บิต ตอนแรกฉันเขียนมันใน C แต่แล้วก็รู้ว่าไม่มีฟังก์ชั่นสำหรับอ่านบรรทัด

อาร์กิวเมนต์บรรทัดคำสั่งแรกควรเป็นชื่อไฟล์ หากมีข้อโต้แย้งที่สองอยู่สรุปของการแก้ไขจะถูกพิมพ์ บรรทัดแรกในไฟล์จะถูกละเว้นในขณะที่บรรทัดที่สองและสามเป็นสตริง

อัลกอริทึมเป็นอัลกอริทึมรุ่นที่ถูกบล็อกเป็นทวีคูณ โดยทั่วไปแล้วจะมีจำนวนการดำเนินการเท่ากัน แต่แน่นอนว่ามีความแม่นยำน้อยกว่ามากเนื่องจากหากการเรียงลำดับทั่วไปถูกแบ่งไปตามขอบของบล็อกการประหยัดที่อาจเกิดขึ้นส่วนใหญ่จะหายไป

#include <cstring>
#include <inttypes.h>
#include <iostream>
#include <fstream>

#define M 24
#define MAXLEN (M*M*M)
#define SETMIN(V, X) if( (X) < (V) ) { (V) = (X); }
#define MIN(X, Y) ( (X) < (Y) ? (X) : (Y) )

char A[MAXLEN+1], B[MAXLEN+1];
uint16_t d0[M+1][M+1], d1[M+1][M+1], d2[M+1][M+1];

int main(int argc, char**argv)
{

    if(argc < 2)
        return 1;

    std::ifstream fi(argv[1]);

    std::string Astr, Bstr;
    for(int i = 3; i--;)
        getline(fi, i?Bstr:Astr);
    if(!fi.good()) {
        printf("Error reading file");
        return 5;
    }
    if(Astr.length() > MAXLEN || Bstr.length() > MAXLEN) {
        printf("String too long");
        return 7;
    }

    strcpy(A, Astr.c_str());
    strcpy(B, Bstr.c_str());

    uint16_t lA = Astr.length(), lB = Bstr.length();
    if(!lA || !lB) {
        printf("%d\n", lA|lB);
        return 0;
    }
    uint16_t nbA2, nbB2, bA2, bB2, nbA1, nbB1, bA1, bB1, nbA0, nbB0, bA0, bB0; //block, number of blocks
    uint16_t iA2, iB2, iA1, iB1, jA2, jB2, jA1, jB1; //start, end indices of block

    nbA2 = MIN(M, lA);
    nbB2 = MIN(M, lB);
    for(bA2 = 0; bA2 <= nbA2; bA2++) {
        iA2 = lA * (bA2-1)/nbA2,  jA2 = lA * bA2/nbA2;
        for(bB2 = 0; bB2 <= nbB2; bB2++) {
            if(!(bA2|bB2)) {
                d2[0][0] = 0;
                continue;
            }
            iB2 = lB * (bB2-1)/nbB2,  jB2 = lB * bB2/nbB2;
            d2[bA2][bB2] = ~0;
            if(bB2)
                SETMIN(d2[bA2][bB2], d2[bA2][bB2-1] + (jB2-iB2));
            if(bA2)
                SETMIN(d2[bA2][bB2], d2[bA2-1][bB2] + (jA2-iA2));

            if(bA2 && bB2) {
                nbA1 = MIN(M, jA2-iA2);
                nbB1 = MIN(M, jB2-iB2);
                for(bA1 = 0; bA1 <= nbA1; bA1++) {
                    iA1 = iA2 + (jA2-iA2) * (bA1-1)/nbA1, jA1 = iA2 + (jA2-iA2) * bA1/nbA1;
                    for(bB1 = 0; bB1 <= nbB1; bB1++) {
                        if(!(bA1|bB1)) {
                            d1[0][0] = 0;
                            continue;
                        }
                        iB1 = iB2 + (jB2-iB2) * (bB1-1)/nbB1, jB1 = iB2 + (jB2-iB2) * bB1/nbB1;
                        d1[bA1][bB1] = ~0;
                        if(bB1)
                            SETMIN(d1[bA1][bB1], d1[bA1][bB1-1] + (jB1-iB1));
                        if(bA1)
                            SETMIN(d1[bA1][bB1], d1[bA1-1][bB1] + (jA1-iA1));

                        if(bA1 && bB1) {
                            nbA0 = jA1-iA1;
                            nbB0 = jB1-iB1;
                            for(bA0 = 0; bA0 <= nbA0; bA0++) {
                                for(bB0 = 0; bB0 <= nbB0; bB0++) {
                                    if(!(bA0|bB0)) {
                                        d0[0][0] = 0;
                                        continue;
                                    }
                                    d0[bA0][bB0] = ~0;
                                    if(bB0)
                                        SETMIN(d0[bA0][bB0], d0[bA0][bB0-1] + 1);
                                    if(bA0)
                                        SETMIN(d0[bA0][bB0], d0[bA0-1][bB0] + 1);
                                    if(bA0 && bB0)
                                        SETMIN(d0[bA0][bB0], d0[bA0-1][bB0-1] + (A[iA1 + nbA0 - 1] != B[iB1 + nbB0 - 1]));
                                }
                            }
                            SETMIN(d1[bA1][bB1], d1[bA1-1][bB1-1] + d0[nbA0][nbB0]);
                        }
                    }
                }

                SETMIN(d2[bA2][bB2], d2[bA2-1][bB2-1] + d1[nbA1][nbB1]);
            }
        }
    }
    printf("%d\n", d2[nbA2][nbB2]);

    if(argc == 2)
        return 0;

    int changecost, total = 0;
    for(bA2 = nbA2, bB2 = nbB2; bA2||bB2; ) {
        iA2 = lA * (bA2-1)/nbA2,  jA2 = lA * bA2/nbA2;
        iB2 = lB * (bB2-1)/nbB2,  jB2 = lB * bB2/nbB2;
        if(bB2 && d2[bA2][bB2-1] + (jB2-iB2) == d2[bA2][bB2]) {
            total += changecost = (jB2-iB2);
            char tmp = B[jB2];
            B[jB2] = 0;
            printf("%d %d deleted {%s}\n", changecost, total, B + iB2);
            B[jB2] = tmp;
            --bB2;
        } else if(bA2 && d2[bA2-1][bB2] + (jA2-iA2) == d2[bA2][bB2]) {
            total += changecost = (jA2-iA2);
            char tmp = B[jA2];
            A[jA2] = 0;
            printf("%d %d inserted {%s}\n", changecost, total, A + iA2);
            A[jA2] = tmp;
            --bA2;
        } else {
            total += changecost = d2[bA2][bB2] - d2[bA2-1][bB2-1];
            char tmpa = A[jA2], tmpb = B[jB2];
            B[jB2] = A[jA2] = 0;
            printf("%d %d changed {%s} to {%s}\n", changecost, total, B + iB2, A + iA2);
            A[jA2] = tmpa, B[jB2] = tmpb;
            --bA2, --bB2;
        }
    }


    return 0;
}

ขอบคุณที่เป็นผู้ตอบคำถามแรก! คะแนนของคุณคืออะไร?

@ Lembik ตกลงฉันได้คำนวณคะแนนโดยสมมติว่าเป็นไปตามตัวอย่างเท่านั้น
feersum

มันเยี่ยมมาก คุณคิดว่าเป็นไปได้หรือไม่ที่จะได้รับคะแนนที่สูงขึ้นมาก?

3

Python 100

ฉันจัดการคำนวณระยะแก้ไขได้อย่างสมบูรณ์แบบในขีด จำกัด หน่วยความจำที่กำหนด น่าเศร้าที่รายการนี้ละเมิดกฎสองข้อของความท้าทายโดยทำเป็นตัวอักษรหากไม่ได้อยู่ในจิตวิญญาณ

ก่อนอื่นฉันไม่ได้เก็บข้อมูลของฉันไว้ใน 1,000 32- บิต ints สำหรับสตริง 10,000 ตัวอักษรโปรแกรมของฉันสร้างอาร์เรย์ 10,000 องค์ประกอบสองตัวที่จะมีเพียง +1, 0 หรือ -1 ที่ 1.585 บิตต่อหมายเลขที่สามมันเป็นไปได้ที่จะแพ็ค 20000 trits เป็น 31700 บิตโดยเหลือ 300 บิตมากกว่าเพียงพอสำหรับจำนวนเต็ม 16 บิตที่เหลืออยู่ 7 ตัวของฉัน

ประการที่สองฉันไม่ได้ใช้งานโหมดที่จำเป็นสำหรับการแสดงการแก้ไข ฉันได้เลือกใช้โหมดที่พิมพ์เมทริกซ์การแก้ไขเต็มรูปแบบ เป็นไปได้อย่างแน่นอนที่จะคำนวณเส้นทางแก้ไขจากเมทริกซ์นั้น แต่ตอนนี้ฉันไม่มีเวลาที่จะใช้มัน

#!/usr/bin/env python

import sys

# algorithm originally from
# https://en.wikipedia.org/wiki/Levenshtein_distance#Iterative_with_two_matrix_rows

print_rows = False
if len(sys.argv) > 2:
    print_rows = True

def LevenshteinDistance(s, t):
    # degenerate cases
    if s == t:
        return 0
    if len(s) == 0:
        return len(t)
    if len(t) == 0:
        return len(s)

    # create two work vectors of integer distance deltas

    # these lists will only ever contain +1, 0, or -1
    # so they COULD be packed into 1.585 bits each
    # 15850 bits per list, 31700 bits total, leaving 300 bits for all the other variables

    # d0 is the previous row
    # initialized to 0111111... which represents 0123456...
    d0 = [1 for i in range(len(t)+1)]
    d0[0] = 0        
    if print_rows:
        row = ""
        for i in range(len(t)+1):
            row += str(i) + ", "
        print row

    # d1 is the row being calculated
    d1 = [0 for i in range(len(t)+1)]

    for i in range(len(s)-1):
        # cummulative values of cells north, west, and northwest of the current cell
        left = i+1
        upleft = i
        up = i+d0[0]
        if print_rows:
            row = str(left) + ", "
        for j in range(len(t)):
            left += d1[j]
            up += d0[j+1]
            upleft += d0[j]
            cost = 0 if (s[i] == t[j]) else 1
            d1[j + 1] = min(left + 1, up + 1, upleft + cost) - left
            if print_rows:
                row += str(left+d1[j+1]) + ", "

        if print_rows:
            print row

        for c in range(len(d0)):
            d0[c] = d1[c]

    return left+d1[j+1]

with open(sys.argv[1]) as f:
    lines = f.readlines()

perfect = lines[0]
string1 = lines[1]
string2 = lines[2]
distance = LevenshteinDistance(string1,string2)
print "edit distance: " + str(distance)
print "score: " + str(int(perfect)*100/distance) + "%"

อินพุตตัวอย่าง:

2
101100
011010

เอาต์พุต verbose ตัวอย่าง:

0, 1, 2, 3, 4, 5, 6,
1, 1, 1, 2, 3, 4, 5,
2, 1, 2, 2, 2, 3, 4,
3, 2, 1, 2, 3, 2, 3,
4, 3, 2, 1, 2, 3, 3,
5, 4, 3, 2, 1, 2, 3,
6, 5, 4, 3, 2, 2, 2,
edit distance: 2
score: 100%
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.