-
Notifications
You must be signed in to change notification settings - Fork 0
153. Find Minimum in Rotated Sorted Array #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| ## 何も見ずに解いてみる | ||
|
|
||
| ```cpp | ||
| class Solution { | ||
| public: | ||
| int findMin(vector<int>& nums) { | ||
| int left = 0; | ||
| int right = nums.size() - 1; | ||
| while (left < right) { | ||
| int mid = left + (right - left) / 2; | ||
| if (nums[mid] > nums[right]) left = mid + 1; | ||
| if (nums[mid] < nums[right]) right = mid; | ||
| } | ||
| return nums[left]; | ||
| } | ||
| }; | ||
| ``` | ||
|
|
||
| ## 他の人のコードを見てみる | ||
|
|
||
| https://github.com/tokuhirat/LeetCode/pull/42/files | ||
| https://github.com/ryosuketc/leetcode_arai60/pull/31/files | ||
| https://github.com/takuya576/leetcode/pull/2/files | ||
| https://github.com/Ryotaro25/leetcode_first60/pull/46/files | ||
| https://github.com/goto-untrapped/Arai60/pull/24/files | ||
|
|
||
| numsの最初や最後の要素をnums[mid]との比較対象に選んでいるコードもあったが、個人的には[left, right]に入っていない要素はループ中考えなくてよい感じにしたいと思いました。再帰関数みたいなイメージです。 | ||
| (そういえばこれ書いているときは思いつきませんでしたが再帰関数でも書けますね) | ||
|
|
||
| ライブラリ関数を使って書けないかなと考えていたら、[std::partition_point](https://cpprefjp.github.io/reference/algorithm/partition_point.html) というのを見つけました。 | ||
| これを使うと「nums[0]未満の最初の要素を見つける、なかったらnums[0]を返す」というアプローチで書けそう。 | ||
|
|
||
| ```cpp | ||
| class Solution { | ||
| public: | ||
| int findMin(vector<int>& nums) { | ||
| auto it = std::partition_point(nums.begin(), nums.end(), [&](int x) { | ||
| return x >= nums[0]; | ||
| }); | ||
| if (it != nums.end()) { | ||
| return *it; | ||
| } else { | ||
| return nums[0]; | ||
| } | ||
| } | ||
| }; | ||
| ``` | ||
|
|
||
| 値がユニークでなかったとき(nums[mid]とnums[right]が同じだったとき)はどうするべきだろう? | ||
| [std::invalid_argument](https://learn.microsoft.com/ja-jp/cpp/standard-library/invalid-argument-class?view=msvc-170) をthrowしてみる? | ||
| geminiに相談してみたらrightを1個下げることで正しい答えが求まるようになると言われました。なるほど。 | ||
|
|
||
| ロバストにするならこんな感じでしょうか? | ||
|
|
||
| ```cpp | ||
| class Solution { | ||
| public: | ||
| int findMin(std::vector<int>& nums) { | ||
| if (nums.empty()) throw std::invalid_argument("nums are empty"); | ||
| int left = 0; | ||
| int right = nums.size() - 1; | ||
| while (left < right) { | ||
| int mid = left + (right - left) / 2; | ||
| if (nums[mid] > nums[right]) { | ||
| left = mid + 1; | ||
| } else if (nums[mid] < nums[right]) { | ||
| right = mid; | ||
| } else { // if (nums[mid] == nums[right]) | ||
| --right; | ||
| } | ||
| } | ||
| return nums[left]; | ||
| } | ||
| }; | ||
| ``` | ||
|
|
||
| ただこれでも(uniqueでないとしても)ソートされてることは仮定しないといけないので、実際にはemptyかどうかのチェックぐらいでいいかな? | ||
| emptyのとき、indexを返すだけだったら-1でも返しておけばいいかなと思ったが、中身を返すとなるとエラーをthrowするぐらいしかないかもしれない。intの上限を返すのもちょっと変な気がする。 | ||
|
|
||
|
|
||
| ## 最終コード | ||
|
|
||
| 条件分岐って全部単体のifで回すよりelseとかcontinueとかつけておいた方が余計な条件分岐の判定が少なくなってちょっと早くなるとかあるんでしょうか? | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. もし気になるようであれば、アセンブラーを出力させて比較したり、マイクロベンチマークを取るとよいと思います。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. なるほど。アセンブラーを出力するのは考えませんでした。 |
||
| コンパイラが勝手に最適化してくれたりすることもあるんですかね。 | ||
| もしかしたらこのelseは少し見づらいかも・・・ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 全体としては良いと思いました。if 文には {} ついている方が個人的には好みです。 |
||
|
|
||
| ```cpp | ||
| class Solution { | ||
| public: | ||
| int findMin(std::vector<int>& nums) { | ||
| if (nums.empty()) throw std::invalid_argument("nums is empty"); | ||
| int left = 0; | ||
| int right = nums.size() - 1; | ||
| while (left < right) { | ||
| int mid = left + (right - left) / 2; | ||
| if (nums[mid] > nums[right]) left = mid + 1; | ||
| else right = mid; | ||
| } | ||
| return nums[left]; | ||
| } | ||
| }; | ||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
すべての値が等しい場合、 O(n) になるように思いました。