superstring ทั่วไปที่สั้นที่สุด


26

ได้รับรายชื่อของสตริงs_0, s_1, ..., s_nพบสตริงที่สั้นที่สุดSที่มีแต่ละs_0, s_1, ..., s_nเป็นสตริงย่อย

ตัวอย่าง :

  • S('LOREM', 'DOLOR', 'SED', 'DO', 'MAGNA', 'AD', 'DOLORE')='SEDOLOREMAGNAD'
  • S('ABCDE', 'BCD', 'C')='ABCDE'

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

ประสิทธิภาพไม่สำคัญ - สมมติว่าสำหรับอินพุตความยาวรวม <100 ตัวอักษรผลลัพธ์จะต้องคำนวณใน <10 วินาทีสำหรับฮาร์ดแวร์สมัยใหม่โดยเฉลี่ย


3
+1 คำถามที่ดี ฉันขอแนะนำให้คุณใส่ตัวอย่างเพิ่มเติมของผลลัพธ์ที่คาดไว้เพื่อให้ผู้คนสามารถตัดสินได้อย่างง่ายดายว่าการส่งผลงานนั้นสามารถรับมือกับหลายกรณีได้หรือไม่
DavidC

ควรจัดการอินพุต / เอาต์พุตอย่างไร ควรพิมพ์ผลลัพธ์หรือส่งคืนจากฟังก์ชันหรือไม่
flornquake

ดังนั้นไม่มี "สำหรับทุกสายถ้ามีทั้งหมด ... ส่งคืน" ไม่ใช่โซลูชันที่ถูกต้องหรือไม่
John Dvorak

ฉันสงสัยว่าจะต้องมีคำตอบ คำถามนี้อาจเหมาะกับStack Overflow (โดยไม่มีส่วนของ code-golf) ค่อนข้างดี
John Dvorak

คำตอบ:


8

Python 2, 170 153/157/159

ขอบคุณที่สั้นลงบางส่วนของความคิดของติส

from itertools import*
print min((reduce(lambda s,w:(w+s[max(i*(s[:i]==w[-i:])for i in range(99)):],s)[w in s],p)
for p in permutations(input())),key=len)

ไม่จำเป็นต้องมีตัวแบ่งบรรทัดที่สอง

อินพุต: 'LOREM', 'DOLOR', 'SED', 'DO', 'MAGNA', 'AD', 'DOLORE'
เอาต์พุต:SEDOLOREMAGNAD

แม้จะมีสตริงอินพุตยาวสิ่งนี้จะทำงานในเวลาน้อยกว่า 2 วินาทีหากมีสตริงอินพุตมากที่สุด 7 สตริง (เช่นในตัวอย่างที่กำหนดซึ่งทำงานใน1.7 1.5 วินาทีในเครื่องของฉัน) ด้วยการมี 8 หรือมากกว่าสายการป้อนข้อมูล แต่มันต้องใช้เวลามากกว่า 10 O(n!)วินาทีเนื่องจากความซับซ้อนของเวลาที่

ตามที่ Baptiste ชี้ให้เห็นrange(99)จะต้องมีการแทนที่ด้วยrange(len(w))ถ้าความยาวอินพุตโดยพลการควรได้รับการสนับสนุน (ทำให้ความยาวทั้งหมดของรหัส 157 ตัวอักษร) range(len(w)+1)หากสายการป้อนข้อมูลที่ว่างเปล่าควรได้รับการสนับสนุนก็จะต้องมีการเปลี่ยนไป ฉันคิดว่าrange(99)ทำงานได้อย่างถูกต้องสำหรับความยาวอินพุตรวมน้อยกว่า 200

การทดสอบเพิ่มเติม:

>>> "AD", "DO", "DOLOR", "DOLORE", "LOREM", "MAGNA", "SED", "ORE",  "R"
SEDOLOREMAGNAD

>>> 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 'abcdefghijklmnopqrstuvw
... xyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstu
... vwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 'ZOOM', 'aZ', 'Za', 'ZA'
aZABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZOOM

5

Mathematica 337 418 372

หลังจากพยายามนำไปใช้งานโดยไม่ประสบผลสำเร็จLongestCommonSubsequencePositionsฉันก็หันไปจับคู่รูปแบบ

