Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions 63/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 63. Unique Paths II

- sol1.py: dpでかいた
- sol2.py: 初期化方法と変数名を改善

https://github.com/olsen-blue/Arai60/pull/34#pullrequestreview-2636297197
> コンパイラ言語ではif文(機械語にしたときの分岐命令)って(分岐予測に失敗するとパイプラインの工程を最初からやり直さないといけないので)他の命令より時間がかかるんです
> なので、可読性の面でも速度の面でもこのfor文は分けた方がよりよいですね
>でも、Pythonはインタプリタ言語(そもそもプログラムの解釈・実行に大量に分岐命令が使われてると思う)なので速度の観点では気にするような速度差は生まれないかもしれません

これは勉強になった。
つまり、CやRustなどんコンパイラ言語では、分岐予測に失敗するとオーバーヘッドが発生するので、for文内のif文はなるべく分けた方が良い。
つまり、事前に決まっている分岐(0行目or0列目など)はfor文の外で行った方が良い。
しかし、Pythonの場合はこれを気にする必要はなさそう。


https://github.com/Fuminiton/LeetCode/pull/34#discussion_r2052772608
> [0][0]にアクセスする前に一応チェックしてもいいかもしれませんね。問題文に制約があるにせよ。

これはたまたまできていた

https://algo-method.com/descriptions/78
配るDPともらうDP
配るDPで書いた:sol3.py
29 changes: 29 additions & 0 deletions 63/sol1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
if not obstacleGrid or not obstacleGrid[0]:
return 0

num_rows, num_cols = len(obstacleGrid), len(obstacleGrid[0])

EMPTY = 0

if obstacleGrid[0][0] != EMPTY:
return 0

unique_paths_per_row = [1] + [0] * (num_cols - 1)

col = 1
while col < num_cols and obstacleGrid[0][col] == EMPTY:
unique_paths_per_row[col] = 1
col += 1

for row in range(1, num_rows):
for col in range(0, num_cols):
if obstacleGrid[row][col] != EMPTY:
unique_paths_per_row[col] = 0
continue
if col == 0:
continue
unique_paths_per_row[col] += unique_paths_per_row[col - 1]

return unique_paths_per_row[-1]
19 changes: 19 additions & 0 deletions 63/sol2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
if not obstacleGrid or not obstacleGrid[0]:
return 0

n_row, n_col = len(obstacleGrid), len(obstacleGrid[0])

unique_paths_per_row = [0] * n_col
unique_paths_per_row[0] = 0 if obstacleGrid[0][0] else 1

for row in range(n_row):
for col in range(n_col):
if obstacleGrid[row][col]:
unique_paths_per_row[col] = 0
continue
elif col > 0:
unique_paths_per_row[col] += unique_paths_per_row[col - 1]

return unique_paths_per_row[-1]
30 changes: 30 additions & 0 deletions 63/sol3.py
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

メモリ使用量が増えるのをやむなしで、2次元配列(フルのテーブル)で書いたほうが、配るDPは分かりやすいと思いました。また、最終行は配らなくていいとか、障害物があったら0に潰して配れない(こっちは最終行も処理する必要がある)、など制御が比較的面倒で、配るよりも貰う方が書きやすそうに感じました。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

「配るよりも貰う方が書きやすそう」は同意します。
配るDPでも直前の二行を保持しておけば良いので、一次元にする必要はないのではないかとと個人的には思います。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

配るDPでも直前の二行を保持しておけば良いので、一次元にする必要はない

そのとおりで、処理的には問題ないのですが、書きやすさ(バグの埋め込みやすさ)・読みやすさの観点からは、2次元配列の方が優れていそうだな、と感じました。unique_paths_per_rowunique_paths_next_row の入れ替え(更新)の必要がなかったり、最終行は入れ替えしないという条件が理解しやすかったりしそうです。

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
if not obstacleGrid or not obstacleGrid[0]:
return 0

n_row, n_col = len(obstacleGrid), len(obstacleGrid[0])

unique_paths_per_row = [0] * n_col
unique_paths_per_row[0] = 0 if obstacleGrid[0][0] else 1

for row in range(n_row):
unique_paths_next_row = [0] * n_col
for col in range(n_col):
if obstacleGrid[row][col]:
unique_paths_per_row[col] = 0
continue

paths = unique_paths_per_row[col]
if paths == 0:
continue

if col + 1 < n_col:
unique_paths_per_row[col + 1] += paths
if row + 1 < n_row:
unique_paths_next_row[col] += paths

if row + 1 < n_row:
unique_paths_per_row = unique_paths_next_row

return unique_paths_per_row[-1]