-
Notifications
You must be signed in to change notification settings - Fork 0
Create 0033-search-in-rotated-sorted-array.md #26
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
Open
docto-rin
wants to merge
1
commit into
main
Choose a base branch
from
0033-search-in-rotated-sorted-array
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
135 changes: 135 additions & 0 deletions
135
0033-search-in-rotated-sorted-array/0033-search-in-rotated-sorted-array.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| ## Step 1 | ||
|
|
||
| - 問題文 | ||
| - 昇順にソートされた後ローテートされた配列`nums`を受け取る。要素は全てユニーク。 | ||
| - さらに整数`target`を受け取り、`nums`に`target`が存在すればそのインデックスを返し、存在しなければ-1を返す。 | ||
| - 時間計算量: O(log n)で書くこと。 | ||
| - 制約: | ||
| - 1 <= nums.length <= 5000 | ||
| - -10^4 <= nums[i] <= 10^4 | ||
| - All values of nums are unique. | ||
| - nums is an ascending array that is possibly rotated. | ||
| - -10^4 <= target <= 10^4 | ||
|
|
||
| ### 実装1 | ||
|
|
||
| - アルゴリズムの選択 | ||
| - 二分探索を使う。 | ||
| - 配列全体で見るとソートされていないのでそのままでは適用できない。 | ||
| - ..., max, min, ...を境に左右を分割してみると、それぞれはソート済みになる。 | ||
| - この特定は[前回の問題](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/)で実装した。単純な二分探索でできる。 | ||
| - nums[-1]との比較により、左右どちらにtargetが存在しうるかを判断し、再度二分探索。 | ||
| - 時間計算量: ~~O(log n)~~ <- スライスを使ってしまったので実際にはO(n) | ||
| - 空間計算量: ~~O(1)~~ <- スライスを使ってしまったので実際にはO(n) | ||
|
|
||
| ```python3 | ||
| from typing import List | ||
| import bisect | ||
|
|
||
|
|
||
| class Solution: | ||
| def search(self, nums: List[int], target: int) -> int: | ||
| min_index = bisect.bisect_left(nums, True, key=lambda x: x <= nums[-1]) | ||
| if target <= nums[-1]: | ||
| target_index = bisect.bisect_left(nums[min_index:], target) + min_index | ||
| else: | ||
| target_index = bisect.bisect_left(nums[:min_index], target) | ||
| if nums[target_index] == target: | ||
| return target_index | ||
| return -1 | ||
| ``` | ||
|
|
||
| ## Step 2 | ||
|
|
||
| - レビュー by GPT-5 | ||
| - 配列スライスによる計算量悪化 | ||
| - `nums[min_index:]` と `nums[:min_index]` は部分配列をコピーするのでO(n)。 | ||
| - `bisect_left` の `lo`, `hi` 引数で範囲指定すればコピーを避けられる。 | ||
| - またこのやり方なら、返り値のインデックスをoffsetで調整する手間も省けて嬉しい。 | ||
| - インデックス境界チェック不足 | ||
| - `bisect_left` の戻り値は上限(つまり引数 `hi`)に等しくなることがある。 | ||
| - そのまま `nums[target_index]` を参照すると `IndexError` の可能性がある。 | ||
| - `i < hi` を先にチェックすべき。 | ||
|
|
||
| ### 実装2 | ||
|
|
||
| [実装1](#実装1)の改良。 | ||
|
|
||
| - 時間計算量: O(logn) | ||
| - 空間計算量: O(1) | ||
|
|
||
| ```python3 | ||
| from typing import List | ||
| import bisect | ||
|
|
||
|
|
||
| class Solution: | ||
| def search(self, nums: List[int], target: int) -> int: | ||
| min_index = bisect.bisect_left(nums, True, key=lambda x: x <= nums[-1]) | ||
| if target <= nums[-1]: | ||
| lo, hi = min_index, len(nums) | ||
| else: | ||
| lo, hi = 0, min_index | ||
| target_index = bisect.bisect_left(nums, target, lo=lo, hi=hi) | ||
| if target_index < len(nums) and nums[target_index] == target: | ||
| return target_index | ||
| return -1 | ||
| ``` | ||
|
|
||
| - [コメント集](https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.427rioitx1u6) | ||
| - > key関数をいじる方法 | ||
| - numsの要素を元に、単調非減少に並ばせるkey空間を作る事ができれば、numsを引数に、1回のbisect_leftで答えが出せてしまう。 | ||
| - https://discord.com/channels/1084280443945353267/1262688866326941718/1344194431800184852 | ||
| - タプルで、順序づけのための値を優先順に書いていく。 | ||
|
|
||
| ### 実装3 | ||
|
|
||
| - 時間計算量: O(logn) | ||
| - 空間計算量: O(1) | ||
|
|
||
| ```python3 | ||
| from typing import List | ||
| import bisect | ||
|
|
||
|
|
||
| class Solution: | ||
| def search(self, nums: List[int], target: int) -> int: | ||
| key_function = lambda x: (x <= nums[-1], x) | ||
|
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. なるほど、このような解き方もあるのですね。勉強になりました。 |
||
| index = bisect.bisect_left( | ||
| nums, | ||
| key_function(target), | ||
| key=key_function | ||
| ) | ||
| if index < len(nums) and nums[index] == target: | ||
| return index | ||
| return -1 | ||
| ``` | ||
|
|
||
| - key関数の計算は複雑になるが、bisect_leftは1回で済んでいる。 | ||
| - x <= nums[-1]がFalse->Trueという単調述語をまず優先し、同じbool判定内ではxにより順序づけがされる、という構造。 | ||
| - 1個目の判定がrotationをほどいた順序づけを回復させることに相当する。 | ||
| - key_function = lambda x: (x < nums[0], x)でもいい。 | ||
|
|
||
| ## Step 3 | ||
|
|
||
| ### 実装4 | ||
|
|
||
| [実装3](#実装3)のkey_functionを少しだけ変えた。 | ||
|
|
||
| ```python3 | ||
| from typing import List | ||
| import bisect | ||
|
|
||
|
|
||
| class Solution: | ||
| def search(self, nums: List[int], target: int) -> int: | ||
| key_function = lambda x: (x < nums[0], x) | ||
| index = bisect.bisect_left( | ||
| nums, | ||
| key_function(target), | ||
| key=key_function | ||
| ) | ||
| if index < len(nums) and nums[index] == target: | ||
| return index | ||
| return -1 | ||
| ``` | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
上の考察では
と書かれていますが、最終的にhiではなく
target_index < len(nums)の比較にされたのは何か理由がありますでしょうか?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.
ありがとうございます。
hiよりlen(nums)の方が認知負荷が少ないかな、となんとなく思い、そうしました。
(bisect_leftの上限値をとった場合はダメとするより、and nums[target_index] == targetを安全に行うためのフィルタリングを行い、全ての判定をand以降に任せる、みたいな感じでしょうか)
ですが、自分としてはどちらでも趣味の範囲内だと考えています。