Periksa apakah string adalah kocokan kembar

10

Penjelasan

Dua string dapat dikocok dengan menyelingi surat-surat mereka untuk membentuk string baru, seperti dua tumpukan kartu dapat dikocok untuk membentuk satu tumpukan.

Misalnya, senar HELLOdan WORLDdapat dikocok untuk membentuk HWEOLRLLOD, atau HEWORLLLDO, atau mungkin hanya HELLOWORLD.

Ini bukan acak jika urutan huruf asli tidak dipertahankan. Misalnya, Ddalam WORLDtidak dapat pernah muncul sebelum Rsetelah dikocok. Ini berarti bahwa EHLLOWRDLO, misalnya, bukan acak HELLOdan WORLD, meskipun berisi semua huruf asli.

String adalah pengocokan kembar jika dapat dibentuk dengan mengacak dua string yang identik. Misalnya, ABACBDECDEadalah kocokan si kembar karena dapat dibentuk dengan mengocok ABCDEdan ABCDE. DBEACBCADEbukan pengocokan kembar karena tidak dapat dibentuk dengan mengacak dua string yang identik.

Detail Program

Diberikan string input, output 0jika bukan kocokan kembar, dan output salah satu string kembar jika itu adalah kocokan kembar.

Anda dapat mengasumsikan bahwa string input memiliki panjang inklusif antara empat dan dua puluh karakter dan seluruhnya terdiri dari karakter huruf besar. Seharusnya bisa berjalan dalam jumlah waktu yang wajar, katakanlah, di bawah 10 menit.

Ini kode golf, jadi solusi terpendek menang.

Contoh I / O

> ABACBDECDE
ABCDE

> DBEACBCADE
0

> FFFFFF
FFF

> FFGGG
0

> ABBA
0

> AABB
AB

> AABAAB
AAB

Saya punya contoh implementasi (non-golf) .

Peter Olson
sumber
Contoh string FGG melanggar pernyataan that the input string has a length inclusively between four and twenty characters, dan jangan bilang "jangan pernah percaya input pengguna!", "Jangan pernah percaya spesifikasi!"
pengguna tidak diketahui
@userunknown Itu sangat memalukan! Saya mengeditnya FFGGGuntuk membuatnya konsisten.
Peter Olson
1
Hanya karena penasaran, adakah yang bisa menemukan solusi dengan kompleksitas waktu terburuk sub-eksponensial, atau membuktikan bahwa tidak ada?
Ilmari Karonen

Jawaban:

4

Haskell, 114

main=getLine>>=putStrLn.f.p;f x=head$[a|(a,b)<-x,a==b]++["0"]
p[]=[([],[])];p(x:y)=do(a,b)<-p y;[(x:a,b),(a,x:b)]

Tidak Disatukan:

main :: IO ()
main = getLine >>= putStrLn . findMatch . partitions

-- | Find the first partition where the two subsequences are
-- equal. If none are, return "0".
findMatch :: [(String, String)] -> String
findMatch ps = head $ [a | (a,b) <- ps, a == b] ++ ["0"]

-- | Return all possible partitions of the input into two
-- subsequences. Preserves the order of each subsequence.
--
-- Example:
-- partitions "AB" == [("AB",""),("B","A"),("A","B"),("","AB")]
partitions :: [a] -> [([a], [a])]
partitions []     = [([], [])]
partitions (x:xs) = do (a, b) <- partitions xs
                       [(x:a, b), (a, x:b)]

Penjelasan:

Sebagian besar pekerjaan sedang dilakukan dalam partitionsfungsi. Ia bekerja dengan secara rekursif menghasilkan semua partisi (a, b)dari ekor daftar, dan kemudian menggunakan daftar monad untuk menambahkan elemen awal xke masing-masing dari mereka dan mengumpulkan semua hasil.

findMatchberfungsi dengan memfilter daftar ini sehingga hanya partisi yang urutannya tetap sama. Kemudian mengembalikan urutan pertama di partisi pertama. Jika tidak ada yang tersisa, daftar itu kosong, jadi yang "0"ditambahkan pada akhirnya akan dikembalikan sebagai gantinya.

main baca saja inputnya, masukkan melalui dua fungsi ini dan cetaklah.

hammar
sumber
Bagi kita yang tidak bisa membaca Haskell, maukah Anda memberikan penjelasan?
Mr.Wizard
1
@ Mr.Wizard: Lihat edit.
hammar
Saya pikir saya datang dengan sesuatu yang sangat mirip, meskipun tidak sesingkat itu, tetapi saya melemparkan sesuatu yang bodoh yang membuatnya gagal total. Apakah Anda keberatan jika saya menerapkan algoritme ini di Mathematica?
Mr.Wizard
4

R, 113 karakter

