Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions 35. Search Insert Position.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
### Step1

- smallerの設定を0にしてしまった。最初の要素がtargetより大きかったら意味ない
- larger_or_equalを返すかsmallerを返すかでindexの計算がこんがらがり頭を使った、苦労した
- smallerに-1を使うのがお行儀が悪いのかはよくわからない???(Atcoderとかのコードだとよくあるけどやばいのかも)

Choose a reason for hiding this comment

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

AtCoderやLeetCodeで良く見るコードがアプリケーションエンジニアとして良いコードではないなという所感があります。

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.

ありがとうございます。あーそれでいうと、過去にAtcoderで自分が書いてたときに思ってたのは、「とりあえずleftのindexを小さくしたいけど、小さくしすぎるとmidが範囲外になるしこれくらいにしとくか」だったので全然わかってなかったですね…

Copy link

Choose a reason for hiding this comment

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

smaller < answer <= larger_or_equal を満たすというのが不変条件ですね。answer は配列の中で同じ値またはそれ以上となる一番左の位置です。知りたいのは分かって書いているかです。

Copy link
Owner Author

@nittoco nittoco Jul 20, 2024

Choose a reason for hiding this comment

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

https://qiita.com/drken/items/97e37dd6143e33a64c8c
なんか過去に読んだ記事で「めぐる式二分探索」と言うのがあって、最初に自分が書いたときもそれで、「rightは常に満たす」「leftは常に満たさない」と言う考えのもと、やってました(この記事の2章)
なのでこれを書いたときには、閉区間というイメージは頭の中になかったです

Copy link

Choose a reason for hiding this comment

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

分かっていて書いているならば別にいいと思うんですが、以下のことを思います。

  1. 分かっていないことは、文字からははっきりしなくても、話をするとかなり簡単に分かります。
  2. 特に分からずに覚えていて、その場で説明ができないとコードを読む能力が低いことを示しています。
  3. 読む力のほうがだいぶ大事です。

https://www.ms.u-tokyo.ac.jp/~yasuyuki/sem.htm

まず,当然書いてあることを理解することが第一歩です.黙って「何々である」とか,"It is easy to see...", "We may assume that...", "It is enough to show..."などと書いてあるのはすべて,なぜなのか徹底的に考えなくてはいけません.「本に書いてあるから」とか「先生がそう言うから」などの理由で,なんとなく分かったような気になるのは絶対にアウトです.そういうところは「なぜですか」と聞かれるに決まっているんですから,どうきかれてもすぐに答えられるように準備をしておく必要があります.

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

class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
larger_or_equal = len(nums)
smaller = -1
while larger_or_equal - smaller > 1:
mid = (larger_or_equal + smaller) // 2
if nums[mid] >= target:
larger_or_equal = mid
else:
smaller = mid
return larger_or_equal
```

## Step2

- 二分探索について。しっくりできていない。[この辺の議論](https://discord.com/channels/1084280443945353267/1192736784354918470/1199018938005213234)を拝見。
- 区間で考えるというアイデアがなかった
- 理解に時間がかかったが 閉開区間の場合
Copy link

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.

検索すると用例が数例ありましたが、ほぼ使わない言葉な気がしますね。

Copy link
Owner Author

Choose a reason for hiding this comment

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

なるほど、そうなんですね、ありがとうございます

- 最後の状態は、「見ている区間がない」状態にする←これを誤解してた
- 閉開区間だったら、left = rightになればOK
- 今見ているもの(mid)は、必ず区間に含まないものとしてどちらかに寄せる
- そうしないと、例えばleft = midの時区間が永遠に減らないかも
- 今回はinsert_leftなので、targetとnums[mid]がイコールであるならばrightを動かして、みている区間を左に寄せる
- left ≤ mid < rightなので
- leftを動かすとき、必ず区間を減らすにはleft = mid + 1
- rightを動かす時、right = midにしても区間は必ず1減る
- mid = (left + right)//2 とすればleft ≤ mid < rightは満たす
- この辺も拝見
- bisectのコード https://github.com/python/cpython/blob/3.12/Lib/bisect.py
- 上の議論と一緒のコードでした
- elifよりelseが良い
- https://github.com/SuperHotDogCat/coding-interview/pull/9/files
- if文、nums[mid] < targetという向きの方がtarget > nums[mid]よりスッキリするかも
- whileの中もright > leftがいいかも
Copy link

Choose a reason for hiding this comment

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

個人的には「右」という変数が左側にあるのは特殊な状況に見えます。
while left < right の方が個人的には混乱少なく読めますね


```python

class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums)
while right > left:
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1
else:
right = mid
return left
```

## Step3

```python

class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums)
while right > left:

Choose a reason for hiding this comment

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

個人的には while left < right:と左側に小さい値が来る方が自然なのですが、右側通行、左側通行みたいに決めの問題なのかもしれないです。とはいえ、コードとしてもleft, rightの準備に並ぶ方が自然な気もしています。

mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1
else:
right = mid
return left
```

## Step4
```python

class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums)
while left < right:
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1
else:
right = mid
return left
```