รหัสต่อเนื่องที่ยาวที่สุดที่สั้นที่สุด


11

งานของคุณเพื่อที่จะแก้ปัญหา SLCSC ซึ่งประกอบด้วยในการหารหัสที่สั้นที่สุดในการแก้ปัญหาร่วมกันที่ยาวที่สุด subsequence

วิธีการแก้ปัญหาที่ถูกต้องในการแก้ไขปัญหา LCS สำหรับสองคนหรือมากกว่าสตริงS 1 ... S nใด ๆ สตริงTของความยาวสูงสุดเช่นว่าตัวละครของTปรากฏในทุกS ฉันในการสั่งซื้อเช่นเดียวกับในT

โปรดทราบว่าTไม่ต้องย่อยสตริงของSฉัน

ตัวอย่าง

สตริงaxbyczและ xaybzcมี 8 ส่วนประกอบทั่วไปของความยาว 3:

abc abz ayc ayz xbc xbz xyc xyz

สิ่งเหล่านี้จะเป็นทางออกที่ถูกต้องสำหรับปัญหา LCS

รายละเอียด

เขียนโปรแกรมหรือฟังก์ชั่นที่แก้ปัญหา LCS ตามที่อธิบายไว้ข้างต้นโดยปฏิบัติตามกฎต่อไปนี้:

  • การป้อนข้อมูลจะประกอบด้วยสองหรือมากกว่าสตริงที่มีตัวอักษรตัวพิมพ์เล็กเท่านั้น

    คุณสามารถอ่านสตริงเหล่านั้นเป็นอาร์เรย์ของสตริงหรือสตริงเดียวที่มีตัวคั่นที่คุณเลือก

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

  • คุณอาจคิดว่าสตริงนั้นสั้นกว่า 1,000 ตัวอักษรและมีได้ไม่เกิน 20 สตริง

    ภายในขอบเขตเหล่านี้รหัสของคุณควรทำงานตามที่คาดไว้ในทางทฤษฎี (ให้เวลาและหน่วยความจำไม่ จำกัด )

  • รหัสของคุณจะต้องดำเนินการกรณีทดสอบรวมกันของส่วนถัดไปในเวลาไม่ถึงชั่วโมงบนเครื่องของฉัน (Intel Core i7-3770, 16 GiB RAM)

    วิธีการที่วนซ้ำไปเรื่อย ๆ ในลำดับทั้งหมดที่เป็นไปได้จะไม่สอดคล้องกับการ จำกัด เวลา

  • การใช้บิวด์อินที่LongestCommonSequenceไม่อนุญาตให้ทำภารกิจนี้เช่นสิ่งเล็กน้อย

ใช้กฎมาตรฐานของ

กรณีทดสอบ

a
ab

เอาท์พุท: a


aaaaxbbbb
bbbbxcccc
ccccxaaaa

เอาท์พุท: x


hxbecqibzpyqhosszypghkdddykjfjcajnwfmtfhqcpavqrtoipocijrmqpgzoufkjkyurczxuhkcpehbhpsuieqgjcepuhbpronmlrcgvipvibhuyqndbjbrrzpqbdegmqgjliclcgahxoouqxqpujsyfwbdthteidvigudsuoznykkzskspjufgkhaxorbrdvgodlb
qnnprxqpnafnhekcxljyysobbpyhynvolgtrntqtjpxpchqwgtkpxxvmwwcohxplsailheuzhkbtayvmxnttycdkbdvryjkfhshulptkuarqwuidrnjsydftsyhuueebnrjvkfvhqmyrclehcwethsqzcyfvyohzskvgttggndmdvdgollryqoswviqurrqhiqrqtyrl

เอาท์พุท: hxbbpyhogntqppcqgkxchpsieuhbncvpuqndbjqmclchqyfttdvgoysuhrrlหรือองค์ประกอบอื่น ๆ ที่มีความยาวเท่ากัน


riikscwpvsbxrvkpymvbbpmwclizxlhihiubycxmxwviuajdzoonjpkgiuiulbjdpkztsqznhbjhymwzkutmkkkhirryabricvhb
jnrzutfnbqhbaueicsvltalvqoorafnadevojjcsnlftoskhntashydksoheydbeuwlswdzivxnvcrxbgxmquvdnfairsppodznm
kzimnldhqklxyezcuyjaiasaeslicegmnwfavllanoolkhvqkjdvxrsjapqqwnrplcwqginwinktxnkfcuuvoyntrqwwucarfvjg

