From 04104001d9de4ffcf2345bea25b31c130538c070 Mon Sep 17 00:00:00 2001 From: tokuhirat <54652919+tokuhirat@users.noreply.github.com> Date: Mon, 21 Jul 2025 11:33:19 +0900 Subject: [PATCH] Create 33. Search in Rotated Sorted Array.md --- .../33. Search in Rotated Sorted Array.md | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 33. Search in Rotated Sorted Array/33. Search in Rotated Sorted Array.md diff --git a/33. Search in Rotated Sorted Array/33. Search in Rotated Sorted Array.md b/33. Search in Rotated Sorted Array/33. Search in Rotated Sorted Array.md new file mode 100644 index 0000000..9e98e34 --- /dev/null +++ b/33. Search in Rotated Sorted Array/33. Search in Rotated Sorted Array.md @@ -0,0 +1,93 @@ +# 33. Search in Rotated Sorted Array +## STEP1 +- 何も見ずに解いてみる +- [left, right] を候補とする。left = right の時 middle = left となり、target と比較される。等しくない場合には次の while 文は実行されず −1 が返る。範囲の狭め方としては、rotate 位置と middle と target の位置関係で場合分けした。 +```python +class Solution: + def search(self, nums: List[int], target: int) -> int: + left = 0 + right = len(nums) - 1 + while left <= right: + middle = (left + right) // 2 + if nums[middle] == target: + return middle + if nums[middle] < target: + if nums[middle] >= nums[left]: + left = middle + 1 + continue + if target <= nums[right]: + left = middle + 1 + else: + right = middle - 1 + else: + if nums[middle] <= nums[right]: + right = middle - 1 + continue + if target >= nums[left]: + right = middle - 1 + else: + left = middle + 1 + return -1 +``` + +## STEP2 +### プルリクやドキュメントを参照 +- https://github.com/olsen-blue/Arai60/pull/43/files + - middle と right が指す数の大小関係を先に判定している。崖を超える前後がわかり、場合分けがシンプルになる。 +- https://discord.com/channels/1084280443945353267/1233295449985650688/1239594872697262121 + - https://discord.com/channels/1084280443945353267/1233295449985650688/1239446770761596928 + - 最初解こうとした時に、nums[middle] と target と nums[-1] の大小関係でどうにかしようと思って失敗していた。*2 をする発想がなかったので、崖を越えたのか、middle を越えたのか見分けがつけられなかった。なるほど、このようにするとできる方法があるのかと驚いた。 + - https://github.com/Yoshiki-Iwasa/Arai60/pull/36#discussion_r1712955053 + ここまで整理できていたらわかりやすいですね。ただ思いつきにくいなとも思う。 + +場合分けを整理して、2分探索の確認のため区間の取り方を変えて書いてみる。[left, right) に解の候補を含まれるように探索。 +```python +class Solution: + def search(self, nums: List[int], target: int) -> int: + left = 0 + right = len(nums) + while left < right: + middle = (left + right) // 2 + if nums[middle] == target: + return middle + if nums[middle] > nums[-1]: + if nums[0] <= target < nums[middle]: + right = middle + else: + left = middle + 1 + else: + if nums[middle] < target <= nums[-1]: + left = middle + 1 + else: + right = middle + return -1 +``` +- https://github.com/tokuhirat/LeetCode/pull/41/files#r2217335504 + - 探す数字が配列に含まれていない場合に -1 を返す場合、index の候補が一つになってもそれが探している値を指すか確認しないといけない(対照的なケースとして挿入箇所を探す場合)。これをwhile文の中でやると終了時は解の候補がなくなるため left > right になるのは当たり前だなとわかるようになった。ただ、挿入箇所を探す場合には、最後に候補indexが一つ残るようにする(解釈する)方が良さそうかなと思っています。 + +## STEP3 +### 3回ミスなく書く +個人的には閉区間で書いた方がわかりやすいです。 +```python +class Solution: + def search(self, nums: List[int], target: int) -> int: + left = 0 + right = len(nums) - 1 + while left <= right: + middle = (left + right) // 2 + if nums[middle] == target: + return middle + if nums[middle] > nums[-1]: + if nums[0] <= target < nums[middle]: + right = middle - 1 + else: + left = middle + 1 + else: + if nums[middle] < target <= nums[-1]: + left = middle + 1 + else: + right = middle - 1 + return -1 +``` + +3分,2分,2分で3回Accept