v=Length;
p[t_]:=Subsets[t,{2}];
f[w_]:=Module[{c,x,s=Flatten,r={{a___,Longest[y__]},{y__,b___}}:>{{a,y},{y,b},{y},{a,y,b}}},
c=p@w;
x=SortBy[Cases[s[{#/.r,(Reverse@#)/.r}&/@c,1],{_,_,_,_}],v[#[[3]]]&][[-1]];
Append[Complement[w,{x[[1]],x[[2]]}],x[[4]]]]

g[r_]:=With[{h=Complement[r,Cases[Join[p@r,p@Reverse@r],y_/;!StringFreeQ@@y:>y[[2]]]]},
FixedPoint[f,Characters/@h,v@h-1]<>""]

กฎการจับคู่รูปแบบ

r={{a___,Longest[y__]},{y__,b___}}:> {{a,y},{y,b},{y},{a,y,b}}},

ใช้คู่ของคำที่เรียงลำดับ (แสดงเป็นรายการของอักขระ) และส่งคืน: (1) คำ{a,y}และ{y,b}ตามด้วย (2) สตริงย่อยทั่วไปyซึ่งจะเชื่อมโยงส่วนท้ายของคำหนึ่งกับจุดเริ่มต้นของคำอื่นและ ในที่สุดคำรวมกัน{a,y,b}ที่จะแทนที่คำที่ป้อนเข้า ดู Belisarius สำหรับตัวอย่างที่เกี่ยวข้อง: /mathematica/6144/look-for-longest-common-substring-solution

อักขระขีดล่างที่ต่อเนื่องกันสามตัวมีความหมายว่าองค์ประกอบนั้นเป็นลำดับของอักขระศูนย์หรือมากกว่า

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

แก้ไข :

ข้อมูลต่อไปนี้จะลบออกจากรายการคำที่ "ฝัง" (เช่นที่มีอยู่ทั้งหมด) ในคำอื่น (เพื่อตอบสนองต่อความคิดเห็นของ @ flornquake)

h=Complement[r,Cases[Join[p@r,p@Reverse@r],x_/;!StringFreeQ@@x:> x[[2]]]]

ตัวอย่าง :

 {{"D", "O", "L", "O", "R", "E"}, {"L", "O", "R", "E", "M"}} /. r

ผลตอบแทน

{{"D", "O", "L", "O", "R", "E"}, {"L", "O", "R", "E", "M"}, { "L", "O", "R", "E"}, {"D", "O", "L", "O", "R", "R", "E", "M"}}


การใช้

g[{"LOREM", "ORE", "R"}]

AbsoluteTiming[g[{"AD", "DO", "DOLOR", "DOLORE", "LOREM", "MAGNA", "SED", "ORE",  "R"}]]

"Lorem"

{0.006256, "SEDOLOREMAGNAD"}


ใช้งานได้กับอินพุต"LOREM", "ORE", "R"หรือไม่
flornquake

(เช่นมันสร้างผลลัพธ์ที่ถูกต้อง"LOREM"หรือไม่?)
flornquake

@flornquake รับได้สวย. ฉันพูดถึงมันในเวอร์ชันปัจจุบัน ฉันหวังว่าฉันจะไม่พลาดกรณีอื่น ๆ ขอบคุณ
DavidC

ไม่มีอะไรนอกจากดีที่สุด!
DavidC

3

GolfScript, 66 ตัวอักษร

{.,1>{.`{[1$]-s:h;.,),\`{:g<`{\+.g?0<{;}*}+h%~}+/}+%.&}*}:s~{,}$0=

ค่อนข้างสั้น แต่เนื่องจากความซับซ้อนของเวลาแบบเอ็กซ์โปเนนเชียล (และ GolfScript) ช้ามาก ๆ มันจึง จำกัด เวลาไว้ 10 วินาที

ตัวอย่าง:

['LOREM' 'DOLOR' 'SED' 'DO' 'MAGNA' 'AD' 'DOLORE']
{.,1>{.`{[1$]-s:h;.,),\`{:g<`{\+.g?0<{;}*}+h%~}+/}+%.&}*}:s~{,}$0=
# => SEDOLOREMAGNAD

['AB' 'BC' 'CA' 'BCD' 'CDE']
{.,1>{.`{[1$]-s:h;.,),\`{:g<`{\+.g?0<{;}*}+h%~}+/}+%.&}*}:s~{,}$0=
# => CABCDE

2

Python 2, 203 187 200

from itertools import permutations as p
def n(c,s=''):
 for x in c:s+=x[next((i+1 for i,l in [(j,x[:j+1])for j in range(len(x))][::-1]if s.endswith(l)),0):]
 return s
print min(map(n,p(input())),key=len)

อินพุต: ['LOREM', 'DOLOR', 'SED', 'DO', 'MAGNA', 'AD', 'DOLORE']
เอาต์พุต:SEDOLOREMAGNAD

แก้ไข

