Categorygithub.com/blueBlue0102/LeetCode-Goleetcode0153.Find-Minimum-in-Rotated-Sorted-Array
package
0.0.0-20241125063422-a7e1e0bf04b0
Repository: https://github.com/blueblue0102/leetcode-go.git
Documentation: pkg.go.dev

# README

153. Find Minimum in Rotated Sorted Array

https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/

已知給定的 nums 中的數字都不會重覆,然後會經過隨機 n 次的翻轉
題目要求以 $O(logn)$ 找出 nums 中的最小值

[1 2 3 4 5 6 7] 為例,來探討各種不同次翻轉後的情況下,比較 nums[left], nums[mid] and nums[right] 的值的關係
翻轉 7 次,[1 2 3 4 5 6 7],nums[left] < nums[mid] && nums[right] > nums[mid],nums[left] 就是最小值

翻轉 1 次,[7 1 2 3 4 5 6],nums[left] > nums[mid] && nums[right] > nums[mid],最小值在中位數左側
翻轉 2 次,[6 7 1 2 3 4 5],nums[left] > nums[mid] && nums[right] > nums[mid],最小值在中位數左側
翻轉 3 次,[5 6 7 1 2 3 4],nums[left] > nums[mid] && nums[right] > nums[mid],最小值在中位數左側

翻轉 4 次,[4 5 6 7 1 2 3],nums[left] < nums[mid] && nums[right] < nums[mid],最小值在中位數右側
翻轉 5 次,[3 4 5 6 7 1 2],nums[left] < nums[mid] && nums[right] < nums[mid],最小值在中位數右側
翻轉 6 次,[2 3 4 5 6 7 1],nums[left] < nums[mid] && nums[right] < nums[mid],最小值在中位數右側

觀察以上規律
當【nums[left] < nums[mid] && nums[right] > nums[mid]】時,其 nums[left] 就會是最小值
當【nums[left] > nums[mid] && nums[right] > nums[mid]】時,最小值會在中位數(包含)左側,所以設定 right = mid
當【nums[left] < nums[mid] && nums[right] < nums[mid]】時,最小值會在中位數(不包含)右側,所以設定 left = mid + 1

再考慮 Edge Case,思考 left, right 和 mid 的定義,是否會重疊
[1 2]: left = 0, nums[left] = 1, mid = 0, nums[mid] = 1, right = 1, nums[right] = 2
為了得以判定 left 是最小值,也就是想符合原先【nums[left] < nums[mid] && nums[right] > nums[mid]】的條件
所以修改條件,left 和 mid 是有重疊的可能性,變成【nums[left] <= nums[mid] && nums[right] > nums[mid]】
[2 1]: left = 0, nums[left] = 2, mid = 0, nums[mid] = 2, right = 1, nums[right] = 1
想要將[2 1]拆成[1],想要符合原先【nums[left] < nums[mid] && nums[right] < nums[mid]】,來觸發left = mid + 1
所以觀察得出,left 和 mid 有重疊的可能,所以條件要改成【nums[left] <= nums[mid] && nums[right] < nums[mid]】

結論:
當【nums[left] <= nums[mid] && nums[right] > nums[mid]】時,其 nums[left] 就會是最小值
當【nums[left] >= nums[mid] && nums[right] > nums[mid]】時,最小值會在中位數(包含)左側,所以設定 right = mid
當【nums[left] <= nums[mid] && nums[right] < nums[mid]】時,最小值會在中位數(不包含)右側,所以設定 left = mid + 1


事後看解答發現,還可以再精簡判斷條件
[1 2 3 4 5 6 7]
[7 1 2 3 4 5 6]
[6 7 1 2 3 4 5]
[5 6 7 1 2 3 4]
[4 5 6 7 1 2 3]
[3 4 5 6 7 1 2]
[2 3 4 5 6 7 1]

可以觀察出其中,只要 nums[right] > nums[mid],就可以推測出最小數在左側(含中位數),更新 right = mid
只要 nums[right] < nums[mid] 就可以推測出最小數在右側(不含中位數),更新 left = mid + 1
[2 1] 的情況下,希望觸發 left = mid + 1,所以 nums[right] < nums[mid] 改成 nums[right] <= nums[mid]

如此迭代,最後可以得出 left 會是最小值

Takeaway