เอาท์พุท: icsvllvjnlktywuarหรือองค์ประกอบอื่น ๆ ที่มีความยาวเท่ากัน


rblartqkfggrjpiipuzzypkycnyckkcqceeujiyy
yfpnedyjtiwrhyuktripdwyvgkblzodeufkelhub
ywcyboxwqkibwvredkrbdsyudkulpvmhixeqxynh
bnxwahbzhwjxkotnvbxrojkkldtsodtjmvdrmbgr

เอาท์พุท: krkkหรือองค์ประกอบอื่น ๆ ที่มีความยาวเท่ากัน


bwfscmotshoczmduwaev
coywaaizdaxjovipsmeh
dobzcpoiedenzlfdjpiu
bbhfeqscvvbwkuoxdoge
drqrzwbcpcsvneodelja

เอาท์พุท: codeหรือองค์ประกอบอื่น ๆ ที่มีความยาวเท่ากัน


nqrualgoedlf
jgqorzglfnpa
fgttvnogldfx
pgostsulyfug
sgnhoyjlnfvr
wdttgkolfkbt

เอาท์พุท: golfหรือองค์ประกอบอื่น ๆ ที่มีความยาวเท่ากัน


epopyfuhgowedpiqpgfj
ddxyestqynpwmytxhozm
ptubgzyqqksieoovuezv
tovotqmnhgzttfpywjgr
aomvytkgaijlgqzkljls
vzvxpaixrnprxvenbbuo
syfuwxlpcyontqlmfvib
arxleuomstkjegpduwcx
xgqrxaopouvkvwgbzewn
yggunddigctgpnuztzai
izroomywwztdymqszsuo
kiawjnxjncdtufhkrjsp

เอาต์พุต: สตริงว่าง



@NotthatCharles ไม่ใช่ทั้งหมด คำถามนั้นให้เพียงสองสายเป็นอินพุตและไม่มีการ จำกัด เวลา คำตอบที่มีอยู่ทั้งหมดใช้แนวทางไร้เดียงสาที่มีขนาดช้าเกินไปที่จะปฏิบัติตามกฎของคำถามนี้
Dennis

ตัวอย่างสุดท้ายอาจใช้เวลานานที่สุดในการคำนวณอย่างไรก็ตามโดยการลบอักขระทุกตัวที่ไม่ปรากฏในทุก ๆ สตริงมันเป็นเรื่องเล็กน้อยที่จะเอาท์พุทสตริงว่างเปล่า คุณสามารถเพิ่มอีกตัวอย่างหนึ่งที่มีจำนวนสายอักขระและความยาวของสตริงเท่ากันโดยที่อักขระทุกตัวที่ใช้ปรากฏในทุกสายอักขระและที่ LCS อย่างน้อย 5 ตัวอักษรหรือมากกว่านั้น? สิ่งที่ต้องการ: ghostbin.com/paste/x9caq
Tyilo

@Tylio การรวมตรรกะบางอย่างที่สิ้นสุดการสอบถามซ้ำก่อนกำหนดหากสตริงไม่มีอักขระที่ใช้ร่วมกันมากไปกว่านี้คือสิ่งที่กรณีทดสอบล่าสุดเป็นเรื่องเกี่ยวกับ
Dennis

@Dennis ดังนั้นวิธีการแก้ปัญหาไม่ควรจะสามารถทำงานในเวลาที่เหมาะสมกับ 20 สายยาว 1,000 ข้อ?
Tyilo

คำตอบ:


4

CJam, 31