การใช้reduceและการนำเข้าเล่ห์เหลี่ยมสกปรกฉันสามารถลดสิ่งนี้ได้อีก (และเป็นหนึ่งบรรทัดเท่านั้น!):

print min((reduce(lambda a,x:a+x[next((i+1 for i,l in [(j,x[:j+1])for j in range(len(x))][::-1]if a.endswith(l)),0):],P,'')for P in __import__('itertools').permutations(input())),key=len)

แก้ไข 2

ตามที่ระบุไว้ flornquake สิ่งนี้ให้ผลลัพธ์ที่ไม่ถูกต้องเมื่อคำหนึ่งอยู่ในอีกคำหนึ่ง การแก้ไขนี้เพิ่มอีก 13 ตัวอักษร:

print min((reduce(lambda a,x:a+(x[next((i+1 for i,l in [(j,x[:j+1])for j in range(len(x))][::-1]if a.endswith(l)),0):],'')[x in a],P,'')for P in __import__('itertools').permutations(input())),key=len)

นี่คือเวอร์ชั่นที่ล้างแล้ว:

from itertools import permutations

def solve(*strings):
    """
    Given a list of strings, return the shortest string that contains them all.
    """
    return min((simplify(p) for p in permutations(strings)), key=len)

def prefixes(s):
    """
    Return a list of all the prefixes of the given string (including itself),
    in ascending order (from shortest to longest).
    """
    return [s[:i+1] for i in range(len(s))]
    return [(i,s[:i+1]) for i in range(len(s))][::-1]

def simplify(strings):
    """
    Given a list of strings, concatenate them wile removing overlaps between
    successive elements.
    """
    ret = ''
    for s in strings:
        if s in ret:
            break
        for i, prefix in reversed(list(enumerate(prefixes(s)))):
            if ret.endswith(prefix):
                ret += s[i+1:]
                break
        else:
            ret += s
    return ret

print solve('LOREM', 'DOLOR', 'SED', 'DO', 'MAGNA', 'AD', 'DOLORE')

เป็นไปได้ที่จะโกนอักขระบางตัวออกไปโดยใช้ความถูกต้องตามทฤษฎีโดยใช้range(99)แทนrange(len(x))(ให้เครดิตกับการทำลายล้างเพื่อคิดเรื่องนี้)


หากคุณเต็มใจที่จะเสียสละความถูกต้องคุณก็อาจใช้วิธีโลภหรือปัจจัยการประมาณพหุนามของ 2 วิธี
Peter Taylor

ทางออกที่ดี! คุณจำเป็นต้องตรวจสอบว่าคำใหม่มีอยู่แล้วใน superstring แม้ว่า: ไม่ถูกต้องผลิตส่งออก'LOREM', 'ORE', 'R' LOREMORER
flornquake

@ flornquake จับได้ดี ฉันจัดการเพื่อแก้ไข แต่เพิ่ม 13 ตัวอักษร
Baptiste M.

1

Python 144 ตัวอักษร

S=lambda A,s:min(S(A-set([a]),s+a[i:])for a in A for i in range(len(a)+1)if i==0 or s[-i:]==a[:i])if A else(len(s),s)
T=lambda L:S(set(L),'')[1]

Sใช้ชุดของคำAที่ยังคงต้องวางและสตริงsที่มีคำที่วางไว้จนถึง เราเลือกคำที่เหลือaจากAการซ้อนทับกันได้จาก0การตัวอักษรที่มีในตอนท้ายของlen(a)s

ใช้เวลาเพียงประมาณ 0.15 วินาทีในตัวอย่างที่กำหนด


ดีจริงๆ! แต่เช่นเดียวกับการแก้ปัญหาอื่น ๆ ['LOREM', 'ORE', 'R']บางนี้ไม่ทำงานสำหรับการป้อนข้อมูลเช่น ฉันใช้เสรีภาพในการแก้ไขปัญหาและแก้ไขปัญหาของคุณเพิ่มเติม: S=lambda A,s='':A and min((S(A-{a},(s+a[max(i*(s[-i:]==a[:i])for i in range(len(a))):],s)[a in s])for a in A),key=len)or s(บรรทัดที่สองไม่จำเป็น การใช้งาน: ผลตอบแทนS({'LOREM', 'DOLOR', 'SED', 'DO', 'MAGNA', 'AD', 'DOLORE'}) 'SEDOLOREMAGNAD'
flornquake

0

Haskell, 121

import Data.List
a p []=[(length p,p)]
a p s=[r|w<-s,t<-tails w,isInfixOf w$p++t,r<-a(p++t)(s\\[w])]
s=snd.minimum.a ""

ลบสองถ้าฟังก์ชันไม่จำเป็นต้องผูกกับชื่อ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.