Sub-urutan Wrap-Around

11

pengantar

Dalam tantangan ini, tugas Anda adalah menemukan string yang disamaratakan secara umum. Selanjutnya tidak selalu berdekatan, dan mereka juga dapat "membungkus" string, melewati ujungnya dan mulai lagi dari awal. Anda akan ingin meminimalkan jumlah wraps.

Lebih formal, biarkan udan vmenjadi dua string, dan k ≥ 0bilangan bulat. Kami mengatakan bahwa uini adalah proses kpembatalan awal v, jika ada indeks yang berbeda sehingga , dan sebagian besar indeks memuaskan . Ini berarti bahwa dapat ditemukan di dalam dengan pergi dari kiri ke kanan, memilih beberapa karakter di jalan, dan membungkus sekitar waktu paling banyak (sama, melakukan paling banyak menyapu ). Perhatikan bahwa tidak ada karakter yang dapat dipilih lebih dari sekali, bahkan setelah selesai, dan bahwa -menggulung tulisan adalah persis biasa yang kita semua kenal.i1, i2, ..., ilen(u)u == v[i1] v[i2] ... v[ilen(u)]kijij > ij+1uvkk+1v0

Tugas

Input Anda adalah dua string alfanumerik yang tidak kosong udan v, dan output Anda adalah bilangan bulat terkecil ksehingga umerupakan akhir proses kpembungkus v. Jika tidak kada, output akan menjadi -1.

Contoh

Pertimbangkan input u := xyzyxzzxyxdan v := yxzzazzyxxxyz. Jika kita mulai mencari karakter udalam vdengan cara serakah, kita akan membungkus sekitar 3 kali:

 yxzzazzyxxxyz
>─x─────y────z┐
┌─────────────┘
└y───────x────┐
┌─────────────┘
└──zz─────x─y─┐
┌─────────────┘
└──────────x──>

Jadi output yang benar adalah paling banyak 3. Perhatikan bagaimana karakter paling kiri xdipilih sekali, dan kemudian diabaikan pada sapuan kedua, karena tidak dapat digunakan kembali. Namun, ada metode yang lebih pendek dengan hanya 2 bungkus:

 yxzzazzyxxxyz
>──────────xyz┐
┌─────────────┘
└yxzz────x────┐
┌─────────────┘
└───────y─x───>

Ternyata satu bungkus-sekitar (yaitu, dua sapuan) tidak cukup, jadi output yang benar adalah 2.

Aturan dan Bonus

Anda dapat menulis fungsi atau program lengkap, dan Anda juga dapat mengubah urutan input jika diperlukan. Hitungan byte terendah menang, dan celah standar tidak diizinkan.

Ada bonus -10% untuk menghitung semua kasus uji dalam waktu kurang dari 10 detik. Saya akan menguji kasus yang tidak jelas pada mesin saya; implementasi referensi saya di Python membutuhkan waktu sekitar 0,6 detik. Saya memiliki laptop 7 tahun dengan CPU dual core 1,86 GHz, yang mungkin perlu Anda pertimbangkan.

Uji Kasus

"me" "moe" -> 0
"meet" "metro" -> -1
"ababa" "abaab" -> 1
"abaab" "baabaa" -> 1
"1c1C1C2B" "1111CCCcB2" -> 3
"reverse" "reserved" -> 2
"abcdefg" "gfedcba" -> 6
"xyzyxzzxyx" "yxzzazzyxxxyz" -> 2
"aasdffdaasdf" "asdfddasdfsdaafsds" -> 2
Zgarb
sumber
1
Apakah ini juga merupakan solusi yang valid untuk contoh ini? Ini pendekatan serakah.
orlp
@ orlp Tidak valid, karena yang pertama xdigunakan dalam tiga sapuan berbeda. Ini hanya bisa digunakan sekali.
Zgarb
Ahhh, aku mengerti sekarang.
orlp

Jawaban:

4

Pyth, 34 byte

Mh+Smssm>.ukC,[email protected]_1

