diff --git a/542_01_matrix/memo.md b/542_01_matrix/memo.md new file mode 100644 index 0000000..37734d4 --- /dev/null +++ b/542_01_matrix/memo.md @@ -0,0 +1,41 @@ +# 542. 01 Matrix + +https://leetcode.com/problems/01-matrix/ + +## Comments + +### step1 + +* 5:00 くらい考えた + * 最短経路なので、BFS あたりで解けそう + * `1 <= m, n <= 10^4` なので、愚直に 1 から初めて最も近い 0 を探すとなると、O((m * n)^2) になり、10^16? さすがに C++ でも通らないな… + * 0 から始めるとどうかな。複数の 1 を一気に更新できるから効率は良さそう +* このあたりまで考えて 5:00 くらい。本当にこの方針でいいのか自信がなかったのと、実装が割と煩雑になりそうだったのでハマる前に答えを見ることにした。 + * `1 <= m * n <= 10^4` を見逃していた。セルの数自体も 10^4 なのか。なら 10^8 くらいに収まるから行けるか + * BFS だと最初の訪問 == 最短経路になる。0 から初めて visited かどうかを管理しておくと、結局それぞれのセルは 1 回ずつしか訪れないので O(m * n) のオーダーに収まる。 + * 1 から始めると、BFS しても途中で訪問したセルの最短距離は確定しないのでややこしい + * 答えを見る前に、0 から始めるか 1 から始めるかの選択肢を持てていたのは良かった。しかし runtime の観点できれいに考えを整理できていなかった。また実装方法についても具体的に頭の中でシミュレーションできていなかったので答えに頼ることになった +* 答えも参考に書いてみた。 + * まあ素直な書き方なのだが、上記実装を具体的に考えられていなかったのは、最初に前処理として 0 を queue に突っ込んでおく、というのを考えられていなかったからだと思われる。 + * あとは割と素直な BFS + * `distance` の命名は `steps` でもよかったかもしれない + * vector 変数の初期化でサイズ指定などを忘れていた。今までは `push_back` していくだけのものが多かったので失念。 + +```cpp +vector> distances(rows, vector(cols, 0)); +vector> visited(rows, vector(cols, false)); +``` + +### step2 + +* https://leetcode.com/problems/01-matrix/editorial/ + * あまりしっかり見れてはいない (TODO) のだが、DP での解法もあるみたい。まあ確かにできそうではある。 +* https://github.com/huyfififi/coding-challenges/pull/27 + * BFS で問題ないと思うのだが、`leetcode/542/step1_two_pass.py` の解答を一応 C++ で書き直してみた。 + * 最初 `numeric_limits` をそのまま使っていたのだが、+1 するケースがあり、そうすると overflow する。Gemini に進められたのでそのようにしてみた。でもこれ prod ではやりたくないな… 10000 という数字の選定も適当だし。 + * この解法、気持ちだけ DP っぽい雰囲気もする (前に確定した情報を使って次を更新していく) + +### step3 + +* skip +* 最終解答 (面接や prod だとしたら) としては step1 の BFS かなと思う diff --git a/542_01_matrix/step1.cpp b/542_01_matrix/step1.cpp new file mode 100644 index 0000000..602bc3c --- /dev/null +++ b/542_01_matrix/step1.cpp @@ -0,0 +1,49 @@ +#include + +class Solution { +public: + vector> updateMatrix(vector>& mat) { + int rows = mat.size(); + int cols = mat[0].size(); + vector> distances(rows, vector(cols, 0)); + vector> visited(rows, vector(cols, false)); + std::queue> cells_and_distances; + // Add zeros to the queue. + for (int row = 0; row < rows; ++row) { + for (int col = 0; col < cols; ++col) { + distances[row][col] = 0; + if (mat[row][col] == 0) { + cells_and_distances.push({row, col, 0}); + visited[row][col] = true; + } + } + } + + // BFS traversal + while (!cells_and_distances.empty()) { + vector info = cells_and_distances.front(); + cells_and_distances.pop(); + int row = info[0]; + int col = info[1]; + int distance = info[2]; + for (vector& direction : directions) { + int next_row = row + direction[0]; + int next_col = col + direction[1]; + if (!IsValid(next_row, next_col, rows, cols) || visited[next_row][next_col]) { + continue; + } + distances[next_row][next_col] = distance + 1; + visited[next_row][next_col] = true; + cells_and_distances.push({next_row, next_col, distance + 1}); + } + } + + return distances; + } +private: + vector> directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; + + bool IsValid(int row, int col, int rows, int cols) { + return 0 <= row && row < rows && 0 <= col && col < cols; + } +}; diff --git a/542_01_matrix/step2.cpp b/542_01_matrix/step2.cpp new file mode 100644 index 0000000..546fd5f --- /dev/null +++ b/542_01_matrix/step2.cpp @@ -0,0 +1,60 @@ +#include +#include + +using namespace std; + +class Solution { +public: + vector> updateMatrix(vector>& mat) { + int rows = mat.size(); + // if (rows == 0) return mat; + int cols = mat[0].size(); + // Use a safe "infinity" that won't overflow when adding 1 + int INF = numeric_limits::max() - 10000; + // Initialization: Set non-zero cells to inf. + for (int row = 0; row < rows; ++row) { + for (int col = 0; col < cols; ++col) { + if (mat[row][col] != 0) { + mat[row][col] = INF; + } + } + } + + // First pass: Check top and left neighbors + for (int row = 0; row < rows; ++row) { + for (int col = 0; col < cols; ++col) { + if (mat[row][col] == 0) { + continue; + } + + if (row > 0) { + // top (up) + mat[row][col] = min(mat[row][col], mat[row - 1][col] + 1); + } + if (col > 0) { + // left + mat[row][col] = min(mat[row][col], mat[row][col - 1] + 1); + } + } + } + + // Second pass: Check bottom and right neighbors (iterate backwards) + for (int row = rows - 1; row >= 0; --row) { + for (int col = cols - 1; col >= 0; --col) { + if (mat[row][col] == 0) { + continue; + } + + if (row < rows - 1) { + // bottom (down) + mat[row][col] = min(mat[row][col], mat[row + 1][col] + 1); + } + if (col < cols - 1) { + // right + mat[row][col] = min(mat[row][col], mat[row][col + 1] + 1); + } + } + } + return mat; + } +}; diff --git a/542_01_matrix/step3.cpp b/542_01_matrix/step3.cpp new file mode 100644 index 0000000..e69de29