Досяжність Word Changer


13

Змінник слів - це гра, в якій ви намагаєтесь перетворити одне слово на інше за допомогою однозначних редагувань, кожен крок - це власне слово. Для цього виклику правки можуть бути замінами, вставками чи видаленнями. Наприклад, WINNER → LOSER можна виконати за цим маршрутом (можуть бути й інші):

WINNER
DINNER
DINER
DINE
LINE
LONE
LOSE
LOSER

Фразований іншим способом, ви повинні мати можливість дістатися до одного слова від іншого, переходячи лише через інші слова на відстані Левенштейна, що дорівнює 1.

Кодування

Вам буде надано список слів і два слова, і ви повинні вивести дійсний маршрут від одного слова до іншого, якщо маршрут існує або чітке постійне значення або послідовна поведінка, якщо маршруту немає.

  • Ви можете припустити, що введені слова є в списку слів
  • Список слів можна взяти за допомогою будь-якого зручного плоского формату.
    • Списки, набори, спроби, рядки, розділені пробілом, і файли, розділені рядками, є дійсними (наприклад), але попередньо обчислений графік суміжності Левенштейна - ні.
  • Маршрут виводу повинен включати обидва вхідні слова, але те, що починається і закінчується, не має значення.
  • Якщо маршрут не знайдений, ви можете вивести конкретну константу, хибне значення, порожній список, викинути виняток, вийти з ненульовим кодом або будь-яку іншу поведінку, що відбувається в обмежений час.
  • Маршрут не повинен бути оптимальним, і немає вимоги, який маршрут слід пройти
  • Комплексна обчислювальність не має значення, однак ваша програма повинна бути гарантовано гарантована, що вона завершиться за певний час. (навіть якщо це би перебігло теплову смерть Всесвіту)
  • Ви можете припустити, що всі слова повністю складаються з букв в одному випадку

Приклади тестових випадків

  • CAT → DOG; [CAT, DOG, COG, COT, FROG, GROG, BOG]
    • CAT, COT, COG, DOG
  • БАНЯ → ДУШ; [Ванна, душ, шапочка, шапочка, ванна, сат, пила, соу, шоу, як]
    • Маршрут не знайдено
  • BREAK → FIX; [BREAK, FIX, BEAK, BREAD, READ, BEAD, CRED, BED, BAD, BID, FAD, FAX]
    • ПОЛУЧАЙТЕ, ХЛІБКА, БІЗ, НЕГО, ЗНАЧЕННЯ, ФАКС, ФІКС
  • БУДІВНИЦТВО → ДЕСТРОЙ; [БУДІВНИЦТВО, ДЕСТРОЙ, СТРОИТЕЛЬНІСТЬ, ПІДГОТОВЛЕННЯ, ГУЛІД, ДІЛЬ, ГІЛЬ, ВИРОБНИЦТВО, УРОК, ЗАЛИШКА, РОЗБУТ, СТРУКТУРА, КОНСТРУКТУРА]
    • Маршрут не знайдено
  • КАРТКА → РАДА; [Картка, рада, борд]
    • КАРТКА, БАРД, КАРТА
  • ДЕМОН → АНГЕЛ; [ДЕМОН, АНГЕЛЬ]
    • Маршрут не знайдено
  • ОСТАННІ → МІННІ; [ОСТАННІ, МІННІ, ВІДХОДНІ, ЛІТНІ, ЧЕРНІ, ПРИГОТОВІ, ПОШТОВІ, ПОБУТНІ]
    • ОСТАННІ, ПРОСТІ
  • ВСТАВКА → ВИДАЛИТИ; Цей список слів
    • ВСТАВКА, ВПРАВЛІННЯ, ІНВЕНТ, ВХОД, НЕБЕНТ, НЕБЕНД, БЕЗПЛАТИ, НЕЗАБАВЛЕННЯ, НЕКІНГ, ВПРАВЛЕННЯ, БЕЗПЕЧЕННЯ, ДІРКІНГ, ДАМКІН, ДАРЛІНГ, АРЛІНГ, АЙЛІНГ, СЕРІНГ, СЕРІНГ, СЕРІНА, НЕРИН, НЕРІТ, СЕРІТ, СЕРАТ, ДЕРАТ, ДЕРАТ УДАЛИТИ


