Conversation
| while left <= right: | ||
| middle = (left + right) // 2 | ||
| if target <= nums[middle]: | ||
| right = middle - 1 |
There was a problem hiding this comment.
right = middleのほうが個人的には良いと思いました。(target <= nums[middle]であってもmiddleが答えになりえるので)
これだと最後left == right + 1の状況になってleftが返されて終わりという感じになると思いますが、少しわかりにくいと感じました(捉え方によるのかもしれません)
| ```python | ||
| class Solution: | ||
| def searchInsert(self, nums: List[int], target: int) -> int: | ||
| def binary_search(begin: int, end: int) -> int: |
There was a problem hiding this comment.
関数名には、どのような値が返ってくるかを表す名前を付けたほうが、ソースコードが理解しやすくなると思います。
| return left | ||
| ``` | ||
|
|
||
| - 開区間 |
There was a problem hiding this comment.
個人的には、開区間か閉区間の選択ではなく、leftとrightがそれぞれ何を満たして欲しいものとして考えるかから始めることが重要な気がしています。
以下の方式であれば、
「rightは必ずtarget以上で、leftは必ずtarget未満である」というのが前提なので、停止するのはleftとrightが隣り合う時であり、targetが全要素より大きい/小さいを満たす初期値は〜、更新の仕方は〜と考えていくイメージです。
There was a problem hiding this comment.
その前提を決めることが開区間か閉区間かを決めることに相当するような気がしているのですが違うのでしょうか?
ちなみにこのやり方は、以前SWE協会の勉強会における模擬面接で「この二分探索を開区間で書けますか?」というような質疑をしていたのを思い出してのことです。
There was a problem hiding this comment.
背景として、「開区間」「閉区間」という単語の意味を分からないまま、二分探索のアルゴリズムの理解に使用しようとしている方がいらっしゃいました。単語の意味を理解しないまま理解を進めようとしたため、二分探索自体も理解できていませんでした。そのため、 SWE 協会の過去のレビューに置いては、開区間・閉区間という単語を使わず、以下を明示的に理解することから始めるという流れができたように思います。
- left より左側にある要素が満たす条件は何か?
- left の位置にある要素が満たす条件は何か?
- left より右側にある要素が満たす条件は何か?
- right より左側にある要素が満たす条件は何か?
- right の位置にあるにある要素が満たす条件は何か?
- right より右側にある要素が満たす条件は何か?
- 二分探索の開始時の left の位置はどこか?
- 二分探索の開始時の right の位置はどこか?
- ループの不変条件は何か?
- ループが終了する条件は何か?
- middle はどのように計算するか?
- middle の位置の要素がどのような条件の時に、 left を変更するか?
- left を変更する場合、何に変更するか?また、なぜその変更は妥当なのか?
- middle の位置の要素がどのような条件の時に、 right を変更するか?
- right を変更する場合、何に変更するか?また、なぜその変更は妥当なのか?
- middle の位置の要素が目的の要素だった場合、 early return するか?
- 無限ループにならないか?
- 最終的に返す要素、または位置は何か?
ご自身が書かれたコードについて、上記を一通り答えられるか確認することをお勧めいたします。また、他の参加者の過去の回答を読み、上記について一通り答えられるかどうか確認すると、理解が深まると思います。
二分探索は、自分なりの書き方で書くことができ、かつ、他の方が書かれた書き方を読んで理解できることが望ましいと思います。
問題文:https://leetcode.com/problems/search-insert-position/description/