From 1af0458d0f53d3a3501b597c3deeb2bd6004c1b7 Mon Sep 17 00:00:00 2001 From: Kazuki Kijima Date: Mon, 9 Mar 2026 21:45:37 -0700 Subject: [PATCH 01/10] LeetCode 62: Add step 1 solution --- leetcode/62/step1.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 leetcode/62/step1.py diff --git a/leetcode/62/step1.py b/leetcode/62/step1.py new file mode 100644 index 0000000..83e4a1c --- /dev/null +++ b/leetcode/62/step1.py @@ -0,0 +1,15 @@ +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + path_count = [[0] * n for _ in range(m)] + for i in range(m): + path_count[i][0] = 1 + for i in range(n): + path_count[0][i] = 1 + + for row in range(1, m): + for col in range(1, n): + path_count[row][col] = ( + path_count[row - 1][col] + path_count[row][col - 1] + ) + + return path_count[m - 1][n - 1] From ea9e55cadc19736563995d760fba2c4d043a6c8e Mon Sep 17 00:00:00 2001 From: Kazuki Kijima Date: Mon, 9 Mar 2026 22:53:35 -0700 Subject: [PATCH 02/10] LeetCode 62: Reduce memory usage --- leetcode/62/memo.md | 3 +++ leetcode/62/step1_two_rows.py | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 leetcode/62/memo.md create mode 100644 leetcode/62/step1_two_rows.py diff --git a/leetcode/62/memo.md b/leetcode/62/memo.md new file mode 100644 index 0000000..0ee4356 --- /dev/null +++ b/leetcode/62/memo.md @@ -0,0 +1,3 @@ +# Step 1 + +典型的なDPの問題 diff --git a/leetcode/62/step1_two_rows.py b/leetcode/62/step1_two_rows.py new file mode 100644 index 0000000..27a0b99 --- /dev/null +++ b/leetcode/62/step1_two_rows.py @@ -0,0 +1,15 @@ +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + prev_row = [1] * n + for row in range(1, m): + curr_row = [0] * n + for col in range(n): + if col == 0: + curr_row[col] = 1 + continue + + curr_row[col] = curr_row[col - 1] + prev_row[col] + + prev_row = curr_row + + return prev_row[-1] From 57159846bfffd974ae572cc72c7ed8c65eb4c4f3 Mon Sep 17 00:00:00 2001 From: Kazuki Kijima Date: Mon, 9 Mar 2026 23:07:59 -0700 Subject: [PATCH 03/10] LeetCode 62: Add step 1 time/space complexity analysis --- leetcode/62/memo.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/leetcode/62/memo.md b/leetcode/62/memo.md index 0ee4356..45febba 100644 --- a/leetcode/62/memo.md +++ b/leetcode/62/memo.md @@ -1,3 +1,9 @@ # Step 1 典型的なDPの問題 + +素直に `m * n` の grid を用意して埋めていけばいい。(`step1.py`) +時間計算量: O(mn), 空間計算量: O(mn) + +`m * n` 全ての結果を持つ必要はなくて、次のrowを埋めるのに必要なのは直前のrowだけなので、2つのrowだけ持てばいい。(`step1_two_rows.py`) +時間計算量は O(mn) で変わらずだが、空間計算量は O(m) で済む。m と n を入れ替えても結果は変わらないので、nの方が小さいことがわかっている場合は先にm と n を入れ替えたら良さそう。 From e92e59cbc52d625c23141f26944ec3d17698011e Mon Sep 17 00:00:00 2001 From: Kazuki Kijima Date: Mon, 9 Mar 2026 23:36:45 -0700 Subject: [PATCH 04/10] LeetCode 62: Add step 2 combination --- leetcode/62/memo.md | 13 +++++++++++++ leetcode/62/step2_combination.py | 11 +++++++++++ 2 files changed, 24 insertions(+) create mode 100644 leetcode/62/step2_combination.py diff --git a/leetcode/62/memo.md b/leetcode/62/memo.md index 45febba..bfb974a 100644 --- a/leetcode/62/memo.md +++ b/leetcode/62/memo.md @@ -7,3 +7,16 @@ `m * n` 全ての結果を持つ必要はなくて、次のrowを埋めるのに必要なのは直前のrowだけなので、2つのrowだけ持てばいい。(`step1_two_rows.py`) 時間計算量は O(mn) で変わらずだが、空間計算量は O(m) で済む。m と n を入れ替えても結果は変わらないので、nの方が小さいことがわかっている場合は先にm と n を入れ替えたら良さそう。 + +# Step 2 + +[dxxsxsxkxさんのPR](https://github.com/dxxsxsxkx/leetcode/pull/33/changes#diff-e425ab53cee19df2ef6995889ba4e527fc0e29e480a6787c15119f2da066511c) + +動的計画法だと初めからわかっていたのでそれに飛びついてしまったが、いつかの数学でやった組み合わせの問題であることも連想できた方が良かったな。 + +総移動距離が (m + n - 2) で、そこから m - 1 (か n - 1) を置く場所を選ぶから (m + n - 2)C(m - 1)。 +例えばm = 3, n = 4 だったら 2個のdownと3個のright を組み合わせるから5箇所から2個のdown を選んで (例えば DRDRR) 5C2 = 10。 + +書いてみた -> `step2_combination.py` Pythonだから桁を気にせず掛け合わせてしまっている。 + +時間計算量: O(min(m, n)), 空間計算量: O(1) diff --git a/leetcode/62/step2_combination.py b/leetcode/62/step2_combination.py new file mode 100644 index 0000000..4d97267 --- /dev/null +++ b/leetcode/62/step2_combination.py @@ -0,0 +1,11 @@ +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + m, n = max(m, n), min(m, n) + + numerator = 1 + denominator = 1 + for i in range(n - 1): + numerator *= m + n - 2 - i + denominator *= n - 1 - i + + return numerator // denominator From fd98c3272ea59e27b2cea33badef26d95ae559de Mon Sep 17 00:00:00 2001 From: Kazuki Kijima Date: Mon, 9 Mar 2026 23:39:17 -0700 Subject: [PATCH 05/10] LeetCode 62: Add step 2 solution with math.comb --- leetcode/62/memo.md | 2 ++ leetcode/62/step2_math_combo.py | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100644 leetcode/62/step2_math_combo.py diff --git a/leetcode/62/memo.md b/leetcode/62/memo.md index bfb974a..c64ff46 100644 --- a/leetcode/62/memo.md +++ b/leetcode/62/memo.md @@ -20,3 +20,5 @@ 書いてみた -> `step2_combination.py` Pythonだから桁を気にせず掛け合わせてしまっている。 時間計算量: O(min(m, n)), 空間計算量: O(1) + +そもそもPythonには [math.comb](https://docs.python.org/3/library/math.html#math.comb) という関数があるらしいのでそれを使えば簡単か。-> `step2_math_comb.py` diff --git a/leetcode/62/step2_math_combo.py b/leetcode/62/step2_math_combo.py new file mode 100644 index 0000000..ec1571a --- /dev/null +++ b/leetcode/62/step2_math_combo.py @@ -0,0 +1,6 @@ +import math + + +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + return math.comb(m + n - 2, m - 1) From 23b9ac7ad41500fbe2006b085844a420878045b6 Mon Sep 17 00:00:00 2001 From: Kazuki Kijima Date: Mon, 9 Mar 2026 23:44:42 -0700 Subject: [PATCH 06/10] LeetCode 62: Add memoization solution --- leetcode/62/memo.md | 6 ++++++ leetcode/62/step2_memoization.py | 9 +++++++++ 2 files changed, 15 insertions(+) create mode 100644 leetcode/62/step2_memoization.py diff --git a/leetcode/62/memo.md b/leetcode/62/memo.md index c64ff46..1eb3d71 100644 --- a/leetcode/62/memo.md +++ b/leetcode/62/memo.md @@ -10,6 +10,8 @@ # Step 2 +## 組み合わせ + [dxxsxsxkxさんのPR](https://github.com/dxxsxsxkx/leetcode/pull/33/changes#diff-e425ab53cee19df2ef6995889ba4e527fc0e29e480a6787c15119f2da066511c) 動的計画法だと初めからわかっていたのでそれに飛びついてしまったが、いつかの数学でやった組み合わせの問題であることも連想できた方が良かったな。 @@ -22,3 +24,7 @@ 時間計算量: O(min(m, n)), 空間計算量: O(1) そもそもPythonには [math.comb](https://docs.python.org/3/library/math.html#math.comb) という関数があるらしいのでそれを使えば簡単か。-> `step2_math_comb.py` + +## Memoization + +そういえば、Memoizationでもいけそうだな -> `step2_memoization.py` diff --git a/leetcode/62/step2_memoization.py b/leetcode/62/step2_memoization.py new file mode 100644 index 0000000..1a8c4df --- /dev/null +++ b/leetcode/62/step2_memoization.py @@ -0,0 +1,9 @@ +import functools + + +class Solution: + @functools.cache + def uniquePaths(self, m: int, n: int) -> int: + if m == 1 or n == 1: + return 1 + return self.uniquePaths(m - 1, n) + self.uniquePaths(m, n - 1) From e06ef0f95cfec59f6782fb2c7fcbaa13c9dc11f9 Mon Sep 17 00:00:00 2001 From: Kazuki Kijima Date: Mon, 9 Mar 2026 23:51:34 -0700 Subject: [PATCH 07/10] LeetCode 62: Add one row DP solution --- leetcode/62/memo.md | 6 ++++++ leetcode/62/step2_one_row_dp.py | 7 +++++++ 2 files changed, 13 insertions(+) create mode 100644 leetcode/62/step2_one_row_dp.py diff --git a/leetcode/62/memo.md b/leetcode/62/memo.md index 1eb3d71..72bd7ed 100644 --- a/leetcode/62/memo.md +++ b/leetcode/62/memo.md @@ -28,3 +28,9 @@ ## Memoization そういえば、Memoizationでもいけそうだな -> `step2_memoization.py` + +## 1 列 DP + +[naoto-iwaseさんのPR](https://github.com/naoto-iwase/leetcode/pull/38/changes#diff-8a6ff63343e74cc80d732f8899ddf515ccf1d52a91f0f73f0d8b022fd23400cbR44) + +保持するのが一列だけでも良いのか、いや確かに言われてみれば。-> `step2_one_row_dp.py` diff --git a/leetcode/62/step2_one_row_dp.py b/leetcode/62/step2_one_row_dp.py new file mode 100644 index 0000000..80b7727 --- /dev/null +++ b/leetcode/62/step2_one_row_dp.py @@ -0,0 +1,7 @@ +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + count = [1] * n + for _ in range(1, m): + for col in range(1, n): + count[col] += count[col - 1] + return count[-1] From 2f2f7cda4d723abc7c7f73dcedf825b8a732bfa2 Mon Sep 17 00:00:00 2001 From: Kazuki Kijima Date: Tue, 10 Mar 2026 00:25:45 -0700 Subject: [PATCH 08/10] LeetCode 62: Add step 2/3 simple DP solution --- leetcode/62/step2.py | 12 ++++++++++++ leetcode/62/step3.py | 12 ++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 leetcode/62/step2.py create mode 100644 leetcode/62/step3.py diff --git a/leetcode/62/step2.py b/leetcode/62/step2.py new file mode 100644 index 0000000..a1e0c87 --- /dev/null +++ b/leetcode/62/step2.py @@ -0,0 +1,12 @@ +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + count = [[0] * n for _ in range(m)] + for row in range(m): + for col in range(n): + if row == 0 or col == 0: + count[row][col] = 1 + continue + + count[row][col] = count[row - 1][col] + count[row][col - 1] + + return count[m - 1][n - 1] diff --git a/leetcode/62/step3.py b/leetcode/62/step3.py new file mode 100644 index 0000000..a1e0c87 --- /dev/null +++ b/leetcode/62/step3.py @@ -0,0 +1,12 @@ +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + count = [[0] * n for _ in range(m)] + for row in range(m): + for col in range(n): + if row == 0 or col == 0: + count[row][col] = 1 + continue + + count[row][col] = count[row - 1][col] + count[row][col - 1] + + return count[m - 1][n - 1] From 29fcf77912a5fdba859ac0560b53153cd4f7cbbd Mon Sep 17 00:00:00 2001 From: Kazuki Kijima Date: Tue, 10 Mar 2026 00:35:57 -0700 Subject: [PATCH 09/10] LeetCode 62: Add time/space complexity analysis with real values --- leetcode/62/memo.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/leetcode/62/memo.md b/leetcode/62/memo.md index 72bd7ed..6dc7b5b 100644 --- a/leetcode/62/memo.md +++ b/leetcode/62/memo.md @@ -8,6 +8,11 @@ `m * n` 全ての結果を持つ必要はなくて、次のrowを埋めるのに必要なのは直前のrowだけなので、2つのrowだけ持てばいい。(`step1_two_rows.py`) 時間計算量は O(mn) で変わらずだが、空間計算量は O(m) で済む。m と n を入れ替えても結果は変わらないので、nの方が小さいことがわかっている場合は先にm と n を入れ替えたら良さそう。 +> `1 <= m, n <= 100` + +なので、最悪でも `10^4` くらいのオーダーの処理しか必要ないので、実行時間は問題ないだろう。 +Pythonのintのメモリ使用量は後で調べるとして、Cだったら int が多くの場合 32 bits = 4 bytes で、それが `10^4` 個あると `4 * 10^4 bytes ~= 39KB`か (vectorのオーバーヘッドを無視して)。 + # Step 2 ## 組み合わせ @@ -34,3 +39,7 @@ [naoto-iwaseさんのPR](https://github.com/naoto-iwase/leetcode/pull/38/changes#diff-8a6ff63343e74cc80d732f8899ddf515ccf1d52a91f0f73f0d8b022fd23400cbR44) 保持するのが一列だけでも良いのか、いや確かに言われてみれば。-> `step2_one_row_dp.py` + +# Step 3 + +特に工夫もないTabulationが一番わかりやすい。 From 5f5766dca7307add69f460575a68bda331296135 Mon Sep 17 00:00:00 2001 From: Kazuki Kijima Date: Tue, 10 Mar 2026 08:11:58 -0700 Subject: [PATCH 10/10] LeetCode 62: Check Python int bytes size --- leetcode/62/memo.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/leetcode/62/memo.md b/leetcode/62/memo.md index 6dc7b5b..f6590fd 100644 --- a/leetcode/62/memo.md +++ b/leetcode/62/memo.md @@ -13,6 +13,41 @@ なので、最悪でも `10^4` くらいのオーダーの処理しか必要ないので、実行時間は問題ないだろう。 Pythonのintのメモリ使用量は後で調べるとして、Cだったら int が多くの場合 32 bits = 4 bytes で、それが `10^4` 個あると `4 * 10^4 bytes ~= 39KB`か (vectorのオーバーヘッドを無視して)。 +具体的な実装はまだ詳しくみれていないが、[Python Maven - Size of integer in Python](https://python.code-maven.com/size-of-integer-in-python) を見ると + +```python +import sys + +for i in range(0, 200, 10): + num = 2**i + print(sys.getsizeof(num), num) + +""" +28 1 +28 1024 +28 1048576 +32 1073741824 +32 1099511627776 +32 1125899906842624 +36 1152921504606846976 +36 1180591620717411303424 +36 1208925819614629174706176 +40 1237940039285380274899124224 +40 1267650600228229401496703205376 +40 1298074214633706907132624082305024 +44 1329227995784915872903807060280344576 +44 1361129467683753853853498429727072845824 +44 1393796574908163946345982392040522594123776 +48 1427247692705959881058285969449495136382746624 +48 1461501637330902918203684832716283019655932542976 +48 1496577676626844588240573268701473812127674924007424 +52 1532495540865888858358347027150309183618739122183602176 +52 1569275433846670190958947355801916604025588861116008628224 +""" +``` + +のようなテストが提示されていて、`1` のような小さい数字でも 28 bytes も使用していることがわかった。 + # Step 2 ## 組み合わせ