ワードチェンジャーの到達可能性


13

ワードチェンジャーは、1文字の編集を介して1つの単語を別の単語に変換しようとしているゲームで、各ステップは独自の単語です。このチャレンジでは、編集は置換、挿入、または削除である場合があります。たとえば、WINNER→LOSERは、次のルートで実行できます(他にも可能性があります)。

WINNER
DINNER
DINER
DINE
LINE
LONE
LOSE
LOSER

別の言い方をすれば、毎回1のレーベンシュタイン距離で他の単語だけを経由して、ある単語から別の単語に到達できる必要があります。

コーディング

単語リストと2つの単語が与えられ、ルートが存在する場合は1つの単語から別の単語への有効なルートを、ルートが存在しない場合は明確な定数値または一貫した動作を出力する必要があります。

  • 入力単語は両方とも単語リストにあると仮定できます
  • 単語リストは、便利なフラット形式で取り込むことができます。
    • リスト、セット、試行、スペースで区切られた文字列、および行で区切られたファイルはすべて有効ですが(たとえば)、事前に計算されたレーベンシュタインの隣接関係のグラフは無効です。
  • 出力ルートには両方の入力語が含まれている必要がありますが、開始と終了はどちらでもかまいません。
  • ルートが見つからない場合、特定の定数、偽の値、空のリストを出力したり、例外をスローしたり、ゼロ以外のコードで終了したり、有限時間で発生するその他の動作を実行したりできます。
  • ルートは最適である必要はなく、どのルートを取るべきかという要件はありません。
  • 計算の複雑さは重要ではありませんが、プログラムは有限時間で終了することが保証されている必要があります。(たとえそれが宇宙の熱死を超えて走るとしても)
  • すべての単語が同じケースの文字で完全に構成されていると仮定することができます

テストケースの例

  • CAT→DOG; [CAT、DOG、COG、COT、FROG、GROG、BOG]
    • CAT、COT、COG、DOG
  • バス→シャワー; [BATH、SHOWER、HATH、HAT、BAT、SAT、SAW、SOW、SHOW、HOW]
    • ルートが見つかりません
  • BREAK→FIX; [BREAK、FIX、BEAK、BREAD、READ、BEAD、RED、BED、BAD、BID、FAD、FAX]
    • ブレーク、パン、ビード、悪い、FAD、FAX、FIX
  • 構築→破壊; [ビルド、デストロイ、ビルド、ギルト、ギルド、ギルド、ギル、ビル、ディル、フィル、破壊、構造、構築]
    • ルートが見つかりません
  • カード→ボード; [カード、ボード、ボード]
    • カード、ボード、ボード
  • デーモン→エンジェル; [悪魔、エンジェル]
    • ルートが見つかりません
  • 最後→過去; [最後、過去、爆発、キャスト、黒、ゴースト、ポスト、ブースト]
    • 最後、過去
  • 挿入→削除; この単語リスト
    • INSERT、INVERT、INVENT、INBENT、UNBENT、UNBEND、UNBIND、UNKIND、UNKING、INKING、IRKING、DIRKING、DARKING、DARRING、ARLING、AILING、SIRING、SERING、SERINE、NERINE、NERITE、CERITE、CERATE、DERATE、DELATE、削除


1
有効なルートのリストを出力できますか、それとも1つのルートにする必要がありますか?
エミグナ

@Emignaはどのルートでも可能です。「ルートは最適である必要はありません」と述べたように
Beefster

出力に開始語と終了語を含める必要がありますか?ルートは常に同じものを開始および終了します!
魔法のタコUr

1
@MagicOctopusUrn「出力ルートには両方の入力語を含める必要がありますが、開始と終了は関係ありません。」
ビーフスター

回答:


5

05AB1E23 21 20バイト

有効なルートのリストを印刷します。Kevin Cruijssenの
おかげで2バイト節約されました

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

オンラインでお試しください!


に変更Dævyœ«}すると、2バイト節約できます怜€` 。(なぜ両方のマップが別々にうまく機能æεœ`}するのかは
わかり

あまりにも悪いの製品が[]ある1の代わりに、0空のリストと同じチェックがあること(あまりにもかかわらず、驚くべきことではない)、または明らかに空のリストになり代わりに0...そうでなければ、あなたが結合している可能性が(私はバグとして参照この1 ...) :別のバイト保存するためのフィルタとfind_first怜€`.Δü.LPy¬²Qsθ³QP
ケビンCruijssen

@KevinCruijssen:ありがとう!を使用することを考えなかった理由がわかりません。同等のチェックは、ベクトル化のために空のリストになると思います。空のリストには特別なケースが必要かもしれませんが、他のケースでは予想外かもしれません。
エミグナ

1
17日間、このような動作をします
魔法のタコUr

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)

オンラインでお試しください!

入力として2つの単語と単語のセットを受け取ります。文字列のリストとして存在する場合は(最適でない)ルートを返し、そうでない場合はFalseを返します。

このフラグメント:

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

Truea==wまたはからのaレーベンシュタイン距離がある場合に限ります。1w



2

Python 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ṆƲ?€Ẏ

オンラインでお試しください!

3つの引数を受け入れる完全なプログラム。最初の単語は開始語で、として提供され[["START"]]ます。2番目の引数は、として指定される最後の単語"END"です。3番目の引数は、引用符で囲まれたコンマ区切りの単語として提供される単語リストです。

プログラムはリストのリストを返します。各リストは、開始から終了までの有効なパスを表します。有効なルートがない場合、応答は空のリストです。

TIOリンクには、スペースで区切られた各単語と改行で区切られた単語の各リストで、結果を適切に表示するためのフッターテキストがあります。リスト表示の基礎となる印刷出力が望ましい場合、これはとして実行できますÇŒṘ

05ABIEとは異なり、レーベンシュタイン距離にはビルトインがないため、このプログラムでは、@ ChasBrownのソリューションと多少似ていますが、ジェリーツイストではありますが、1つの文字が欠落している修正を比較します。

説明

ヘルパーリンク:単語のリストを取り、可能な拡張リストのリストを返すモナドリンク、またはそれ以上拡張できない場合は空のリスト

⁵ḟ                      | 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])

オンラインでお試しください!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.