q~L{_:&\f{_2$f#:).>j+}{,}$W>s}j

ลองออนไลน์

9 ไบท์ golfed ขอบคุณเดนนิส!

คำอธิบาย:

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

q~          read and evaluate the input (taken as an array)
L{…}j       execute block with recursive memoization and no starting values
  _         duplicate the array of strings
  :&\       intersect the strings as character sets and move before the array
             these are all the possible characters for the sequence
  f{…}      for each character and the array
    _2$     duplicate the array and the character
    f#      find the character position in each string
    :)      increment the positions (to skip the character)
    .>      slice each string starting at the corresponding position
    j       call the j block recursively
    +       concatenate the starting character with the result
  {,}$      sort resulting strings (one for each character) by length
  W>        keep only the last element, if any
  s         convert (from 0/1-string array) to string

5

Python - 665 644

ระดับการเยื้อง:

1: space
2: tab
3: tab + space
4: 2 tabs
5: 2 tabs + space

รหัสกำหนดฟังก์ชันoซึ่งรับรายการสตริงเป็นอาร์กิวเมนต์และส่งคืนหนึ่งใน LCS สำหรับสตริง

def o(t):
 t=[[y for y in x if y in reduce(lambda x,y:x.intersection(y),t,set(t[0]))]for x in t];l=map(len,t);C=[0]*reduce(lambda x,y:x*-~y,l,1);y=lambda z:[x-1for x in z];m=len(t);e=enumerate
 def g(h):
    r,x=0,1
    for k,j in e(h):r+=-~j*x;x*=-~l[k]
    return r
 def f(h):
    i=len(h)
    if i==m:
     b=g(h);c=t[0][h[0]]
     for k,j in e(h):
         if t[k][j]!=c:break
     else:C[b]=1+C[g(y(h))];return
     r=0
     for k,_ in e(h):a=h[:];a[k]-=1;r=max(r,C[g(a)])
     C[b]=r;return
    for j,_ in e(t[i]):f(h+[j])
 def p(h):
    if min(h)==-1:return''
    v=C[g(h)]
    for k,_ in e(h):
        a=h[:];a[k]-=1
        if v==C[g(a)]:return p(a)
    return p(y(h))+t[0][h[0]]
 f([]);return p(y(l))

รหัสทดสอบ:

tests = [
"""
a
ab
""",
"""
aaaaxbbbb
bbbbxcccc
ccccxaaaa
""",
"""
hxbecqibzpyqhosszypghkdddykjfjcajnwfmtfhqcpavqrtoipocijrmqpgzoufkjkyurczxuhkcpehbhpsuieqgjcepuhbpronmlrcgvipvibhuyqndbjbrrzpqbdegmqgjliclcgahxoouqxqpujsyfwbdthteidvigudsuoznykkzskspjufgkhaxorbrdvgodlb
qnnprxqpnafnhekcxljyysobbpyhynvolgtrntqtjpxpchqwgtkpxxvmwwcohxplsailheuzhkbtayvmxnttycdkbdvryjkfhshulptkuarqwuidrnjsydftsyhuueebnrjvkfvhqmyrclehcwethsqzcyfvyohzskvgttggndmdvdgollryqoswviqurrqhiqrqtyrl
""",
"""
riikscwpvsbxrvkpymvbbpmwclizxlhihiubycxmxwviuajdzoonjpkgiuiulbjdpkztsqznhbjhymwzkutmkkkhirryabricvhb
jnrzutfnbqhbaueicsvltalvqoorafnadevojjcsnlftoskhntashydksoheydbeuwlswdzivxnvcrxbgxmquvdnfairsppodznm
kzimnldhqklxyezcuyjaiasaeslicegmnwfavllanoolkhvqkjdvxrsjapqqwnrplcwqginwinktxnkfcuuvoyntrqwwucarfvjg
""",
"""
rblartqkfggrjpiipuzzypkycnyckkcqceeujiyy
yfpnedyjtiwrhyuktripdwyvgkblzodeufkelhub
ywcyboxwqkibwvredkrbdsyudkulpvmhixeqxynh
bnxwahbzhwjxkotnvbxrojkkldtsodtjmvdrmbgr
""",
"""
bwfscmotshoczmduwaev
coywaaizdaxjovipsmeh
dobzcpoiedenzlfdjpiu
bbhfeqscvvbwkuoxdoge
drqrzwbcpcsvneodelja
""",
"""
nqrualgoedlf
jgqorzglfnpa
fgttvnogldfx
pgostsulyfug
sgnhoyjlnfvr
wdttgkolfkbt
""",
"""
epopyfuhgowedpiqpgfj
ddxyestqynpwmytxhozm
ptubgzyqqksieoovuezv
tovotqmnhgzttfpywjgr
aomvytkgaijlgqzkljls
vzvxpaixrnprxvenbbuo
syfuwxlpcyontqlmfvib
arxleuomstkjegpduwcx
xgqrxaopouvkvwgbzewn
yggunddigctgpnuztzai
izroomywwztdymqszsuo
kiawjnxjncdtufhkrjsp
"""
]

for s in tests:
 print o(s.strip().split())

ใช้เวลาในการรันการทดสอบบนคอมพิวเตอร์ของฉัน:

$ time python 52808-shortest-longest-common-subsequence-code-golfed.py
a
x
hecbpyhogntqtpcqgkxchpsieuhbncvhuqndbjqmclchqyfhtdvgoysuhrrl
icsvllvanlktywuar
krkk
code
golf

        9.03 real         8.99 user         0.03 sys

1
คุณควรเพิ่มไบต์เพื่อรับรหัสของคุณถึง 666 ไบต์ ดังนั้นโลหะ \ m /
อเล็กซ์เอ.

@AlexA ใช่ฉันยังสังเกตเห็นว่าเมื่อนับจำนวนไบต์เนื่องจากมีการขึ้นบรรทัดใหม่ในบรรทัดสุดท้าย
Tyilo

มีการปรับปรุงเล็ก ๆ น้อย ๆ ที่ฉันเห็นในทันทีที่ควรช่วย ประการแรกทุกที่ที่คุณมี(n+1)คุณสามารถแทนที่ด้วย-~nเพื่อบันทึก 2 ไบต์ในแต่ละกรณี นอกจากนี้ทุกที่ที่คุณใช้mapกับ a lambdaให้พิจารณาใช้ list comprehension แทน ยกตัวอย่างเช่นสามารถจะสั้นลงโดยสามไบต์โดยเปลี่ยนไปmap(lambda x:x-1,z) [~-x for x in z]
Kade

r,x=r+(j+1)*x,x*(l[k]+1)r+=(j+1)*x;x*=(l[k]+1)สามารถลงไป นอกจากนี้คุณไม่จำเป็นu=...เพราะuมีการใช้งานในที่เดียวเท่านั้น uเพียงแค่ใช้แทนรหัสว่าสำหรับตัวอักษร
mbomb007

@ Vioz- และ mbomb007 ขอบคุณ
Tyilo

4

Pyth, 59 58 55 35 ไบต์

L&@Fb?+yPMbeeb@FeMbeolNmyXJbdP@bdlb

ลดขนาดมหึมา 20 ไบต์ด้วย @isaacg!

รุ่น 55 ไบต์:

DCHR?k!&.AH@FH?+Cm<1dHeeHql{medH1h.MlZ.eC++<Hk]<1b>HhkH

ตัด 3 ไบต์โดยเปลี่ยน.U@bZเป็น@F(ตัวดำเนินการแบบพับได้)

รุ่น 58 ไบต์:

DCHR?k!&.AH.U@bZH?+Cm<1dHeeHql{medH1h.MlZ.eC++<Hk]<1b>HhkH

ตัดไบต์ด้วยการเปลี่ยนรูปแบบของเงื่อนไขบูลีน

รุ่น 59 ไบต์:

DCHR?k|!.AH!.U@bZH?+Cm<1dHeeHql{medH1h.MlZ.eC++<Hk]<1b>HhkH

มันยาก! Python ทำการแยกกลุ่มอย่างต่อเนื่อง! ค่อนข้างแน่ใจว่ามันเป็นข้อผิดพลาดบางอย่าง แต่ฉันไม่ได้รับกรณีทดสอบเล็กน้อย โอ้ดี

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

มันค่อนข้างช้า แต่ควรใช้เวลาน้อยกว่าหนึ่งชั่วโมง (หวังว่า) ฉันกำลังทดสอบ Core i3 ของฉันด้วย RAM ขนาด 6 GB ดังนั้น Core i7 แบบ 16 GB ของคุณน่าจะใช้งานได้ :)