Ini mendefinisikan fungsi g, yang mengambil dua string sebagai parameter. Cobalah secara online: Pyth Compiler / Executor

Kode ini sangat tidak efisien. Ini memiliki kompleksitas waktu dan memori len(v)!/(len(v)-len(u))!. Itu tidak dapat menyelesaikan kasus uji yang lebih lama dalam waktu kurang dari 10 detik. (Ini juga akan crash sangat mungkin, karena akan kehabisan memori.)

M                                    define g(G, H): return _
                          .PUHlG        all permutations of [0, 1, ..., len(H)-1] of length len(G)
                 fqGsm@HkT              filter the permutations which form the string G
    mssm>.ukC,dtd                       compute the number of wraps for each of the remaining permutations
  +S                            _1      sort the numbers and append -1
 h                                      return the first element
Jakube
sumber
4

Haskell, 160 * 0,9 = 144 byte

a#(-1)=a
a#b=min a b
f y=w(y++" ")0$length y
w _ n _[]=n
w(c:d)n o g@(a:b)|n>o=(-1)|a==c=z#w y n z g|c==' '=w y(n+1)o g|1<2=w y n o g where z=w d n o b;y=d++[c]

Waktu untuk semua kasus uji (catatan: argumen dibalik):

*Main> map (uncurry f) [
             ("moe", "me"),
             ("metro", "meet"),
             ("abaab", "ababa"),
             ("baabaa", "abaab"),
             ("1111CCCcB2", "1c1C1C2B"),
             ("reserved", "reverse"),
             ("gfedcba", "abcdefg"),
             ("yxzzazzyxxxyz", "xyzyxzzxyx"),
             ("asdfddasdfsdaafsds", "aasdffdaasdf")]
[0,-1,1,1,3,2,6,2,2]
(0.08 secs, 25794240 bytes)

Cara kerjanya (versi pendek): brute force sederhana yang mengambil minimum menggunakan karakter yang cocok dan melewatkannya. Saya menghentikan pencarian ketika selesai (mengembalikan jumlah siklus) atau ketika bersepeda lebih dari minimum sejauh ini (mengembalikan -1).

Menyimpan banyak byte dibandingkan dengan versi pertama saya, terutama karena saya beralih dari program lengkap ke fungsi.

Dengan beberapa komentar dan jarak yang tepat, golf Haskell cukup mudah dibaca:

-- a minimum function that ignores a -1 in the right argument to prevent
-- "not solvable" cases in parts of the recursive search to dominate low numbers
-- of solvable parts. If the case isn't solvabale at all, both arguments are
-- -1 and are carried on.
a # (-1) = a
a # b    = min a b

-- the main function f calls the worker funktion w with arguments
-- * the string to search in (STSI), appended by a space to detect cycles
-- * the number of cycles so far
-- * the minimum of cycles needed so far, starting with the length of STSI
-- * the string to search for (STSF) (partial applied away and therefore invisible)
f y = w (y++" ") 0 (length y)

-- the worker function 
w _ n _ [] = n          -- base case: if STSF is empty the work is done and the 
                        -- number of cycles is returned

w (c:d) n o g@(a:b)     -- "c" is first char of STSI, "d" the rest
                        -- "n" number of cycles, "o" minimum of cycles so far
                        -- "g" is the whole STSF, "a" the 1st char, "b" the rest
  | n>o    = (-1)             -- if current cycle is more than a previous result,
                              -- indicate failure
  | a==c   = z # w y n z g    -- if there's a character match, take the min of
                              -- using it and skipping it
  | c==' ' = w y (n+1) o g    -- cycle detected, repeat and adjust n
  | 1<2    = w y n o g        -- otherwise try next char in STSI

  where                 -- just some golfing: short names for common subexpressions
  z = w d n o b;        -- number of cycles if a matching char is used
  y = d ++ [c]          -- rotated STSI

Untuk referensi: versi lama, program lengkap, 187 byte