1
Чи можемо ми вивести список дійсних маршрутів чи це повинен бути один маршрут?
Емінья

@Emigna будь-який маршрут буде робити. Як я вже згадував "Маршрут не повинен бути оптимальним"
Beefster

Чи потрібно нам включати початкове і закінчувальне слово у висновок? Маршрути завжди будуть починатися і закінчуватися однаково!
Чарівна восьминога

1
@MagicOctopusUrn "Маршрут виведення повинен включати обидва вхідні слова, але те, що починається і закінчується, не має значення."
Beefster

Відповіді:


5

05AB1E , 23 21 20 байт

Друкує список дійсних маршрутів.
Збережено 2 байти завдяки Kevin Cruijssen .

怜€`ʒü.LP}ʒ¬²Qsθ³Q*

Спробуйте в Інтернеті!


Ви можете зберегти 2 байти, змінивши Dævyœ«}на æ€œ€` . (Не впевнений, чому обидві карти окремо спрацьовують чудово, але æεœ`}не btw, але це все одно те саме число байтів.)
Кевін Круїйсен

Шкода , що продукт []є 1замість 0(Не дивно, хоча) , або рівний чек з порожнім списком по- видимому , призводить до порожнього списку замість 0(цього я бачу , як помилка ..) .. В іншому випадку ви могли б поєднували фільтр і find_first, щоб зберегти ще один байт:怜€`.Δü.LPy¬²Qsθ³QP
Kevin Cruijssen

@KevinCruijssen: Дякую! Не впевнений, чому я не думав використовувати . Я думаю, що рівна перевірка призводить до порожнього списку завдяки векторизації. Можливо, має бути окремий випадок для порожнього списку, але, можливо, це було б несподівано в інших випадках.
Емінья

1
Чи щось подібне працює для 17: Спробуйте в Інтернеті!
Чарівний восьминіг Урна

1
@MagicOctopusUrn: На жаль, нам потрібно включити до виводу всі слова шляху.
Емінья

4

JavaScript (V8) ,  177  176 байт

Вводиться як " (target)(source, list). Друкує всі можливі маршрути. Або нічого не друкується, якщо немає рішення.

t=>F=(s,l,p=[],d)=>s==t?print(p):l.map((S,i)=>(g=(m,n)=>m*n?1+Math.min(g(m-1,n),g(m,--n),g(--m,n)-(S[m]==s[n])):m+n)(S.length,s.length)^d||F(S,L=[...l],[...p,L.splice(i,1)],1))

Спробуйте в Інтернеті!

Прокоментував

t =>                            // t = target string
F = (                           // F is a recursive function taking:
  s,                            //   s = source string
  l,                            //   l[] = list of words
  p = [],                       //   p[] = path
  d                             //   d = expected Levenshtein distance between s and the
) =>                            //       next word (initially undefined, so coerced to 0)
  s == t ?                      // if s is equal to t:
    print(p)                    //   stop recursion and print the path
  :                             // else:
    l.map((S, i) =>             //   for each word S at index i in l[]:
      ( g =                     //     g = recursive function computing the Levenshtein
        (m, n) =>               //         distance between S and s
        m * n ?                 //       if both m and n are not equal to 0:
          1 + Math.min(         //         add 1 to the result + the minimum of:
            g(m - 1, n),        //           g(m - 1, n)
            g(m, --n),          //           g(m, n - 1)
            g(--m, n) -         //           g(m - 1, n - 1), minus 1 if ...
            (S[m] == s[n])      //           ... S[m - 1] is equal to s[n - 1]
          )                     //         end of Math.min()
        :                       //       else:
          m + n                 //         return either m or n
      )(S.length, s.length)     //     initial call to g with m = S.length, n = s.length
      ^ d ||                    //     unless the distance is not equal to d,
      F(                        //     do a recursive call to F with:
        S,                      //       the new source string S
        L = [...l],             //       a copy L[] of l[]
        [...p, L.splice(i, 1)], //       the updated path (removes S from L[])
        1                       //       an expected distance of 1
      )                         //     end of recursive call
    )                           //   end of map()


3

Python 2 , 155 байт

f=lambda a,b,W,r=[]:a==b and r+[a]or reduce(lambda q,w:q or any({a,a[:i]+a[i+1:]}&{w,w[:i]+w[i+1:]}for i in range(len(a+w)))and f(w,b,W-{a},r+[a]),W-{a},0)

Спробуйте в Інтернеті!

Приймає два слова і набір слів як вхідні дані; повертає (неоптимальний) маршрут, якщо такий існує як список рядків, інакше повертає False.

Цей фрагмент:

any({a,a[:i]+a[i+1:]}&{w,w[:i]+w[i+1:]}for i in range(len(a+w)))

це Trueякщо і тільки якщо a==wабо aмає відстань Левенштайн 1від w.



2

Пітон 2 , 163 байти

Якщо маршрут знайдений, він виводиться на stderr і програма виходить з кодом виходу 1.
Якщо маршруту немає, виходу немає і програма закінчується кодом виходу 0.

s,e,d=input();r=[[s]]
for x in r:t=x[-1];t==e>exit(x);r+=[x+[w]for w in d-set(x)for a,b in(t,w),(w,t)for i in range(len(b)*2)if a==b[:i/2]+a[i/2:][:i%2]+b[i/2+1:]]

Спробуйте в Інтернеті!



0

Желе , 38 байт

⁵ḟ,€0ị$ṭ¹-Ƥ$€e€/ẸƊƇḢ€
Wṭ@ⱮÇßƊe@⁴oṆƲ?€Ẏ

Спробуйте в Інтернеті!

Повна програма, що приймає три аргументи. Перше - це початкове слово і подається як [["START"]]. Другий аргумент - це заключне слово, подане як "END". Третій аргумент - це список слів, поданий як цитований, розділений комами.

Програма повертає список списків, кожен список представляє дійсний шлях від початку до кінця. Якщо немає правильного маршруту, відповідь - це порожній список.

У посиланні TIO є текст нижнього колонтитулу, щоб добре відображати результат з кожним словом, розділеним пробілами та кожним списком слів, розділених новими рядками. Якщо кращим є представлення роздрукованого списку, це може бути зроблено як ÇŒṘ.

На відміну від 05ABIE, для відстані Левенштейна немає вбудованої програми, тому ця програма порівнює виправлення з відсутнім одним символом, дещо схожим на рішення @ ChasBrown , хоча з желейним поворотом.

Пояснення

Посилання помічника: монадичне посилання, яке бере список слів і повертає список можливих розширених списків, або порожній список, якщо подальше розширення не можливе

⁵ḟ                      | Filter the word list to remove words already used
  ,€0ị$                 | Pair each word with the last word in the current path
                  ƊƇ    | Filter these pairs such that
              e€/Ẹ      |   there exists any
       ṭ¹-Ƥ$€           |   match between the original words or any outfix with a single character removed
                    Ḣ€  | Take the first word of each of these pairs (i.e. the possible extensions of the route)

Головна посилання

              €         | For each of the current paths
            Ʋ?          | If:
       e@⁴              |   The path contains the end word
          oṆ            |   Or the path is empty (i.e. could not be extended)
W                       | Return the path wrapped in a list (which will be stripped by the final Ẏ)
 ṭ@ⱮÇ                   | Otherwise, look for possible extensions using the helper link, and add onto the end of the path
     ßƊ                 | And then feed all of these paths back through this link
               Ẏ        | Strip back one layer of lists (needed because each recursion nests the path one list deeper)

0

Swift 4.2 / Xcode 10.2.1 , 387 байт

func d(l:String,m:String)->Bool{return (0..<l.count).contains{var c=l;c.remove(at:c.index(c.startIndex,offsetBy:$0));return c==m}};func f(r:[String])->[String]{if b==r.last!{return r};return w.lazy.map{!r.contains($0)&&(d(l:r.last!,m:$0)||d(l:$0,m:r.last!)||(r.last!.count==$0.count&&zip(r.last!,$0).filter{$0 != $1}.count==1)) ? f(r:r+[$0]):[]}.first{!$0.isEmpty} ?? []};return f(r:[a])

Спробуйте в Інтернеті!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.