Skip to content
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

First Bad Version #33

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open

First Bad Version #33

wants to merge 9 commits into from

Conversation

rihib
Copy link
Owner

@rihib rihib commented Sep 7, 2024

First Bad Versionを解きました。レビューをお願い致します。

問題:https://leetcode.com/problems/first-bad-version/
言語:Go

すでに解いている方々:
colorbox/leetcode#16
NobukiFukui/Grind75-ProgrammingTraining#25

二分探索についての説明→#27 (comment)

go/binary_search.go Outdated Show resolved Hide resolved
Copy link

@colorbox colorbox left a comment

Choose a reason for hiding this comment

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

良さそうに思います


単なる二分探索だが、少し混乱してしまったため、時間がかかってしまった。二分探索については理解しているつもりだが、考えずにできるレベルにはまだなれてないので少し問題文が変更されていると頭で考える必要が出てきてしまう。

半閉区画の場合、rightは常にtrueの範囲に収まり続け、leftはfalseとtrueの境界にあるとき、mid+1によりtrueに移動するため、left == rightになった瞬間はleftはFirst bad versionであることがわかる。
Copy link

Choose a reason for hiding this comment

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

半開区間と呼ぶことが多いと思います。


単なる二分探索だが、少し混乱してしまったため、時間がかかってしまった。二分探索については理解しているつもりだが、考えずにできるレベルにはまだなれてないので少し問題文が変更されていると頭で考える必要が出てきてしまう。

半閉区画の場合、rightは常にtrueの範囲に収まり続け、leftはfalseとtrueの境界にあるとき、mid+1によりtrueに移動するため、left == rightになった瞬間はleftはFirst bad versionであることがわかる。
Copy link

Choose a reason for hiding this comment

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

「trueの範囲」とはどこからどこまでを表していますか?例えば [false, false, false, true, true, true] という bool 値の配列があったとき、インデックスでいうと何から何までですか?


単なる二分探索だが、少し混乱してしまったため、時間がかかってしまった。二分探索については理解しているつもりだが、考えずにできるレベルにはまだなれてないので少し問題文が変更されていると頭で考える必要が出てきてしまう。

半閉区画の場合、rightは常にtrueの範囲に収まり続け、leftはfalseとtrueの境界にあるとき、mid+1によりtrueに移動するため、left == rightになった瞬間はleftはFirst bad versionであることがわかる。
Copy link

Choose a reason for hiding this comment

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

left は false と true の境界にあるとき、 isBadVersion() が常に true を返すため、 left が mid + 1 になることはないのではないでしょうか?


単なる二分探索だが、少し混乱してしまったため、時間がかかってしまった。二分探索については理解しているつもりだが、考えずにできるレベルにはまだなれてないので少し問題文が変更されていると頭で考える必要が出てきてしまう。

半閉区画の場合、rightは常にtrueの範囲に収まり続け、leftはfalseとtrueの境界にあるとき、mid+1によりtrueに移動するため、left == rightになった瞬間はleftはFirst bad versionであることがわかる。
Copy link

Choose a reason for hiding this comment

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

本来は理由が先に合って、理由に依存して挙動が定まるところを、先にに挙動が定まっていて、その挙動になる理由をこじつけているように感じられました。

「rightは常にtrueの範囲に収まり続け」るのはなぜですか?「leftはfalseとtrueの境界にあるとき、mid+1によりtrueに移動する」のはなぜですか?


半閉区画の場合、rightは常にtrueの範囲に収まり続け、leftはfalseとtrueの境界にあるとき、mid+1によりtrueに移動するため、left == rightになった瞬間はleftはFirst bad versionであることがわかる。
leftがmid+1でtrueに移動したときにrightがleftよりも大きい位置(left < right)にいたとしても、探索は続くが、leftもrightもtrueであればmidも必ずtrueになるため、leftは動かず、rightだけが徐々にleftに近づいていき、最終的にはleftと合流する。
right = midと更新される以上、rightがleftを飛び越えることはなくtrueの範囲にとどまり続け、left == rightになるまで探索は終了しないので、firstBadVersionHalfClosed2のようにleftの代わりにrightを返しても問題ない。
Copy link

