Skip to content

35. Search Insert Position#1

Open
takuya576 wants to merge 2 commits into
mainfrom
35-Search-Insert-Position
Open

35. Search Insert Position#1
takuya576 wants to merge 2 commits into
mainfrom
35-Search-Insert-Position

Conversation

@takuya576
Copy link
Copy Markdown
Owner

@takuya576 takuya576 commented Apr 16, 2025

Problem

https://leetcode.com/problems/search-insert-position/description/

  1. Search Insert Position
    Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.

You must write an algorithm with O(log n) runtime complexity.

Example 1:

Input: nums = [1,3,5,6], target = 5
Output: 2
Example 2:

Input: nums = [1,3,5,6], target = 2
Output: 1
Example 3:

Input: nums = [1,3,5,6], target = 7
Output: 4

Approach

2分探索で解きました。

Additional Notes

int searchInsert(int* nums, int numsSize, int target) {
int left = 0, right = numsSize, pivot = 0;
while (left < right) {
pivot = left + (right - left) / 2;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

変数の宣言位置をここにして(pivot->int pivotにして)変数のスコープを狭めた方がいいと思います。
使わない場所でも変数を覚えておかないといけなくなるからです。
また元のコードでも0で初期化する必要はないと思います。
さらに言えば、僕はpivotよりmid(dle)の方が好きです。
pivotであるのは使われ方から分かっているので、それ以外の情報を伝えてほしいからです。

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.

レビューありがとうございます!
変数のスコープを厳密に気にしていませんでした。
そしてmidの方が役割が明確になりますね。

while (left < right) {
pivot = left + (right - left) / 2;
if (target == nums[pivot]) return pivot;
else if (target < nums[pivot]) right = pivot;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

参考までに今はぶら下がりよりブロック{}で囲むほうがスタイルとしては(多分)人気のようです。
フォーマットに関してはc言語だとclang-formatとかを導入してVSCode等で保存時に自動フォーマットを掛けるといいと思います。
philip82148/leetcode-swejp#9 (comment)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ぶら下がりだと
if ...
if ...
else ...
の場合に最後のelseがどっちのifにかかっているのかわからないので避けるべきということですよね。今回はelse ifなのでわかりますが

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.

なるほど、そのような理由なのですね。ありがとうございます!
今後{}を使用しようと思います。

while (left < right) {
pivot = left + (right - left) / 2;
if (target == nums[pivot]) return pivot;
else if (target < nums[pivot]) right = pivot;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

僕は「<ループ毎に変わるのもの>は<変わらないもの>に一致するか」と考えたいので、これらの条件式でtargetを右辺にした方が読みやすいと感じます。

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.

おっしゃることも一理あると考えます。
自分が今回このように書いた理由は、小さいものを左で書いてあげる(>ではなく<を用いる)と、配列のソート順と一致するので、視覚的に分かりやすかったからです。

ただ、一般的には<変わらない閾値>を右に置くというのがセオリーですよね。
ここら辺のベストプラクティスはよくわかっていません。

while (left < right) {
pivot = left + (right - left) / 2;
if (nums[pivot] == target) return pivot;
else if (nums[pivot] > target) right = pivot;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

私は、ここの else 消しますね。上で return しているのでなくても同じです。

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.

確かに消しても問題なさそうですね。
一番上のif文を、下の二つの条件分岐から独立した処理にできるので、思考の処理を減らせる気がします。

配列のメモリは呼び出し元ですでに確保されている。
*numsは配列の先頭の要素を取得、nums[pivot] == *(nums+pivot)。

他の人の回答を見てみると、閉区間、半開区間というか替えがあるらしい。<=と<の違いか。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

二分探索は様々なバリエーションがあります。どのような形でも読めるならば問題ないかと思います。
何を探しているのか、left, right が一体どういう条件を示す変数だと思っているのか、などが拾えるかということです。
結構よく話す内容なのでコメント集にも結構あります。
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.c15qprmvxkc2

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.

コメント集ありがとうございます。
「left,rightの使い方や条件式」から伝わるニュアンスと、自分の実装方針が一致しているかということが大事だと理解できました。
とりあえず、自分がしっくりきている実装方法を一つ確立できました。

int searchInsert(int* nums, int numsSize, int target) {
    int left = 0, right = numsSize - 1;
    while (left <= right) { // 最後にrightとleftが交差して終わる形式。終了条件はright<left。
        int mid = left + (right - left) / 2;
        if (nums[mid] >= target) { // [False,....,False,True,.....,True]の棒を考え、一番左のTrueが答えになる。
            right = mid - 1;
        }
        else {
            left = mid + 1;
        }
    }
    return left;
// 以下が終了状態。leftが答えになる。
// [False,....,False,True,.....,True]
//             right, left
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

はい。

この場合、right とは、そこより右(含まない)がすべて True だと確信している場所、left とは、そこよりも左(含まない)がすべて False だと確信している場所ですね。

left, right の意味付けはコードごとに変わります。どういう順序で読み解くかに留意しながら色々と読んでみましょう。

@oda
Copy link
Copy Markdown

oda commented Apr 18, 2025

PR のタイトルに問題名をいれていただけると助かります。

@takuya576 takuya576 changed the title 35 35. Search Insert Position Apr 18, 2025
Comment on lines +5 to +7
if (nums[pivot] == target) return pivot;
else if (nums[pivot] > target) right = pivot;
else left = pivot + 1;
Copy link
Copy Markdown

@olsen-blue olsen-blue Apr 20, 2025

Choose a reason for hiding this comment

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

条件チェックが3つありますが、1つ目と、2&3つ目は意図が違うので、分離させたい気がします。

if nums[pivot] == target:
    return pivot
    
if nums[pivot] > target:
    right = pivot
else:
    left = pivot + 1

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.

5 participants