diff --git a/127/step1.cpp b/127/step1.cpp new file mode 100644 index 0000000..92ec78f --- /dev/null +++ b/127/step1.cpp @@ -0,0 +1,99 @@ +/* + +Solve Time : over 1 hours + +Time : O(N^2 * log N) +Space : O(N^2) + +単語同士の距離から隣接リストを形成して探索すれば良い、というところまではすぐにたどり着いたが +微妙なミスを連発してしまい、時間がかかってしまった。 + +priority_queueのデフォルが最大を取り出す仕様を失念していた +最短距離を出す探索方法をしばらく失念しており、間違ったコードを書いていた + +*/ +class Solution { + public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + bool no_begin = std::none_of(wordList.begin(), wordList.end(), [beginWord](string s) { + return s == beginWord; + }); + if (no_begin) { + wordList.push_back(beginWord); + } + bool no_end = std::none_of(wordList.begin(), wordList.end(), [endWord](string s) { + return s == endWord; + }); + if (no_end) { + return 0; + } + vector> adjcent_indexes = vector>(wordList.size(), set{}); + for (int i = 0; i < wordList.size(); ++i) { + for (int j = 0; j < wordList.size(); ++j) { + string left = wordList[i]; + string right = wordList[j]; + if (!IsNextWord(left, right)) { + continue; + } + adjcent_indexes[i].insert(j); + adjcent_indexes[j].insert(i); + } + } + int begin_index; + int end_index; + for (int i = 0; i < wordList.size(); ++i) { + if (wordList[i] == beginWord) { + begin_index = i; + } + if (wordList[i] == endWord) { + end_index = i; + } + } + return CountDistance(begin_index, end_index, adjcent_indexes); + } + + private: + bool IsNextWord(const string left, const string right) { + int count = 0; + for (int i = 0; i < left.size(); ++i) { + if (left[i] != right[i]) { + ++count; + } + if (count > 1) { + return false; + } + } + if (count == 0) { + return false; + } + return true; + } + + int CountDistance(int begin_index, int end_index, vector>& adjcent_indexes) { + priority_queue, vector>, greater>> next_indexes; + next_indexes.emplace(1, begin_index); + vector distances(adjcent_indexes.size(), std::numeric_limits::max()); + distances[begin_index] = 1; + while (!next_indexes.empty()) { + auto [distance, index] = next_indexes.top(); + next_indexes.pop(); + if (distances[index] < distance) { + continue; + } + if (index == end_index) { + return distance; + } + distances[index] = distance; + for (auto next_index : adjcent_indexes[index]) { + if (distances[next_index] < distance + 1) { + continue; + } + next_indexes.emplace(distance + 1, next_index); + } + } + if (distances[end_index] == std::numeric_limits::max()) { + return 0; + } + return distances[end_index]; + } +}; diff --git a/127/step2_1.cpp b/127/step2_1.cpp new file mode 100644 index 0000000..9565df7 --- /dev/null +++ b/127/step2_1.cpp @@ -0,0 +1,91 @@ +/* + +Time : O(L * N^2) +Space : O(N^2) + +- 全てのノード間の距離が同じなのでpriority_queueは不要で、queueで十分 +- 隣接リストを作る際に、i < jの条件を追加して計算量を減らす +- BFSにて、queueが空になったときは到達不能と判断して良いのでif分を削除 +*/ +class Solution { + public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + bool no_begin = std::none_of(wordList.begin(), wordList.end(), [beginWord](string s) { + return s == beginWord; + }); + if (no_begin) { + wordList.push_back(beginWord); + } + bool no_end = std::none_of(wordList.begin(), wordList.end(), [endWord](string s) { + return s == endWord; + }); + if (no_end) { + return 0; + } + vector> adjacent_indexes = vector>(wordList.size(), set{}); + for (int i = 0; i < wordList.size(); ++i) { + for (int j = i + 1; j < wordList.size(); ++j) { + string left = wordList[i]; + string right = wordList[j]; + if (!IsNextWord(left, right)) { + continue; + } + adjacent_indexes[i].insert(j); + adjacent_indexes[j].insert(i); + } + } + int begin_index; + int end_index; + for (int i = 0; i < wordList.size(); ++i) { + if (wordList[i] == beginWord) { + begin_index = i; + } + if (wordList[i] == endWord) { + end_index = i; + } + } + return CountDistance(begin_index, end_index, adjacent_indexes); + } + + private: + bool IsNextWord(const string left, const string right) { + int count = 0; + for (int i = 0; i < left.size(); ++i) { + if (left[i] != right[i]) { + ++count; + } + if (count > 1) { + return false; + } + } + if (count == 0) { + return false; + } + return true; + } + + int CountDistance(int begin_index, int end_index, vector>& adjacent_indexes) { + queue> next_indexes; + next_indexes.emplace(1, begin_index); + vector distances(adjacent_indexes.size(), std::numeric_limits::max()); + distances[begin_index] = 1; + while (!next_indexes.empty()) { + auto [distance, index] = next_indexes.front(); + next_indexes.pop(); + if (distances[index] < distance) { + continue; + } + if (index == end_index) { + return distance; + } + distances[index] = distance; + for (auto next_index : adjacent_indexes[index]) { + if (distances[next_index] < distance + 1) { + continue; + } + next_indexes.emplace(distance + 1, next_index); + } + } + return 0; + } +}; diff --git a/127/step2_2.cpp b/127/step2_2.cpp new file mode 100644 index 0000000..6339b77 --- /dev/null +++ b/127/step2_2.cpp @@ -0,0 +1,90 @@ +/* + +Time : O(N * L * log N) +Space : O(N^2) + +他の人の解法を参考に改良したもの +隣接リストの形成を改善、単語のリストを二重ループで探索するのではなく、各単語を1文字ずつa - zに変化させて、wordList内に一致する単語の有無を確認。 + +*/ +class Solution { + public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + bool no_end = std::none_of(wordList.begin(), wordList.end(), [endWord](string s) { + return s == endWord; + }); + if (no_end) { + return 0; + } + bool no_begin = std::none_of(wordList.begin(), wordList.end(), [beginWord](string s) { + return s == beginWord; + }); + if (no_begin) { + wordList.push_back(beginWord); + } + vector> adjacent_indexes = vector>(wordList.size(), set{}); + ComposeAdjacentIndexes(adjacent_indexes, wordList); + int begin_index; + int end_index; + for (int i = 0; i < wordList.size(); ++i) { + if (wordList[i] == beginWord) { + begin_index = i; + } + if (wordList[i] == endWord) { + end_index = i; + } + } + return CountDistance(begin_index, end_index, adjacent_indexes); + } + + private: + void ComposeAdjacentIndexes(vector>& adjacent_indexes, const vector& wordList) { + map word_to_index; + for (int i = 0; i < wordList.size(); ++i) { + word_to_index[wordList[i]] = i; + } + for (int i = 0; i < wordList.size(); ++i) { + for (int char_index = 0; char_index < wordList[i].size(); ++char_index) { + string adjacent_word = wordList[i]; + for (char c = 'a'; c <= 'z'; ++c) { + adjacent_word[char_index] = c; + if (adjacent_word == wordList[i]) { + continue; + } + if (!word_to_index.contains(adjacent_word)) { + continue; + } + const int left = i; + const int right = word_to_index[adjacent_word]; + adjacent_indexes[left].insert(right); + adjacent_indexes[right].insert(left); + } + } + } + } + + int CountDistance(int begin_index, int end_index, vector>& adjacent_indexes) { + queue> next_indexes; + next_indexes.emplace(1, begin_index); + vector distances(adjacent_indexes.size(), std::numeric_limits::max()); + distances[begin_index] = 1; + while (!next_indexes.empty()) { + auto [distance, index] = next_indexes.front(); + next_indexes.pop(); + if (distances[index] < distance) { + continue; + } + if (index == end_index) { + return distance; + } + distances[index] = distance; + for (auto next_index : adjacent_indexes[index]) { + if (distances[next_index] < distance + 1) { + continue; + } + next_indexes.emplace(distance + 1, next_index); + } + } + return 0; + } +}; diff --git a/127/step3.cpp b/127/step3.cpp new file mode 100644 index 0000000..800b102 --- /dev/null +++ b/127/step3.cpp @@ -0,0 +1,70 @@ +class Solution { + public: + int ladderLength(string begin_word, string end_word, vector& word_list) { + bool no_end = none_of(word_list.begin(), word_list.end(), [end_word](string s) { return s == end_word;}); + if (no_end) { + return 0; + } + bool no_begin = none_of(word_list.begin(), word_list.end(), [begin_word](string s) { return s == begin_word; }); + if (no_begin) { + word_list.emplace_back(begin_word); + } + vector> adjacent_indexes = vector>(word_list.size(), vector{}); + ComposeAdjacentIndexes(adjacent_indexes, word_list); + int begin_index; + int end_index; + for (int i = 0; i < word_list.size(); ++i) { + if (word_list[i] == begin_word) { + begin_index = i; + } + if (word_list[i] == end_word) { + end_index = i; + } + } + return CountWordLadder(begin_index, end_index, adjacent_indexes); + } + + private: + void ComposeAdjacentIndexes(vector>& adjacent_indexes, const vector& word_list) { + for (int i = 0; i < word_list.size(); ++i) { + for (int j = i + 1; j < word_list.size(); ++j) { + if (!IsNextWords(word_list[i], word_list[j])) { + continue; + } + adjacent_indexes[i].emplace_back(j); + adjacent_indexes[j].emplace_back(i); + } + } + } + + bool IsNextWords(const string left, const string right) { + int diff_count = 0; + for (int i = 0; i < left.size(); ++i) { + if (left[i] != right[i]) { + ++diff_count; + } + } + return diff_count == 1; + } + + int CountWordLadder(const int begin_index, const int end_index, const vector>& adjacent_indexes) { + queue> indexes_and_distances; + indexes_and_distances.emplace(begin_index, 1); + vector distances = vector(adjacent_indexes.size(), numeric_limits::max()); + while (!indexes_and_distances.empty()) { + auto [index, distance] = indexes_and_distances.front(); + indexes_and_distances.pop(); + if (distances[index] <= distance) { + continue; + } + distances[index] = distance; + for (int next_index : adjacent_indexes[index]) { + if (next_index == end_index) { + return distance + 1; + } + indexes_and_distances.emplace(next_index, distance + 1); + } + } + return 0; + } +}; diff --git a/127/step4.cpp b/127/step4.cpp new file mode 100644 index 0000000..798e6be --- /dev/null +++ b/127/step4.cpp @@ -0,0 +1,84 @@ +class Solution { + public: + int ladderLength(string begin_word, string end_word, vector& word_list) { + bool no_end = true; + for (auto word : word_list) { + if (word == end_word) { + no_end = false; + break; + } + } + if (no_end) { + return 0; + } + bool no_begin = true; + for (auto word : word_list) { + if (word == begin_word){ + no_begin = false; + break; + } + } + if (no_begin) { + word_list.emplace_back(begin_word); + } + vector> adjacent_indexes = vector>(word_list.size(), vector{}); + ComposeAdjacentIndex(adjacent_indexes, word_list); + int begin_index; + int end_index; + for (int i = 0; i < word_list.size(); ++i) { + if (word_list[i] == begin_word) { + begin_index = i; + } + if (word_list[i] == end_word) { + end_index = i; + } + } + return CountWordLadder(begin_index, end_index, adjacent_indexes); + } + + private: + void ComposeAdjacentIndex(vector>& adjacent_indexes, const vector& word_list) { + for (int i = 0; i < word_list.size(); ++i) { + for (int j = i + 1; j < word_list.size(); ++j) { + if (!IsNextWord(word_list[i], word_list[j])) { + continue; + } + adjacent_indexes[i].emplace_back(j); + adjacent_indexes[j].emplace_back(i); + } + } + } + + bool IsNextWord(const string& left, const string& right) { + int diff_count = 0; + for (int i = 0; i < left.size(); ++i) { + if (left[i] != right[i]) { + ++diff_count; + } + } + return diff_count == 1; + } + + int CountWordLadder(const int begin_index, + const int end_index, + vector>& adjacent_indexes) { + queue> indexes_and_distances; + indexes_and_distances.emplace(begin_index, 1); + vector distances = vector(adjacent_indexes.size(), numeric_limits::max()); + while(!indexes_and_distances.empty()) { + auto [index, distance] = indexes_and_distances.front(); + indexes_and_distances.pop(); + if (distances[index] <= distance) { + continue; + } + distances[index] = distance; + for (int next_index : adjacent_indexes[index]) { + if (next_index == end_index) { + return distance + 1; + } + indexes_and_distances.emplace(next_index, distance + 1); + } + } + return 0; + } +};