Skip to content

63. Unique Paths II #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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
40 changes: 40 additions & 0 deletions 63. Unique Paths II/solution1_1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* ・概要
* 自力解法
* 一つ前のUniquePathと同様の方法を思いついた(動的計画法)。違いは障害物があればpathを0にするくらい。
* 注意点として、スタート地点に障害物があるケースもある。(これで1回とおらなかった。)
*
* ・計算量
* 時間:O(row * col)
* 空間: O(row * col)
*
* ・その他
* ループないで障害物みるからl22でとりあえず1いれてるけど逆にわかりにくいかもしれない
* UniquePathと同じように1次元配列でもできるなという思い(ちょっとわかりにくくはなるが)
*/

public class solution1_1 {
private static final int OBSTACLE = 1;

public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int rowLimit = obstacleGrid.length;
int colLimit = obstacleGrid[0].length;
int[][] numOfPaths = new int[rowLimit][colLimit];
numOfPaths[0][0] = 1;
for (int row = 0; row < rowLimit; row++) {
for (int col = 0; col < colLimit; col++) {
if (obstacleGrid[row][col] == OBSTACLE) {
numOfPaths[row][col] = 0;
continue;
}
if (row != 0) {
numOfPaths[row][col] += numOfPaths[row - 1][col];
}
if (col != 0) {
numOfPaths[row][col] += numOfPaths[row][col - 1];
}
}
}
return numOfPaths[rowLimit - 1][colLimit - 1];
}
}
47 changes: 47 additions & 0 deletions 63. Unique Paths II/solution1_2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* ・概要
* 自力解法
* 練習のため再帰バージョンでも書いてみた。やはりDPのが直感的な気がする。
* 注意点として、ゴール地点に障害物があるケースもある。(これで1回とおらなかった。)
*
* ・計算量
* 時間:O(row * col)
* 空間: O(row * col)
*/

public class solution1_2 {
private static final int OBSTACLE = 1;

public int uniquePathsWithObstacles(int[][] obstacleGrid) {
if (obstacleGrid[0][0] == 1) {
return 0;
}
int rowLimit = obstacleGrid.length;
int colLimit = obstacleGrid[0].length;
int[][] memo = new int[rowLimit][colLimit];
for (int row = 0; row < rowLimit; row++) {
Arrays.fill(memo[row], -1);
}
return countPaths(obstacleGrid, 0, 0, rowLimit - 1, colLimit - 1, memo);
}

private int countPaths(
int[][] obstacleGrid, int row, int col, int goalRow, int goalCol, int[][] memo) {
if (goalRow < row || goalCol < col) {
return 0;
}
if (obstacleGrid[row][col] == OBSTACLE) {
return 0;
}
if (row == goalRow && col == goalCol) {
return 1;
}
if (memo[row][col] != -1) {
return memo[row][col];
}
memo[row][col] =
countPaths(obstacleGrid, row + 1, col, goalRow, goalCol, memo)
+ countPaths(obstacleGrid, row, col + 1, goalRow, goalCol, memo);
return memo[row][col];
}
}
69 changes: 69 additions & 0 deletions 63. Unique Paths II/solution2_1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* https://github.com/irohafternoon/LeetCode/pull/37/files
* numRow→良さそう!!
*
* https://github.com/Fuminiton/LeetCode/pull/34/files
* ネストが少しだけ深いかも(個人的には今回は処理も単純なので許容くらいの感じ)ので、関数化してもいいかも
*
* https://github.com/olsen-blue/Arai60/pull/34/files#r1979987243
* これは大事。実務ではここらへんはコミュニケーションすぐあ、信用できないので念の為バリデーションをする方針はよくとられがちなイメージ(僕の経験上)
*
* https://github.com/olsen-blue/Arai60/pull/34/files#r1979998266
* たしかに、row,colくらいならr,cでも悪くないかなという気がしてきた。
* https://google.github.io/styleguide/javaguide.html#s4.8.2-variable-declarations
* ガイドをみてもループないならOKそう
* 入力配列のバリデーションもやはり意識すべし
* エッジ初期化を先にする手法。コード量は増えるがやってることは少し、明示的な気もするなくらいな気持ち。
*
Copy link

Choose a reason for hiding this comment

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

いいんじゃないでしょうか。1次元でやっている人も見ましたね。

*/
public class solution2_1 {
static int OBSTACLE = 1;

public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int numOfRow = obstacleGrid.length;
if (numOfRow == 0) {
return 0;
}
int numOfCol = obstacleGrid[0].length;
if (numOfCol == 0) {
return 0;
}
if (obstacleGrid[0][0] == OBSTACLE || obstacleGrid[numOfRow - 1][numOfCol - 1] == OBSTACLE) {
Copy link

Choose a reason for hiding this comment

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

自分も無駄な計算が生じないようにこうやって弾きたくなります。
01
11
から始まるような場合もグリッドが大きいと最適化したくなるかもしれませんね。

return 0;
}
int[][] numOfPaths = new int[numOfRow][numOfCol];
numOfPaths[0][0] = 1;
for (int c = 0; c < numOfCol; c++) {
if (obstacleGrid[0][c] == OBSTACLE) {
numOfPaths[0][c] = 0;
break;
} else {
numOfPaths[0][c] = 1;
}
}
for (int r = 0; r < numOfRow; r++) {
if (obstacleGrid[r][0] == OBSTACLE) {
numOfPaths[r][0] = 0;
break;
} else {
numOfPaths[r][0] = 1;
}
}

for (int r = 1; r < numOfRow; r++) {
for (int c = 1; c < numOfCol; c++) {
if (obstacleGrid[r][c] == OBSTACLE) {
numOfPaths[r][c] = 0;
continue;
}
if (r != 0) {
Copy link

Choose a reason for hiding this comment

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

ループが r=1 から始まっているので不要だと思います。
反対に、この条件を入れるならr, cが0の場合を処理しているループを二重ループの方に統合できますね。r, cが両方0の場合の処理も入れる必要がありますが

numOfPaths[r][c] += numOfPaths[r - 1][c];
}
if (c != 0) {
numOfPaths[r][c] += numOfPaths[r][c - 1];
}
}
}
return numOfPaths[numOfRow - 1][numOfCol - 1];
}
}