假設按照升序排序的數組在預先未知的某個點上進行了旋轉。
( 例如,數組 [0,1,2,4,5,6,7] 可能變爲 [4,5,6,7,0,1,2] )。
請找出其中最小的元素。
你可以假設數組中不存在重複元素。
示例 1:
輸入: [3,4,5,1,2]
輸出: 1
示例 2:
輸入: [4,5,6,7,0,1,2]
輸出: 0
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
思路
當然可以直接暴力搜啊:這個min_element和二分的代碼耗時相同,說明庫函數還是挺快的嘛 重點是練習二分的思想
class Solution {
public:
int findMin(vector<int>& nums)
{
return nums[min_element(nums.begin(), nums.end())-nums.begin()];
}
};
暴力遞歸
將一個數組分爲左,中間元素,右
三部分,返回【左遞歸結果,中間值,右遞歸結果】中最小的一個
- 遞歸邊界條件是子數組只有一個元素
- 對於越界的情況,返回大值,確保避開這種情況
class Solution {
public:
int fm(vector<int>& nums, int l, int r)
{
if(l>r || l<0 || r>=nums.size())
return INT_MAX;
if(l==r)
return nums[l];
int mid = l+(r-l)/2;
return min(nums[mid], min(fm(nums, l, mid-1), fm(nums, mid+1, r)));
}
int findMin(vector<int>& nums)
{
if(nums.size()==1)
return nums[0];
return fm(nums, 0, nums.size()-1);
}
};
二分遞歸
通過判斷中點元素與區間右端點元素,決定是在右邊還是左邊查找,遞歸的邊界條件是數組剩下一個元素
通過比較區間中間元素nums[mid]
與區間右端點的關係,決定是在左邊還是在右邊查找
- 如果中間元素小於右端點值,那麼中間元素可能是最小值,或者最小值還在中間元素左邊,此時右邊界收縮(r=mid)
- 如果中間元素大於等於右端點值,說明這個區間肯定是無序的,並且旋轉數組的旋轉點就在區間內,此時最小元素肯定在中間元素右邊,所以左邊界收縮(l=mid+1)
class Solution {
public:
int fm(vector<int>& nums, int l, int r)
{
if(l>r || l<0 || r>=nums.size())
return INT_MAX;
if(l==r)
return nums[l];
int mid = l+(r-l)/2;
if(nums[mid]>nums[r])
return fm(nums, mid+1, r);
return fm(nums, l, mid);
}
int findMin(vector<int>& nums)
{
if(nums.size()==1)
return nums[0];
return fm(nums, 0, nums.size()-1);
}
};
非遞歸
通過比較區間中間元素nums[mid]
與區間右端點的關係,決定是在左邊還是在右邊查找
- 如果中間元素小於右端點值,那麼中間元素可能是最小值,或者最小值還在中間元素左邊,此時右邊界收縮(r=mid)
- 如果中間元素大於等於右端點值,說明這個區間肯定是無序的,並且旋轉數組的旋轉點就在區間內,此時最小元素肯定在中間元素右邊,所以左邊界收縮(l=mid+1)
class Solution {
public:
int findMin(vector<int>& nums)
{
if(nums.size()==1)
return nums[0];
int l = 0;
int r = nums.size()-1;
while(l<r)
{
int mid = l+(r-l)/2;
// 和區間右端點值比較
if(nums[mid]<nums[r])
r = mid;
else
l = mid+1;
}
return nums[l];
}
};