Choose a reason for hiding this comment

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

right = midと更新してよい理由は何ですか?

right = midと更新される以上、rightがleftを飛び越えることはなくtrueの範囲にとどまり続け、left == rightになるまで探索は終了しないので、firstBadVersionHalfClosed2のようにleftの代わりにrightを返しても問題ない。
rightがleftを飛び越えることはないのでfirstBadVersionHalfClosed3のように書くこともできる。

閉区画の場合、falseとtrueの境界にあるとき、rightはmid-1によりfalseの方に移動するのに対し、leftはtrueの方に移動するため、right < leftになった瞬間にleftはFirst bad versionであることがわかる。left == rightの場合、trueの範囲内でleft == rightになる場合は問題ないが、falseの範囲内でleft == rightとなる場合は探索結果になってしまうため、right < leftになるまで探索を続ける必要がある。
Copy link

Choose a reason for hiding this comment

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

何がfalseとtrueの境界にあるのですか?

right = midと更新される以上、rightがleftを飛び越えることはなくtrueの範囲にとどまり続け、left == rightになるまで探索は終了しないので、firstBadVersionHalfClosed2のようにleftの代わりにrightを返しても問題ない。
rightがleftを飛び越えることはないのでfirstBadVersionHalfClosed3のように書くこともできる。

閉区画の場合、falseとtrueの境界にあるとき、rightはmid-1によりfalseの方に移動するのに対し、leftはtrueの方に移動するため、right < leftになった瞬間にleftはFirst bad versionであることがわかる。left == rightの場合、trueの範囲内でleft == rightになる場合は問題ないが、falseの範囲内でleft == rightとなる場合は探索結果になってしまうため、right < leftになるまで探索を続ける必要がある。
Copy link

Choose a reason for hiding this comment

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

なぜ「rightはmid-1に」してよいのですか?なぜ right を mid にしてはいけないのですか?

right = midと更新される以上、rightがleftを飛び越えることはなくtrueの範囲にとどまり続け、left == rightになるまで探索は終了しないので、firstBadVersionHalfClosed2のようにleftの代わりにrightを返しても問題ない。
rightがleftを飛び越えることはないのでfirstBadVersionHalfClosed3のように書くこともできる。

閉区画の場合、falseとtrueの境界にあるとき、rightはmid-1によりfalseの方に移動するのに対し、leftはtrueの方に移動するため、right < leftになった瞬間にleftはFirst bad versionであることがわかる。left == rightの場合、trueの範囲内でleft == rightになる場合は問題ないが、falseの範囲内でleft == rightとなる場合は探索結果になってしまうため、right < leftになるまで探索を続ける必要がある。
Copy link

Choose a reason for hiding this comment

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

right < left になることは、区間の定義上あり得ない、もしくはあってはならなのではないでしょうか?

閉区間の場合、 right == left になった瞬間、境界が一意に定まる、もしくは区間内の要素が一つに定まります。

/*
実はこの問題はfirstBadVersion1のようにrightをn+1で初期化しなくてもパスすることができる。

通常の二分探索では半閉区画で書く場合、rightは常に探索済みの範囲に入れておく必要がある。もしもrightをlen(nums)-1で初期化してしまうと、一番最後の要素が探しているtargetの場合に、left < rightによってleftがtargetに到達した瞬間に探索が終了し、targetが存在しなかったという扱いになってしまう。
Copy link

Choose a reason for hiding this comment

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

探索済みという言葉は、二分探索の文脈ではあまり使わないように思います。グラフ理論で、あるノードを探索し終えた場合に使うように思います。別の言葉で表現してみていただけますか?

@rihib
Copy link
Owner Author

rihib commented Sep 9, 2024

if isBadVersion(mid) && (mid == 1 || !isBadVersion(mid-1)) {
return mid
}
if isBadVersion(mid) {
Copy link

Choose a reason for hiding this comment

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

isBadVersion 次第ですが、これだとループ一回で最大3回呼ばれるのが少し気になりますね。
場合によっては10分くらいかかるとても重い処理かもしれません。

Copy link
Owner Author

Choose a reason for hiding this comment

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

確かにその可能性は考えられますね、、ありがとうございます

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants