LeetCode:153 尋找旋轉排序數組中最小值 二分遞歸與二分非遞歸

假設按照升序排序的數組在預先未知的某個點上進行了旋轉。

( 例如,數組 [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];
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章