Skip to content

Word Ladder.md #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Word Ladder.md #18

wants to merge 1 commit into from

Conversation

katataku
Copy link
Owner

distance = 0
for i in range(len(str1)):
if str1[i] != str2[i]:
distance += 1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

distance が 2 になったところで return False すると、処理量が少し減ると思います。

```python
class Solution:
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
def is_adjacent_pair(str1, str2):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

長さが違うものが来たらどうなるか考えておきましょう。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます。
せっかくなので、面接だったらどういう選択肢を視野に入れて面接官とディスカッションするか考えてみました。

  • 異常な値として対応するパターン
    • 例外を投げて処理を停止する。
      • wordListに異なる値が含まれている時点で例外を投げる。
    • 異常な値だけ無視して処理を続行する。
      • “正しい長さ”も受け取るように修正する方法。
      • データの内容から”正しい長さ”も決める方法。(多数決など)
  • 正常な値として対応するパターン
    • adjacentの定義をハミング距離からレーベンシュタイン距離に変更して対応する

P.S. レーベンシュタイン距離は、正式な用語がわからずググりました。また、ハミング距離は”ハフマン距離”と間違えて覚えていました。。。
https://ja.wikipedia.org/wiki/%E3%83%AC%E3%83%BC%E3%83%99%E3%83%B3%E3%82%B7%E3%83%A5%E3%82%BF%E3%82%A4%E3%83%B3%E8%B7%9D%E9%9B%A2

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

自分なら、問題としては長さが違うものが来てもOK。単にその単語が到達不能なだけで無視すれば良い。
is_adjacent_pairの入力として長さが違う物が来たら、Falseを返すかなという感じです。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

正常な値として対応するパターン
adjacentの定義をハミング距離からレーベンシュタイン距離に変更して対応する

これは問題全体の要件が変わっているじゃんという気持ちです。まあそのレイヤーでの話をしているなら、良いですが、odaさんの意図とは違う気がします。

distance = 0
for i in range(len(str1)):
if str1[i] != str2[i]:
distance += 1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2以上になったら False を返すのも一つです。

- 2回くらいなら許容な気がした。3回以上足し算があるなら、f-stringの方が読みやすそう

- > で、そのおまけの話として、
hamming_distance(a, b) と hamming_distance(b, a) が同じ結果なのに別のキャッシュになるのを避けたい気持ちがあるので、@cache つけるのを補助関数にするなどを考えていました。
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

これ、たとえば、大小関係を入れようとすると、大小関係の確認に文字列を比べてしまい、hamming 距離の計算と遜色がない時間かかるので、id 化するなどちょっと工夫が必要でしょう。

- 前者は`O(len(wordList)*len(word))`
- 後者は`O(26*len(word))`
- https://github.com/TORUS0818/leetcode/pull/22/files#r1666932153

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://discord.com/channels/1084280443945353267/1295357747545505833/1309222881330335816
変えるところを "*" に置き換えてルックアップという方法もありました。

- 実装時間: 4分
- wordListの要素数を`n`, wordの長さ`l`をとして、
- 時間計算量: O(ln)
- generate_adjacentsでO(26 * l)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

文字数だけループするのと、その中で新しい文字列を作成しているのでl^2ですかね?
なんかlだと視認性が悪いので他のアルファベットを使ってもらう方が良いかもです。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます!
文字列作成気づいてませんでした。ご指摘の通りです。

lが見にくいも確かにです。ありがとうございます。

- wordListの要素数を`n`, wordの長さ`l`をとして、
- 時間計算量: O(ln)
- generate_adjacentsでO(26 * l)
- メインのループでO(l)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

これはO(n)?

word_and_lengths = deque([(beginWord, 1)])
while word_and_lengths:
word, length = word_and_lengths.popleft()
if word == endWord:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この判定をnext_wordに対して行うことで、dequeに入れる前に判定できるので少しだけ高速化可能です。

if next_word in unused_words:
yield next_word

word_and_lengths = deque([(beginWord, 1)])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好みの問題かもですが、words_and_lengthsと、両方とも複数形にするほうが違和感が少ないと思いました。

@hroc135
Copy link

hroc135 commented Jan 14, 2025

最初にハミング距離が1である単語同士を結んだ無向グラフを作り、グラフに対してBFSをするという方法もあると思います
ハミング距離計算しながら、隣接する単語を列挙しながら、endWordを探す、となると同時に色々なタスクを進めることになるので、自分としてはそれぞれの作業を一度にまとめる方が認知負荷が少ないと思いました。wordListがめちゃくちゃ大きくてbeginWordからendWordへすぐ行ける場合に無駄な計算をいっぱいすることにはなりますが

```python
class Solution:
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
def generate_adjacents(word):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

個人的にはここは外側で定義して、generate_unused_adjacentsとして、引数はunused_wordsも含めます。(その方がインターフェーとしてわかりすい気がしました)

return length
for next_word in generate_adjacents(word):
word_and_lengths.append((next_word, length + 1))
unused_words.remove(next_word)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

個人的にはused_wordsに突っ込んでく方が好きですが、好みの問題かもしれません

Comment on lines +160 to +161
if next_word not in unused_words:
continue
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L148~149かここの、どっちかは必要ないですかね

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants