Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# 153. Find Minimum in Rotated Sorted Array
## STEP1
- 何も見ずに解いてみる
- [left, right] に最小値となる index が含まれていて、それ以外には含まれていないことを保証して範囲を狭める。初期値は left = 0, right = len(nums) - 1 とする。 nums[left] より nums[middle] の方が小さい場合、[left, middle] で ..., nums[n - 1], nums[0], ... となっている箇所があるため、この中に最小値が含まれる。そうでない場合、区間全体で単調増加 (nums[left] < nums[right]) していれば left が求める index であり、そうでない場合は middle より右側に求める index がある。nums[middle] は nums[left] より大きいので +1 してよい。
```python
class Solution:
def findMin(self, nums: List[int]) -> int:
left = 0
right = len(nums) - 1
while left < right:
middle = (left + right) // 2
if nums[middle] < nums[left]:
right = middle
continue
if nums[left] < nums[right]:
break
left = middle + 1
return nums[left]
```
## STEP2
### プルリクやドキュメントを参照
- https://github.com/olsen-blue/Arai60/pull/42/files
- nums[right] もしくは nums[-1] と比較した方が直接的。nums[middle] < nums[right] の場合、[middle, right] に切れ目があろうがなかろうが middle 以下の範囲に最小値がある。left と比較するとそうはいかない。
- https://discord.com/channels/1084280443945353267/1230079550923341835/1233971372946882600
> nums[0] <= nums[i] な領域と nums[0] > nums[i] な領域の境界を探せ
nums[-1] < nums[i] な領域と nums[-1] >= nums[i] な領域の境界を探せ
- このように捉えると普通の二分探索。
- STEP1では無理やり探索している感がある。これは[false, false, false, ..., false, true, true, ture, ..., true]から左の true を探す問題という設定をしていなかったためですね。。。
- 考え直して解く。
- nums[-1] 以下である一番左の index を求める。[left, right] に求める index が含まれるようにする。left より小さい index では nums[-1] 以上が確定、right 以上の index では nums[-1] 以下が確定している。
```python
class Solution:
def findMin(self, nums: List[int]) -> int:
left = 0
right = len(nums) - 1
while left < right:
middle = (left + right) // 2
if nums[middle] <= nums[-1]:
right = middle
else:
left = middle + 1
return nums[left]
```
- https://discord.com/channels/1084280443945353267/1230079550923341835/1235694567085576275
- bisect を使うパターン。
- 2番目は、オペレータ ge に partial を使って部分的に引数を代入して比較する関数を作り出している。
- https://docs.python.org/3/library/operator.html
- https://docs.python.org/3/library/functools.html#functools.partial
- 3番目は、先頭の要素と比較している。単調増加の場合は全て False になり bisect_right の結果は len(nums) となり、返り値は nums[0] で先頭を返す。rotate している場合はその箇所で false, true となる。bisect_right の結果はそのままで良いが、単調増加の場合との場合分けを減らすために - len(nums) としている。
- なるほど、先頭と比較しても場合分け増えずに書けるが、index の取り扱いがややトリッキーな気がした。
```python
def findMin(self, nums: List[int]) -> int:
return nums[bisect_left(nums, True, key=lambda x: x <= nums[-1])]
return nums[bisect_left(nums, True, key=partial(ge, nums[-1]))]
return nums[bisect_right(nums, False, key=lambda x: x < nums[0]) - len(nums)]
```

## STEP3
### 3回ミスなく書く
```python
class Solution:
def findMin(self, nums: List[int]) -> int:
left = 0
right = len(nums) - 1
while left < right:
middle = (left + right) // 2
if nums[middle] <= nums[-1]:
right = middle
else:
left = middle + 1
return nums[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.

いいと思います。

```

3分,1分,1分で3回Accept