main=interact$show.f.lines
a#(-1)=a
a#b=min a b
f[x,y]=w x(y++" ")0 0
w[]_ n _=n
w g@(a:b)(c:d)n m|a==c=w b d n 1#y|c==' '&&m==1=w g(d++" ")(n+1)0|c==' '=(-1)|1<2=y where y=w g(d++[c])n m
nimi
sumber
@ Zgarb: mengerjakan ulang solusi saya. Sekarang lebih cepat dan lebih pendek.
nimi
Berjalan dalam 0,6s saat ditafsirkan, 0,01s saat dikompilasi.
Zgarb
2

JavaScript (ES6) 174 (193 - 10%)

Pencarian rekursif, seperti jawaban @ nimi, menjaga min wraps. Ruang solusi besar (di atas semua untuk contoh terakhir) tetapi memotong pencarian di min saat ini ditemukan membuat waktu tetap rendah. Sunting 1 Tambahkan test case yang hilang, disingkat sedikit. Edit 2 Tidak perlu melewati parameter, itu diperbaiki

K=(w,s,x)=>
  ~-(R=(r,l,p=0,q=1,z=w[p],i=0)=>
  {
    if(z&&!(q>x)){
      if(~(r+l).indexOf(z))
        for(t=l?R(l+r,'',p,q+1):x;x<t?0:x=t,i=~r.indexOf(z,-i);)
          t=R(r.slice(-i),l+r.slice(0,~i),p+1,q);
      q=x
    }
    return q
  })(s,'')

Tidak disatukan

K=(word, astring)=>
{
  var minWraps // undefined at first. All numeric comparison with undefined give false 
  var R=(right, left, pos, wraps)=>
  {
    var cur = word[pos]
    var i,t;
    if (! cur) // when all chars of word are managed
      return wraps;
    if (wraps > minWraps) // over the minimum wrap count already found, stop search
      return wraps; 
    if ( (right+left).indexOf(cur) < 0 ) // if the current char is not found in the remaining part of the string
      return minWraps; // return the current min, could still be undefined (that means 'no way')
    if ( left ) // if there is a left part, try a wrapping search with the current char
    {
      t = R(left+right, '', pos, wraps+1)
      if ( !(minWraps < t)) minWraps = t; // set current min if t is less than current min or current min is still undefined
    }
    // find all occurrences of current char in the remaining part
    // for each occurrence, start a recursive search for the next char
    for(i = 0; (i = right.indexOf(cur, i)) >= 0; i++)
    {
      var passed = right.slice(0,i) // the passed chars go in the left part
      var rest = right.slice(i+1) 
      t = R(rest, left+passed, pos+1, wraps) // try next char in the remaining part, no wrap
      if ( !(minWraps < t)) minWraps = t; // set current min if t is less than current min or current min is still undefined
    }
    return minWraps
  }
  var result = R(astring, '', 0, 1) // start with right=string and left empty
  return ~-result; // decrement. convert undefined to -1
}

Uji di Firefox / konsol FireBug

time=~new Date;
[['me','moe']
,['meet','metro']
,['ababa','abaab']
,['abaab','baabaa']
,['1c1C1C2B','1111CCCcB2']
,['reverse','reserved']
,['abcdefg','gfedcba']
,['xyzyxzzxyx','yxzzazzyxxxyz']
,['aasdffdaasdf','asdfddasdfsdaafsds']]
.forEach(s=>console.log(s,r=K(...s)))
time-=~new Date

Output (baris terakhir adalah waktu eksekusi dalam ms)

["saya", "moe"] 0
["bertemu", "metro"] -1
["ababa", "abaab"] 1
["abaab", "baabaa"] 1
["1c1C1C2B", "1111CCCcB2"] 3
["terbalik", "dilindungi undang-undang"] 2
["abcdefg", "gfedcba"] 6
["xyzyxzzxyx", "yxzzazzyxxxyz"] 2
["aasdffdaasdf", "asdfddasdfsdaafsds"] 2
116

edc65
sumber
Diuji dengan Firebug, beroperasi pada 175ms di mesin saya.
Zgarb
@Zgarb maka ada ruang untuk perbaikan: Saya akan mencoba membuatnya lebih lambat dan lebih pendek
edc65