From 7ea1e44b9bda093892d1df73d13e81b94b2edf4d Mon Sep 17 00:00:00 2001 From: Yota Maeda Date: Tue, 11 Aug 2026 10:41:38 +0900 Subject: [PATCH 1/2] step1,2 --- 62-Unique-Paths/note.md | 69 ++++++++++++++++++++++++++++++++++++++++ 62-Unique-Paths/step1.py | 24 ++++++++++++++ 62-Unique-Paths/step2.py | 23 ++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 62-Unique-Paths/note.md create mode 100644 62-Unique-Paths/step1.py create mode 100644 62-Unique-Paths/step2.py diff --git a/62-Unique-Paths/note.md b/62-Unique-Paths/note.md new file mode 100644 index 0000000..925a42b --- /dev/null +++ b/62-Unique-Paths/note.md @@ -0,0 +1,69 @@ +# 62. Unique Paths + +https://leetcode.com/problems/unique-paths/ + +## step1(まず通す) + +### 方法1 + +数学の問題でよくある設定。m - 1 回の下移動と n - 1 回の右移動を並べるときの並べ方の総数。 +`((m - 1) + (n - 1))!/((m - 1)! (n - 1)!)` + +Python の整数は 64 bit 環境では sys.maxsize が `2 ^ 63 - 1` で、 10 進数で 18 桁ある。ただし、Python ではこれは int の最大値ではなくて、メモリが許せばもっと大きな整数も扱える。`2 ^ 7 - 1` で 1 byte なので、よほどメモリが厳しい環境でないならそこまで気にすることではなさそうか(少なくとも Python を使う用途ではそういう環境は少なそう) + +``` +# 手元の PC で実験 +$ python3 +>>> import sys +>>> sys.maxsize +9223372036854775807 +>>> large = 10 ** 50 +>>> large +100000000000000000000000000000000000000000000000000 +>>> type(large) + +>>> sys.maxsize < large +True +``` + +```python +from math import factorial + + +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + return factorial(m + n - 2) // (factorial(m - 1) * factorial(n - 1)) +``` + +`m = <大きい>, n = 2` みたいに偏っていると、答えの大きさに制限があっても↑の素朴なやり方では計算過程で大きすぎる数が発生することがあるが、その場合でも分母の m - 1, n - 1 の大きい方で分子を割るという事前の式変形により `(m + n - 2) * (m + n - 3) * ... * (n - 1) / (n - 1)!` (m - 1が大きい場合)のように桁数をある程度抑えて計算できる。 + +時間計算量は O(m + n)、空間計算量は O(1) (整数がデカすぎる場合には確証が持てないが、あまり大きくなければこれでいいと思う) + +### 方法2(step1.py) + +↑のような計算ではない解き方だとすると? + +各マス目に対して、そこまでの行き方を左上から順にマス目に書き込んでいけばよい。 +ただし、あるマス目への行き方の数は、`そのマスの左のマスまでの行き方 + そのマスの上のマスまでの行き方` である。 + +このやり方だと、計算過程で出てくる数字が答えより必ず小さくなるので桁数の心配は(そもそも答えが大きすぎるとき以外は)しなくて良さそう。 +ただし、m \* n のグリッド全て(効率化しても対角線より上半分)に対してループを回すので時間計算量と空間計算量は O(m \* n) になる。 +今回は 1 <= m, n <= 100 なのでかかっても数 ms 〜 数十 ms と予想できる。 + +## step2(整形&他の人のコードを読む) + +変数名: + +- way より path の方がいいかも。 +- grid よりは num_paths とかの方が良さそう + - https://github.com/Fuminiton/LeetCode/pull/33#discussion_r2061953239 + - ただ個人的には、各マス目の path の数を num_paths と呼びたいのでその表には別の名前をつけたいかも。でもいい名前が思いつかないし長すぎても読みづらそうなのでこれを採用 +- index_xxx は単に xxx でいいかも + +> 内側が掛け算で構わない、つまり、数字が同一オブジェクトであったとしても代入するときに immutable なので置き換えられるので構わないが、List は問題であるという認識をしておきましょう。 + +https://discord.com/channels/1084280443945353267/1337642831824814192/1363923644635549928 + +step1 で方法2を書いた際、初回でこのミスをしてしまった。 + +## step3(10分以内にさっとかける \* 3回) diff --git a/62-Unique-Paths/step1.py b/62-Unique-Paths/step1.py new file mode 100644 index 0000000..35410df --- /dev/null +++ b/62-Unique-Paths/step1.py @@ -0,0 +1,24 @@ +from collections import deque + + +class Solution: + def uniquePaths(self, num_rows: int, num_columns: int) -> int: + grid = [[0] * num_columns for _ in range(num_rows)] + frontier = deque([(0, 0)]) + seen = set([(0, 0)]) + grid[0][0] = 1 + while frontier: + index_row, index_column = frontier.popleft() + num_ways = grid[index_row][index_column] + if index_row + 1 < num_rows: + grid[index_row + 1][index_column] += num_ways + if (index_row + 1, index_column) not in seen: + frontier.append((index_row + 1, index_column)) + seen.add((index_row + 1, index_column)) + if index_column + 1 < num_columns: + grid[index_row][index_column + 1] += num_ways + if (index_row, index_column + 1) not in seen: + frontier.append((index_row, index_column + 1)) + seen.add((index_row, index_column + 1)) + + return grid[num_rows - 1][num_columns - 1] diff --git a/62-Unique-Paths/step2.py b/62-Unique-Paths/step2.py new file mode 100644 index 0000000..3cd8790 --- /dev/null +++ b/62-Unique-Paths/step2.py @@ -0,0 +1,23 @@ +from collections import deque + + +class Solution: + def uniquePaths(self, num_rows: int, num_columns: int) -> int: + num_paths = [[0] * num_columns for _ in range(num_rows)] + frontier = deque([(0, 0)]) + seen = set([(0, 0)]) + num_paths[0][0] = 1 + while frontier: + row, column = frontier.popleft() + if row + 1 < num_rows: + num_paths[row + 1][column] += num_paths[row][column] + if (row + 1, column) not in seen: + frontier.append((row + 1, column)) + seen.add((row + 1, column)) + if column + 1 < num_columns: + num_paths[row][column + 1] += num_paths[row][column] + if (row, column + 1) not in seen: + frontier.append((row, column + 1)) + seen.add((row, column + 1)) + + return num_paths[num_rows - 1][num_columns - 1] From b52c6376af30b3ce14058250760b35bd19ee1ef4 Mon Sep 17 00:00:00 2001 From: Yota Maeda Date: Tue, 11 Aug 2026 10:41:48 +0900 Subject: [PATCH 2/2] step3 --- 62-Unique-Paths/note.md | 2 ++ 62-Unique-Paths/step3.py | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 62-Unique-Paths/step3.py diff --git a/62-Unique-Paths/note.md b/62-Unique-Paths/note.md index 925a42b..e4f114f 100644 --- a/62-Unique-Paths/note.md +++ b/62-Unique-Paths/note.md @@ -67,3 +67,5 @@ https://discord.com/channels/1084280443945353267/1337642831824814192/13639236446 step1 で方法2を書いた際、初回でこのミスをしてしまった。 ## step3(10分以内にさっとかける \* 3回) + +別オブジェクトを複数回作りたいときは `*` じゃなくて `for` で書く、と決めといた方が間違いづらいかも? diff --git a/62-Unique-Paths/step3.py b/62-Unique-Paths/step3.py new file mode 100644 index 0000000..6e21cbb --- /dev/null +++ b/62-Unique-Paths/step3.py @@ -0,0 +1,23 @@ +from collections import deque + + +class Solution: + def uniquePaths(self, num_rows: int, num_columns: int) -> int: + num_paths = [[0 for _ in range(num_columns)] for _ in range(num_rows)] + frontiers = deque([(0, 0)]) + seen = set([(0, 0)]) + num_paths[0][0] = 1 + while frontiers: + row, column = frontiers.popleft() + if row + 1 < num_rows: + num_paths[row + 1][column] += num_paths[row][column] + if (row + 1, column) not in seen: + frontiers.append((row + 1, column)) + seen.add((row + 1, column)) + if column + 1 < num_columns: + num_paths[row][column + 1] += num_paths[row][column] + if (row, column + 1) not in seen: + frontiers.append((row, column + 1)) + seen.add((row, column + 1)) + + return num_paths[-1][-1]