l=length(x<-charToRaw(scan(,'')));max(apply(combn(l,l/2),2,function(i)if(all(x[i]==x[-i]))rawToChar(x[i])else 0))

Tidak digabungkan (dan alih-alih fungsi yang mengambil string):

untwin <- function(x) {
  x <- charToRaw(x)
  indMtx <- combn(length(x),length(x)/2)
  res <- apply(indMtx, 2, function(i) {
    if (all(x[i]==x[-i]))
      rawToChar(x[i])
    else
      0
  })
  max(res)
}

untwin("ABACBDECDE") # "ABCDE"
untwin("DBEACBCADE") # 0

Solusinya bergantung pada combnfungsi yang menghasilkan semua kombinasi indeks sebagai kolom dalam matriks. applykemudian menerapkan fungsi ke setiap kolom (dimensi 2) dalam matriks dan mengembalikan vektor string atau nol. maxkemudian temukan string terbesar (yang mengalahkan 0).

Fitur keren di R adalah kemampuan untuk memilih subset dari vektor yang diberi vektor indeks, dan untuk kemudian memilih pelengkap dari subset tersebut dengan meniadakan indeks:x[i] == x[-i]

Tommy
sumber
Melakukan beberapa peningkatan bertahap dan mengurangi jumlah arang.
Tommy
3

Mathematica, 87

Ini secara langsung didasarkan pada posting hammar, tetapi mudah-mudahan cukup berbeda untuk mendapatkan posting.

<<Combinatorica`

f=Catch[Cases[Characters@#~KSetPartitions~2,{x_,x_}:>Throw[""<>x]];0]&

Uji:

f /@ {"ABACBDECDE", "DBEACBCADE", "FFFFFF", "FGG", "ABBA", "AABB", "AABAAB"}
{"ABCDE", 0, "FFF", 0, 0, "AB", "AAB"}
Tuan Wisaya
sumber
1

D

string c(string in,string a=[],string b=[]){
    if(in.length==0)return a==b?a;"0";
    auto r=c(in[1..$],a~in[0],b);
    return r=="0"?c(in[1..$],a,b~in[0]):r;
}
void main(){writeln(c(readline));}

menggunakan kedalaman pencarian rekursif pertama

Saya bisa membuatnya lebih cepat dengan int i = min(a.length,b.length);if(a[0..i]!=b[0..i])return "0";klausa penjaga

aneh ratchet
sumber
Pada IDEONE, saya gagal mencoba memulai program dengan void main(){writeln(c("ABCADABCAD"));}- hanya versi D yang berbeda, salah saya, sesuatu yang lain? Bagaimana dengan "ABCABCA"?
pengguna tidak diketahui
Anda harus mengimpor std.stdio; untuk IO
ratchet freak
1

Ruby, 89 karakter

s=->a,x,y{a=="\n"?x==y ?x:?0:[s[b=a[1..-1],x+c=a[0],y],s[b,x,y+c]].max}
$><<s[gets,'','']

Kode ini mengimplementasikan algoritma pencarian rekursif biasa. Masukan harus diberikan pada STDIN.

Howard
sumber
1

Perl, 68 karakter

/^((.+)(?{local($x,$,)=($,,$x.$^N)}))+$(?(?{$o=$,eq$x&&$,})|x)/?$o:0

String input diasumsikan dalam $_variabel, output adalah nilai ekspresi. Mengejar baris baru dalam input diabaikan. Anda dapat menjalankan ini dari baris perintah seperti ini:

perl -lne 'print /^((.+)(?{local($x,$,)=($,,$x.$^N)}))+$(?(?{$o=$,eq$x&&$,})|x)/?$o:0'

Kode ini memanfaatkan mesin regexp Perl (dan khususnya fitur eksekusi kode yang disematkan ) untuk melakukan backtracking. Pada dasarnya, ini cocok dengan string input terhadap regexp ^((.+))+$, melacak kiriman bernomor ganjil dan genap di $xdan $,, dan menolak kecocokan pada akhirnya jika keduanya tidak sama.

Ilmari Karonen
sumber
Apakah ini memiliki hasil yang benar AABAAB?
Peter Olson
Ya itu. (Sebenarnya, AABAABini adalah kasus yang mudah untuk solusi ini, karena kelompok luar hanya perlu mencocokkan dua kali. Butuh waktu lebih lama untuk menyelesaikannya dengan AABBbenar.)
Ilmari Karonen
1

Python, 168 karakter

def f(s):
 c=s[0]
 d=i=r=0
 if s==c+c:r=c
 while i+1 and i<=len(s)/2 and not r:
  if i:d=f(s[1:i]+s[i+1:])
  if d:r=c+d
  i=s.find(c,i+1)
 return r
print f(raw_input())
Steven Rumbalski
sumber