Skip to content

112. Path Sum#24

Open
hroc135 wants to merge 3 commits intomainfrom
112PathSum
Open

112. Path Sum#24
hroc135 wants to merge 3 commits intomainfrom
112PathSum

Conversation

@hroc135
Copy link
Copy Markdown
Owner

@hroc135 hroc135 commented Oct 18, 2024

Comment on lines +169 to +171
leftFound := hasPathSum(root.Left, remaining)
rightFound := hasPathSum(root.Right, remaining)
return leftFound || rightFound
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

	return hasPathSum(root.Left, remaining) || hasPathSum(root.Right, remaining)

とした方が短絡評価が起こるので良さそうです。

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.

短絡評価という言葉を知らなかったです。ブール演算子による計算において、第一引数を評価して結果が定まらない場合のみ第二引数を評価するということですね
ありがとうございます

}

func hasPathSum(root *TreeNode, targetSum int) bool {
stack := make([]nodePathSum, 0, 10000)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

どうしてcapacityを指定しましたか?

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.

スライスに入りうる最大要素数を知っている場合にはキャパシティを指定した方が再割り当てが起きずパフォーマンスが向上することが多いので、キャパシティを指定しました

ただ、今見返したら最大要素数は1e4ではなく5e3でした。木の要素数が最大で5e3で、木が右側への直線の時に、各ノードがnilノードも合わせて二つの子ノードを持ち、両方スタックに積まれるので 2 * 5e3 = 1e4個スタックに入ることになるかと思ったのですが、popされることを忘れていたので、5e3でした

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

capacityを大きく割り当てるとインプットのサイズが小さい時に悪影響がありそうでしょうか?

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.

はい、5e3個分のキャパシティを割り当てたのに実際の要素数が0だと5e3だけ無駄にメモリ使用量として数えられてしまうことになります。
つまり、キャパシティを5e3に設定すると、

  1. 木の要素数が大きいと、メモリ領域の再割り当てを避けられるので実行時間的に良い
  2. 木の要素数が小さいと、無駄にメモリ領域を割り当てることになってしまい、メモリ使用量的に良くない
    というトレードオフがあり、今回は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.

なるほど、まず、本当にそこの速度が大事なのかと全体が何秒速くなっているかを考えるか試してみるかして下さい。
速度が大事で速くしたいといっても、一般にボトルネックでないところを速くしてもそれほど効果はありません。

次、メモリー使用量です、ポインターと int なので環境によりますがサイズは 8 + 4 バイトですか? たぶん、パディングされて16バイトでしょうか。それで、1万とっているので、これ、160キロバイトですかね。環境にもよりますがL1キャッシュのサイズを超えていそうです。ランダムアクセスではないのでかもしれませんが遅くなるかも。

最後に、10000という数がコードに現れると疑問が湧きます。「わざわざデフォルト引数から動かさなくてはいけなかったはずだ。どれくらいのコストを払ってこの数字を決めたのか、どれくらい動かしてはいけないのか、たとえば、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.

メモリー確保などに分解して時間を測って、上の表と比較をすると面白いかもしれません。

「精進」は、2010年前後の JOI 勢がいい始めた気がしています。
もともとのプログラミングコンテストや競技プログラミング同好会では聞かなかった気がしますね。
だいたいこれが競技プログラミング同好会の次の次あたりの世代です。

https://qnighy.github.io/informatics-olympiad/joi-glossary.html#:~:text=%E4%B8%80%E7%A8%AE%E3%81%A7%E3%81%82%E3%82%8B%E3%80%82-,%E7%B2%BE%E9%80%B2,-(%E3%81%97%E3%82%87%E3%81%86%E3%81%98%E3%82%93)

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://touyoubuntu.hatenablog.com/entry/20111216/1323992210
精進について2011年の言及を発見しました。
やはり、JOI (2010-2011) の合宿から広まったということで正しいようです。

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.

なんと、考察記事まであるとは。想像以上に界隈で使われていたようですね。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2005年に ICPC の世界出場メンバーが私に向かって精進と書いているのを見つけました。
実は精進という言葉もっと歴史があるのかしら。

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.

その方が「精進」を根付かせた説はありますかね

#### 2c スタックDFS nilノードもスタックに入れる
- スタックDFSでnilノードもスタックに入れる方法。
これにより、条件分岐が少なくなる。
一方、nilノードもスタックに入れるので、最悪の場合、一本のパスだけからなる二分木だとスタックの要素数が木の要素数の倍になってしまう
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

Choose a reason for hiding this comment

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

速度は実験してみるといいと思います。分岐予測の失敗もそこそこコストがかかります。

そもそも論として、速度にこだわる必要があるかは状況次第です。
Python は C/C++ などから50倍くらい遅いので、それを使っている時点でそこの速度が問題でない可能性が高いです。

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
ここの文間違っていました!
#24 (comment) でも記載しましたが、stackからは毎ループ1つpopされるので、常に2-1=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.

勝手に自分で文を「スタックに入った通算要素数」で解釈してしまってました。確かに要素数というと瞬間要素数を指すのが一般的かもしれないですね、ありがとうございます。

分岐予測は確かに頭になかったです。言語間の比較や、分岐予測も含めてコストを考えてみます。

Comment on lines +92 to +94
if found {
return true
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

下のliquoriceさんのレビューでもありますが、短絡評価になるよう実装すればここの複雑なことをしなくても早めにreturnできますね。

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.

4 participants