ฉันยังใช้ประโยชน์จากฟังก์ชั่นบันทึกอัตโนมัติของ Pyth เพื่อให้เร็วขึ้นอีกเล็กน้อย

แก้ไข : @Dennis บอกว่ามันผ่านไปแล้ว!

หากต้องการทดสอบให้เพิ่มบรรทัดต่อไปนี้:

CQ

และให้รายการของสตริงผ่านอินพุตมาตรฐาน (เช่น['a', 'ab'])

คำอธิบายสำหรับเวอร์ชัน 35 ไบต์:

WIP

คำอธิบายสำหรับเวอร์ชัน 55 ไบต์:

DCH                                                        define a function C that takes a list of strings H
   R                                                       return the following expression
    ?                                                      if
      !&.AH@FH                                             there are no more common letters OR all the strings are empty
     k                                                     return the empty string
              ?          ql{medH1                          else if the last character of every string is equal
               +Cm<1dHeeH                                  return the result of adding the last character to recursion with every item without its last character
                                 h.MlZ.eC++<Hk]<1b>HhkH    otherwise, return the largest result of recursing len(H) times, each time with one element's last character cut off

@Dennis Ok; ฉันจะทำงานกับมัน
kirbyfan64sos

@Dennis Updated คุณสามารถลองอีกครั้งในตอนนี้
kirbyfan64sos

