En kısa yaygın superstring


26

Dizelerin bir listesi göz önüne alındığında her birini alt dize olarak içeren s_0, s_1, ..., s_nen kısa dizeyi bulun .Ss_0, s_1, ..., s_n

Örnekler :

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

Bu sorunu çözen en kısa programı (veya işlevi) yazın. Dizeleri, isterseniz diziler veya karakter / tamsayı listesi olarak temsil edebilirsiniz. Standart kütüphaneler iyi durumda. Giriş / çıkış için daha uygun olanı kullanabilirsiniz: STDIN / STDOUT, kullanıcı istemi, bir fonksiyonun parametre / dönüş değeri vb.

Performans kritik değildir - diyelim ki, toplam uzunluk <100 karakterlik bir girdi için, sonuç ortalama modern donanımda <10 saniyede hesaplanmalıdır.


3
+1 Güzel soru. Bazı beklenen sonuç örnekleri eklemenizi öneriyorum, böylece insanlar gönderilerin çeşitli davalarla başa çıkıp çıkamayacağını kolayca değerlendirebilirler.
DavidC

Giriş / çıkış nasıl ele alınmalıdır? Sonuç bir işlevden yazdırılmalı mı yoksa iade edilmeli mi?
Flornquake

öyleyse, hayır "her dize için, hepsini içeriyorsa ..., onu geri getirin" geçerli bir çözüm değil mi?
John Dvorak

Bir cevap olacağından şüpheliyim. Bu soru, Stack Overflow'a (kod-golf kısmı olmadan) oldukça uygun olabilir .
John Dvorak

Yanıtlar:


8

Python 2, 170 153/157/159

Baptiste'un bazı fikirleri sayesinde kısaltıldı .

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)

İkinci satır sonu gerekli değildir.

Giriş: 'LOREM', 'DOLOR', 'SED', 'DO', 'MAGNA', 'AD', 'DOLORE'
Çıkış:SEDOLOREMAGNAD

Uzun giriş dizelerinde bile, en fazla 7 giriş dizesi varsa ( makinemde 1.7 1.5 saniyede çalışan verilen örnekte olduğu gibi), bu 2 saniyeden daha kısa sürede çalışır . Bununla birlikte, 8 veya daha fazla giriş dizesiyle, zaman karmaşıklığı nedeniyle 10 saniyeden fazla sürer O(n!).

Baptiste'in belirttiği gibi, isteğe bağlı giriş uzunluklarının desteklenmesi range(99)gerekiyorsa bunun değiştirilmesi range(len(w))gerekir (kodun toplam uzunluğu 157 karakterdir). Boş giriş dizeleri desteklenmeli ise, olarak değiştirilmelidir range(len(w)+1). range(99)Yine de 200'den küçük toplam giriş uzunluğu için düzgün çalıştığını düşünüyorum .

Daha fazla test:

>>> "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

Mathematica's kullanarak başarısızlıkla denedikten sonra LongestCommonSubsequencePositionskalıp eşleştirmeye döndüm.

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]<>""]

Desen eşleştirme kuralı,

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

sıralı bir sözcük çifti alır (karakter listeleri olarak gösterilir) ve şunu döndürür: (1) sözcükleri {a,y}ve {y,b}ardından (2) ybir sözcüğün sonunu diğer kelimenin başlangıcıyla bağlayan ortak alt dize ve Sonunda, {a,y,b}giriş sözcüklerinin yerini alacak olan birleşik kelime İlgili bir örnek için Belisarius'a bakınız: https://mathematica.stackexchange.com/questions/6144/looking-for-longest-common-substring-solution

Ardışık üç alt çizgi karakteri, öğenin sıfır veya daha fazla karakter dizisi olduğunu gösterir.

ReverseHer iki siparişin test edilmesini sağlamak için daha sonra kullanılır. Bağlanabilir harfleri paylaşan çiftler değiştirilmez ve dikkate alınmaz.

Düzenle :

Aşağıdaki, başka bir kelimeyle "gömülen" (yani tamamen yerleşmiş) (@ flornquake'in yorumuna cevap olarak) listesindeki kelimeleri kaldırır.

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

Örnek :

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

döner

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


kullanım

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

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

"LOREM"

{0.006256, "SEDOLOREMAGNAD"}


Bu girdi için çalışıyor mu "LOREM", "ORE", "R"?
Flornquake

(Yani, doğru çıktı üretir "LOREM"mi?)
flornquake

@flornquake. İyi yakaladın. Geçerli sürümde ele aldım. Umarım başka davaları da kaçırmamışımdır. Teşekkürler.
DavidC,

Hiçbir şey ama en iyisi!
DavidC

3

GolfScript, 66 karakter

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

Oldukça kısa, ancak üstel zaman karmaşıklığı (ve GolfScript) gerçekten yavaş olduğundan, 10 saniye zaman sınırını aştı.

Örnekler:

['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)

Giriş: ['LOREM', 'DOLOR', 'SED', 'DO', 'MAGNA', 'AD', 'DOLORE']
Çıkış:SEDOLOREMAGNAD

Düzenle

reduceVe bazı kirli ithalat hileci kullanarak , bunu daha da azaltabilirim (ve sadece bir satıra!):

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)

Düzenle 2

Flornquake'in belirttiği gibi, bir kelime bir başkasında bulunduğunda bu yanlış sonuçlar verir. Bunun için düzeltme başka 13 karakter ekler:

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)

İşte temizlenmiş versiyonu:

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')

Birkaç karakteri teorik doğruluk pahasına kullanmak range(99)yerine range(len(x))(bunu düşünmek için flornquake kredisi) kullanarak tıraş etmek mümkündür.


Doğruluğu feda etmeye istekli iseniz, açgözlü yaklaşımı veya 2 yaklaşımın polinom yaklaşım faktörünü de kullanabilirsiniz.
Peter Taylor

Güzel çözüm! Yine de yeni sözcüklerin zaten süperstring'de olup olmadığını kontrol etmeniz gerekir: 'LOREM', 'ORE', 'R'yanlış çıktı üretir LOREMORER.
Flornquake

@flornquake İyi yakala. Düzeltmeyi başardım ama 13 karakter ekliyor.
Baptiste M.

1

Python, 144 karakter

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]

SAhala yerleştirilmesi gereken bir kelime kümesi ve sşimdiye kadar yerleştirilmiş kelimeleri içeren bir dize alır . Biz kalan kelime seçmek agelen Ave onu üst üste 0için len(a)bitimiyle karakterler s.

Verilen örnekte sadece yaklaşık 0.15 saniye sürer.


Gerçekten hoş! Ancak diğer bazı çözümler gibi, bu giriş gibi için işe yaramaz ['LOREM', 'ORE', 'R']. Bunu düzeltmek için özgürlüğümü kullandım ve çözümünüzü biraz daha arttırdım: 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(ikinci satıra gerek yok). Kullanım: S({'LOREM', 'DOLOR', 'SED', 'DO', 'MAGNA', 'AD', 'DOLORE'})döndürür '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 ""

Fonksiyonun bir isme bağlı olması gerekmiyorsa eksi iki

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.