Skip to content

Conversation

@TORUS0818
Copy link
Owner

return left
```
思考ログ:
- 二分探索についてはdiscord上でかなり議論されているので、別途検索をかけてみる
Copy link

Choose a reason for hiding this comment

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

二分探索は何をループの不変条件とするかによっていろいろな書き方があるんですが、不変条件を理解せずに書いている人が多いということです。

理解せずに書くためには書き方を固定すれば、ある程度は書けるようになります。

書く時は自分の書き方を固定してもいいんですが、読むときには、不変条件をどのような形で書いてくるかを指定できないので、どんな書き方がされていても動くのか動かないのかも含めて読めないといけない、というように読むほうがだいぶ難しいという話かと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

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

今回、色々見て回ってとても勉強になりました。

白状すると、二分探索は自分も書き方を固定して使っていました。
具体例をなぞってみたり、なぜそれで上手くいくのかを自分なりに理解した上で覚えていたつもりでしたが、不十分だったと思います。

そのせいで、型から外れたコードを読むのには、少なからず抵抗感があったと自覚してます。
所謂エンジニアリングをしようとしていなかったのだなと反省しました。

Copy link

Choose a reason for hiding this comment

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

まずは「何を探しているのか」「ループごとに今どこまで分かっているのか」「それをどう変数に表現しているのか」というのが意味の部分の話で、あとはループの中で「終了条件」「更新」「必ず終了すること」という形式操作の話くらいです。

だいたい、意味をすっ飛ばして形式だけでやろうとするので、「左」「右」「閉区間」などと唱えたら倒せると思っているんですが、もっと単純に、二分探索の仕事を途中で引き継いだら知りたいことは何なのか「昇順で並んでいる数字の中で一番左の400以上の数を探していて、いくつか確認した。重要な知見として、25番目が288で、51番目が789、その間は開いていない。」くらいですよね。で、この情報を圧縮して変数とコードにするだけです。

Copy link
Owner Author

Choose a reason for hiding this comment

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

ACすることが目的になれば、等号不等号の組み合わせを全探索したり、特定の型を暗記した方がコスパが良い、ということですよね。
エンジニアリングをするという目的で正しく報酬設計ができていれば、こういった意味の部分を蔑ろにすることに自然と抵抗感が生まれる。それがエンジニアリングの専門家集団界隈に入門した、ということなのかなと思っています。

- 探索範囲は単調に縮まり最終的にleft==rightとなりループが停止する
- この時left==rightのインデックスは、Xの下限となっている(X^cの上限でもある)
- パラパラ漫画も作ってみた
- https://docs.google.com/presentation/d/1QABhB8fFeR5nt8x58dpSa3R3cNGzZ4Rcnmj-1cX74qA/edit#slide=id.p

Choose a reason for hiding this comment

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

自分ごとですが、二分探索はとても苦手(現在進行形で苦戦してます)なのでビジュアルの説明と思考の文書化はとても勉強になります🙇

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。
一緒に克服しましょう💪

Copy link

Choose a reason for hiding this comment

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

パラパラ漫画わかりやすかったです。
毎回ではないですが、自分はコード書いた後、エディタ上で下記のように手計算して検算しています。
l 0 ..
r 3 ..
m 1 ..

```python
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
def is_larger_than_target(i: int) -> bool:
Copy link

@Ryotaro25 Ryotaro25 Feb 27, 2025

Choose a reason for hiding this comment

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

今まで気づかなかったのですがPythonにはInner Functionがあるのですね。

Avoid nested functions or classes except when closing over a local value other than self or cls.

https://google.github.io/styleguide/pyguide.html#26-nestedlocalinner-classes-and-functions
Google Guideにも記載ございましたが今回のように使うのですね!

Copy link
Owner Author

Choose a reason for hiding this comment

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

これは、正直に言うと実は私の意識が足りていないです()
もう少し気をつけて使います。

```
思考ログ:
- pythonでは心配はないが、オーバーフローを気にする場合はleft + (right - left) // 2の選択肢も頭においておく
- left <= middle < rightになっているのも大事なポイント

Choose a reason for hiding this comment

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

このポイントですが常にこうなっているということでしょうか?
スライドの最後にL = Rになったのでループを抜けるとあるので、どのタイミングでなっているのか補足があればよりいいのかなと思いました。

自分は現在ここに苦戦していますが。。。🙇

Copy link
Owner Author

Choose a reason for hiding this comment

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

コメントありがとうございます。
middleを計算しているwhileループの中での話ですね。
つまりleft < rightの時、もっというとleft, rightは整数なので、left + 1 <= rightが成り立っている時です。

この時、left = ⌊(left + left + 1) / 2⌋ <= ⌊(left + right) / 2⌋ <= (left + right) / 2 < right
となっているので、left <= middle (=⌊(left + right) / 2⌋) < rightがいえると思います。

@Mike0121
Copy link

Mike0121 commented Mar 2, 2025

良いと思いました。せっかくのなので半開区間以外で書いてみても良いかと思いました。

@TORUS0818
Copy link
Owner Author

ありがとうございます。
閉区間だと以下のような感じですかね。

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        def is_larger_than_target(i: int):
            return target <= nums[i]

        left = 0
        right = len(nums) - 1
        while left <= right:
            middle = (left + right) // 2
            if is_larger_than_target(middle):
                right = middle - 1
            else:
                left = middle + 1
        
        return left

```python
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
def is_larger_than_target(i: int) -> bool:
Copy link

Choose a reason for hiding this comment

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

(間が空いてしまいすみません)
is_larger_thanだと、target < num[i]のように思えてしまう気がします。
chatGPTに聞いたら、is_at_least_targetを提案してくれました。

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.

6 participants