กรณีทดสอบสุดท้ายเสร็จสิ้นทันทีในขณะนี้
Dennis

@Dennis YESSSSS !!
kirbyfan64sos

@ kirbyfan64sos เกี่ยวกับ segfaults: Pyth segfaults เมื่อความลึกของการเรียกซ้ำสูงเกินไปเช่นการเรียกซ้ำแบบไม่สิ้นสุด
isaacg

4

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;}

อัลกอริธึมเองนั้นไม่เปลี่ยนแปลง แต่รหัสใหม่นั้นขึ้นอยู่กับหน่วยงานและการใช้งานระดับบิตที่ซับซ้อนซึ่งจะทำให้ทุกอย่างช้าลง


ฉันกำลังคิดเกี่ยวกับการโพสต์รหัสที่เร็วที่สุดเกี่ยวกับหัวข้อที่คล้ายกัน แต่ดูเหมือนว่าฉันไม่จำเป็นต้องทำอีกต่อไป 0.01s และ 712KB นั้นยอดเยี่ยมมาก
Dennis

มันช่างยอดเยี่ยมมาก!
kirbyfan64sos

ลองดูคำอธิบายของคุณว่าอะไรห่าbest_found? มันถูกกล่าวถึงเพียงสองครั้งเมื่อมันถูกใช้ในเงื่อนไขและอื่น ๆ เมื่อมันถูกรีเซ็ต
kirbyfan64sos

มองผ่านมา C ก็ดูเหมือนว่ามีการตั้งค่าbest_found best_length + current_depthคุณควรพูดถึงในคำอธิบาย!
kirbyfan64sos

@ kirbyfan64sos best_foundเป็นจำนวนเต็มทั่วโลกที่อธิบายถึงความยาวของสตริงย่อยทั่วไปที่ยาวที่สุดที่พบ ณ จุดใด ๆ ในการดำเนินการ ฉันจะอธิบายเรื่องนี้ด้วย!
BrainSteel

1

Python 2, 285

รหัส:

import re
def f(s,a,b):
  if b==[]:return s+f('',[],a)
  if a==[]:return s+max([f(b[0][i],[b[0][i+1:]],b[1:]) for i in range(len(b[0]))],key=len) if b[0]!='' else ''
  return max([f(s,a+[b[0][i.start()+1:]],b[1:]) for i in re.finditer(s[-1],b[0])],key=len) if ~b[0].find(s[-1]) else ''

การใช้งาน:

print f('',[],['axbycz','xaybzc'])

คำอธิบาย:

นี่คือฟังก์ชั่นวนซ้ำ sเป็นตัวละครที่เรากำลังมองหา มีรายการของสตริงหั่นหลังa มีรายการของสตริงที่ยังไม่ได้เผยแพร่ ส่งคืนสตริงทั่วไปที่ยาวที่สุดsbf

เงื่อนไขแรกตรวจสอบว่าเราเสร็จสิ้นการผ่านสายทั้งหมด ถ้าเป็นเช่นนั้นก็หมายถึงsตัวละครทั่วไปและมันจะส่งกลับsและมองหาตัวละครที่พบบ่อยมากขึ้น

เงื่อนไขที่สองตรวจสอบว่าเราไม่ได้เริ่มต้นผ่านสายใด ๆ ซึ่งหมายความว่าเราไม่ได้มีตัวละคร ( a==[]เทียบเท่าs=='') bถ้าเป็นเช่นนั้นเราจะตรวจสอบลักษณะของสายแรกในแต่ละ

บรรทัดสุดท้ายย้ายสตริงแรกbไปที่aโดยค้นหาแต่ละรายการที่เกิดขึ้นsในสตริงนี้

ในการโทรครั้งแรกsควรเป็นสตริงที่ว่างเปล่า aควรเป็นรายการที่ว่างเปล่าและbควรมีสตริงทั้งหมด


2
f(b,s='',a=[])คุณควรใช้ข้อโต้แย้งเริ่มต้นเพื่อให้มีเพียงสตริงจะต้องมีการจ่ายให้กับฟังก์ชั่นเช่น
feersum
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.