Skip to content

62. Unique Paths#31

Open
seal-azarashi wants to merge 9 commits intomainfrom
unique-paths
Open

62. Unique Paths#31
seal-azarashi wants to merge 9 commits intomainfrom
unique-paths

Conversation

@seal-azarashi
Copy link
Copy Markdown
Owner

}
```

(💭 夜中にダラダラやってたのでかかった時間は15分を全然超えてますが、意外と出来るものですね。ちゃんと考えを整理しながら解法を段階的にアップデートしていって理解が深まったので、今後も長い間覚えていられそうです。)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

あ、そうそう、この感覚です。

### 数学的の組み合わせの問題として計算

[組み合わせの公式](https://manabitimes.jp/math/1352#4)を使って解く。 Constraints の範囲内でも最大で 198! を扱うことになり、その結果は int の最大値 2^31 - 1 を簡単に超えてしまう (int が扱えるのは 12! まで)。そのため java.math パッケージの BigInteger を使う。
(💭 [Math クラス](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Math.html) や [math パッケージ](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/math/package-summary.html) を眺めてみましたが、意外と factorial や combination 算出用の関数はないんですね)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

ありがとうございます。Java はこれとか Google Guava あたりと一緒に使うイメージ強いですね。
まあ import すればいいので困ることはないですが、他の言語だとサポートしてる関数が標準ライブラリに無いとちょっと不便に感じます。

```

寝る前の暇な時間にコードを眺めていたら、[m - 2][n - 2] のマスが常に2になることから、右端の列と底の行は全部1にしておき、それらを走査対象から外せばイテレーション内の条件分岐を無くせることに気づいた。
ゴールのマスは基本的に正しくは 0 なのだけど、スタート地点の値 (unique path の数) の算出には基本的に影響しないので、見やすさのためにこのような実装にした。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ゴールのマスは基本的に正しくは 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.

@fhiyo
返信が大変遅くなりました。

pathCountCache の各要素にはゴールに到達するまでに必要なステップ数を入れています。ゴールのマスからゴールのマスにたどり着くのに必要なステップ数は0なので、上記のようにコメントしました。
(常に0であることが正しいので「基本的に」は余計ですね)

Comment on lines +27 to +28
this.m = m;
this.n = n;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

n, mをメンバ変数にしてるのはどうしてなんでしょうか?

あと、変更されない変数にはfinal? をつけてimmutableにしたほうが良いかなと思いました

Copy link
Copy Markdown
Owner Author

@seal-azarashi seal-azarashi Oct 28, 2024

Choose a reason for hiding this comment

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

@Yoshiki-Iwasa
返信が大変遅くなりました。

n, mをメンバ変数にしてるのはどうしてなんでしょうか?

引数として渡すと記述が冗長になると感じてこのようにしていました。しかし人によっては違和感ありますよね。

あと、変更されない変数にはfinal? をつけてimmutableにしたほうが良いかなと思いました

他の言語だとそうではないと思うのですが、Java だと慣習的に、クラスメンバー以外にはあまり final をつけない (定数であることを明示しない) ことが多いと感じるのでこのようにしています。そういえば前別のプルリクエストで同じ話をしてました: #27 (comment)

}

private void findUniquePathRecursively(int x, int y) {
if (x == n - 1 && y == m - 1) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ここのn,m は this. になってないのどうしてですか??

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.

@Yoshiki-Iwasa
返信が大変遅くなりました。

書き漏らしていました。一貫性が保てておらずよろしくないので修正しておきました。

class Solution {
public int uniquePaths(int m, int n) {
if (m <= 0 || n <= 0) {
return 0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

マイナスの処理を考えるの、勉強になりました。
個人的にはマイナスが入力されたらエラーを返すと思います。
例えばユーザーがうっかりマイナスを入れちゃったとなったとき(3, 5と入力しようとしてうっかり-3, 5としたときなど)、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.

@nittoco
返信が大変遅くなりました。

ご指摘ありがとうございます。自分も最近、引数が不正だった場合は所定の値を返すのでなく、エラーを返すなりした方が良いのではないかと考えていたところでした。
こちらでした修正のように、今後は所定の exception を throw しようと考えています: #30 (comment)

int[][] pathCountCache = new int[m][n];
for (int y = m - 1; y >= 0; y--) {
for (int x = n - 1; x >= 0; x--) {
boolean inXBorder = x + 1 == n, inYBorder = y + 1 == m;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

こういう書き方ってJavaだとよくあるんでしょうか
前CSライザップで小西さんが言ってたように、=と==が混乱しそうな気がします

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.

@nittoco
返信が大変遅くなりました。

はい、宣言するいくつかの変数の型が同じ場合、このように一行でまとめて宣言するのは普通の書き方だと思います。しかし、仰るとおり === が混在する代入文が同じ行に並んでいるとちょっと煩雑な印象がありますね。
例えば以下のように書いたら見やすくなるでしょうか?

boolean inXBorder = x + 1 == n;
boolean inYBorder = y + 1 == m;

もし === が混在するのが読みづらい原因であれば、nittoco さん的に (言語はなんでもいいので) どのような書き方が好ましいのか参考までに聞かせてもらえると嬉しいです。Java だと、比較演算の結果を変数に代入するのであればこの書き方は多分避けられないはず...?


private void findUniquePathRecursively(int x, int y) {
if (x == 0 && y == 0) {
this.uniquePathCount++;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

自分はここではインクレメント処理せず、初期値を1にすると思います。(下ではそうしてますが)

}

private BigInteger combination(int m, int n) {
return factorial(m).divide(factorial(n).multiply(factorial(m - n)));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

微妙なラインですが、一気に処理されるとちょっと見にくいので分母と分子を別変数にしてもいいかなという気もしました。

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.

@nittoco
返信が大変遅くなりました。

確かにそうですね。次の通り修正しました: 6c753fc

seal_azarashi added 2 commits October 29, 2024 08:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants