Conversation
arai60/Graph_BFS_DFS/word-ladder.md
Outdated
| // 時間計算量: O(N^2) | ||
| // 空間計算量: O(N) |
There was a problem hiding this comment.
@fhiyo
返信が大変遅くなりました。
N を明示する際改めて計算してみたのですが、間違っていますね。次のように修正しました。
/**
* 時間計算量: O(n * m^2):
* - O(n): wordList のクローン (n は wordList の要素数)
* - O(n * m^2): Map の生成 (n は wordList の要素数、 m は要素の文字数)
* - O(n * m^2): wordQueue の要素の走査 (n は wordQueue の最大要素数、 m は要素の文字数)
* 空間計算量: O(n * m)
* - O(n): wordListClone
* - O(n * m): globPatternToWords (n は Map の要素数、 m は value の要素数)
* - O(n): wordQueue
* - O(n): visitedWords
*/|
|
||
| private String createGlobPattern(int index, String word) { | ||
| StringBuilder patternBuilder = new StringBuilder(word); | ||
| patternBuilder.setCharAt(index, '?'); |
There was a problem hiding this comment.
leetcodeの制約上問題ないですが、'?'が使える文字に含まれる場合は上手くいかないですかね。
There was a problem hiding this comment.
確かにそうですね。一般的に String 値に含まれない null 文字を変わりに使ってみようと思います。
| Set<String> visitedWords = new HashSet<>(); | ||
| visitedWords.add(beginWord); | ||
|
|
||
| int distance = 1; |
There was a problem hiding this comment.
(細かい気はしますが) この変数名はちょっと違和感ありました。
beginWord = "a", endWord = "b", wordList = ["b"] だと答えは2になりますが、distanceとしては1が自然な気がしたので。
There was a problem hiding this comment.
仰るとおりだと思いました。Step 4 で numberOfWordsInSequence としてみましたが、こちらはいかがでしょうか?
| private static final int NO_SEQUENCE_EXISTS = 0; | ||
|
|
||
| public int ladderLength(String beginWord, String endWord, List<String> wordList) { | ||
| Deque<WordDistance> wordDistances = new ArrayDeque<>(); |
There was a problem hiding this comment.
これ Queue<WordDistance> wordDistances = new ArrayDeque<>(); で良かったりしますか?
There was a problem hiding this comment.
はい、特に問題ないです。
Queue にするなら使うメソッドも offer(), poll() に書き換えたいですね
| while(!wordQueue.isEmpty()) { | ||
| distance++; | ||
| int wordQueueSizeSnapshot = wordQueue.size(); | ||
| for (int wordQueueIndex = 0; wordQueueIndex < wordQueueSizeSnapshot; wordQueueIndex++) { |
There was a problem hiding this comment.
wordQueueIndex, 意味ありげに長いけど使ってない変数なので気になりました。中のiをjとかに変えてiで良いような気がします
There was a problem hiding this comment.
そうですね、ロジックを書いててややこしくならないように命名してましたが、これは i とかで良いように思います。
There was a problem hiding this comment.
step 4 の修正案ではこちらのレビューを踏まえ、そもそもキューの扱い方を変えてこの for 文に相当するものでイテレータを使わなくなってしまいましたが、今後はそのようにしようと思います。
| for (String word : wordList) { | ||
| for (int i = 0; i < word.length(); i++) { | ||
| String globPattern = createGlobPattern(i, word); | ||
| List<String> list = adjacencyMap.getOrDefault(globPattern, new ArrayList<>()); |
There was a problem hiding this comment.
adjacencyMapと言いつつそのkey-valueの関係はpatternとそれにマッチするwordsの関係なのでちょっと気になりました。patternToWordsとかで良い気がします。
There was a problem hiding this comment.
step 4 で globPatternToWords に修正しました。
| addedWords.add(targetWord); | ||
| wordDistances.addLast(new WordDistance(targetWord, wordDistance.distance + 1)); | ||
| } | ||
| wordList.removeAll(addedWords); |
There was a problem hiding this comment.
wordList -> remainedWords, addedWords -> waypointWordsとかでどうでしょうか?
| continue; | ||
| } | ||
| wordQueue.offer(adjacentWord); | ||
| visitedWords.add(adjacentWord); |
There was a problem hiding this comment.
ネストが少しキツイ気がします。
BFSなら配列を用意してword.length()のループを無くしたり、197-205辺りを別途関数として切り出すのは如何でしょうか。
| ``` | ||
|
|
||
| - Levenshtein distance, Edit distance, Hamming distance についての知識があれば `step` よりも `distance` の方が役割を理解しやすいなと思ったので変数名を修正 ([こちらのコメント](https://github.com/Ryotaro25/leetcode_first60/pull/22#issuecomment-2255580125)とその引用から知りました) | ||
| - クラスの外から渡される引数 wordList を書き換える副作用があっていいのかは議論の余地ありなので、一応その点コメント |
There was a problem hiding this comment.
そうですよね。step 4 では元はいじらずにクローンオブジェクトを作ってそれを扱うようにしました。
| for (int i = 0; i < word.length(); i++) { | ||
| String globPattern = createGlobPattern(i, word); | ||
| for (String adjacentWord : adjacencyMap.get(globPattern)) { |
| int distance = 1; | ||
| while(!wordQueue.isEmpty()) { | ||
| distance++; | ||
| int wordQueueSizeSnapshot = wordQueue.size(); |
There was a problem hiding this comment.
個人的に、一つの Queue と distance 変数を使って、ループごとに distance が一定な要素だけが出てくるという処理、間違ってはいないんですが、これが「ループごとに distance が一定な要素だけが出てくる」ことを示すためには、ループ全体で変なこと(たとえば、頭から追加されていないことなど)がなされていないことを確認しないといけないので、個人的には、ループごとに別の Deque なり Array なりを使って切り替えていくほうが好みではありますね。
There was a problem hiding this comment.
そうですね、Deque など new する処理は比較的重いから避けたかったのと、この書き方に慣れてて違和感無かったのでこの実装にしましたが、コメント頂いた書き方のほうが自然に思います。
他の指摘と合わせて後ほど修正します。
There was a problem hiding this comment.
あとネストも深くなりますしね今の実装だと
There was a problem hiding this comment.
修正結果を step 4 に書きました。
https://leetcode.com/problems/word-ladder/description/