Skip to content
Open
Show file tree
Hide file tree
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
11 changes: 11 additions & 0 deletions 0035-search-insert-position/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
### step1

findとlower_boundを使ってit != nums.end()のときはそのイテレータ、そうでない場合は配列のサイズを返すようにした。

### step2

他の方のコード(https://github.com/5ky7/arai60/pull/41/changes#diff-0c860cd754249868513e4f9054206317fa33d0f548fc3896ac2b3e11822fd852R19)を見てみると、lower_bound自体を実装していたので自分も実装してみた。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

実装したlower_boundのコードもPRに含めると良いと思います。

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.

すみません、何か勘違いしているかもなのですがstep2に載せたコードがlower_boundの実装のつもりでした。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

lower_boundと振る舞いが違うので、ドキュメントを確認してみると良さそうです。
https://en.cppreference.com/cpp/algorithm/lower_bound

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.

承知しました。ありがとうございます!


### step3

step2を3回通すまで書き直し。
14 changes: 14 additions & 0 deletions 0035-search-insert-position/step1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
auto it = find(nums.begin(), nums.end(), target);
if (it != nums.end()) {
return it - nums.begin();
}
Comment on lines +4 to +7
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

問題文には、

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

とありますが、こちらの計算量はどうなっていますか?

lower_boundを一回呼び出すだけで書けますか?

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.

5ky7さんのPRを参考にlower_bound1回だけで書いてみました。見つからない場合もitがnums.end()になるのでdistanceを取ればちょうどnums.size()と同じになるのでこれだけでよかったです。
https://github.com/5ky7/arai60/pull/41/changes#diff-0c860cd754249868513e4f9054206317fa33d0f548fc3896ac2b3e11822fd852R5

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        auto it = lower_bound(nums.begin(), nums.end(), target);
        int position = distance(nums.begin(), it);
        return position;
    }
};

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.

ぼくの書いた方の計算量ですが、lower_boundの計算量はO(log n)ですがfindの方の計算量はO(n)のようなので問題文の条件をクリアできていなさそうです。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

見つからない場合もitがnums.end()になる

見つからない場合は、いつもそうなりますかね?

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.

見つからない場合というかtarget以上の要素がない場合、つまりtargetがいちばん後ろにくるべきケースではlower_boundでnums.end()が返ると思うのでこれでいいかなと思いました。

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以上の要素が)見つからない」という意味でしたら、それで合っていますね。

auto it2 = lower_bound(nums.begin(), nums.end(), target);
if (it2 != nums.end()) {
return it2 - nums.begin();
}
return nums.size();
}
};
20 changes: 20 additions & 0 deletions 0035-search-insert-position/step2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0;
int right = nums.size();

while (left < right) {
int mid = (left + right) / 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.

オーバーフローを避けるため、

int mid = left + (right - left) / 2;

と書いたほうが良いと思います。

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[mid] == target) {
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 文はなくても動きますか?

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の値が同じになるはずなのでこのif文は必要なかったと思います。一応LeetCodeでも確認したところなくても動きました。

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の値が同じになる

とありますが、ループ終了後には、どこを指していますか?

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.

以下のプレイグラウンドで値を見ながら確認したのですが、nums[mid]がtarget以上の場合はright = midに、nums[mid]がtargetより小さい場合はleft = mid + 1になるので最終的にleftとrightは同じ値になって、target以上の最小のnumのインデックスを指しそうです。
https://leetcode.com/playground/mR6MWyoh

また、下記のコードがあることで最終的な答えは変わらないですがnums[mid] == targetの場合は早期にループを抜けられることもわかりました。

if (nums[mid] == target) {
    return mid;
}

return mid;
}
if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
};
20 changes: 20 additions & 0 deletions 0035-search-insert-position/step3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0;
int right = nums.size();

while (left < right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
return mid;
}
if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
};