leetCode -Array 154. Find Minimum in Rotated Sorted Array II

算法系列博客

154. Find Minimum in Rotated Sorted Array II

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
Find the minimum element.
The array may contain duplicates.

注:要求算法以函数形式实现,检测所用vector作为函数参数,求出结果作为函数返回值。

——————————————————————————————–

分析:在环形已排序数组中找出最小值,即是找出比前一元素小的元素的值,其中第一个元素的前一元素定义为最后一个元素。
因而算法的目标即是找出比前一元素小的元素。

解法一:简单遍历

    遍历找出比前一元素小的元素,如果找不出这样的元素,即说明所有元素相等,直接返回任意元素即可。 容易看出时间复杂度O(n)

int findMin(vector<int>& nums) {
    for(int i = 0; i < nums.size() - 1; i++)
        if(nums[i] > nums[i+1]) return nums[i+1];
    return nums[0];
}

解法二:二分递归

    定义包含结果的数组段nums下标起点为begin,终点为end,中点mid=(begin+end)/2;

  1. 结束条件:nums[begin] < nums[end]或begin == end
    此时最小值一定是nums[begin];
  2. 从中点将数组nums分为两个新的数组段[begin,mid]和[mid+1,end],
    如果某段中起点的值比终点的值大,那么最小值一定是在这一段之中,此时便可对这个数组段进行递归;
  3. 在前面两条都不成立的情况下,有如下表达式成立:
        nums[begin] >= nums[end]
        nums[begin] <= nums[mid]
        nums[mid+1] <= nums[end]
    如果有nums[begin] < nums[mid], 则[begin,mid]段段内必然升序,
    并且有nums[mid+1] <= nums[end] <= nums[begin] < nums[mid], 因而nums[mid]即是比前一元素小的元素,也即最小值;
    此时需要对两段进行递归,分别找出两段中各自的最小值,然后两者比较选其小;
  4. 剩下的情况下,最小值一定在[mid+1,end]段之中
int _findMin(vector<int>& nums, int begin, int end) {
   if(nums[begin] < nums[end] || begin == end)
       return nums[begin];
   int mid = (begin + end) / 2;
   if(nums[mid+1] > nums[end])
       return _findMin(nums, mid+1, end);
   if(nums[begin] > nums[mid])
       return _findMin(nums, begin, mid);
   if(nums[begin] < nums[mid])
       return nums[mid+1];
   if(nums[begin] == nums[end] && nums[begin] ==            nums[mid] && nums[mid+1] == nums[end]) {
       int front = _findMin(nums, begin, mid);
       int back = _findMin(nums, mid+1, end);
       return front < back ? front : back;
   }
   return _findMin(nums, mid+1, end);
}

int findMin(vector<int>& nums) {
    return _findMin(nums, 0, nums.size()-1);
}

解法三:二分递推

    设置两个下标low,high初始值分别为数组的下边界和上边界,调整low和high的值,使它们的距离越来越小,并且始终保持最小值在数组low位置和high位置之间,直到low和high相等,则此时low位置的元素记为最小元素

借助辅助量mid=(low+high)/2来对low和high进行调整
与解法二一样,精巧的设计可以免去一些不必要的迭代过程
1.nums[low] < nums[high]时,nums[low]必然是最小值
2.nums[low] > nums[mid]时,最小值必然在[low,mid], 故将mid赋值给high
3.nums[mid] > nums[high]时,最小值必然在[mid+1,high]
4.前面都不满足的条件下
          如果nums[low] < nums[mid],同法二,nums[mid+1]必然是最小值
          如果nums[mid] < nums[high],则nums[mid]必然是最小值
5.其余条件下,不能判断最小值在前半部分还是后半部分,但有nums[low] >= nums[high], 因而nums[low]一定不是最小值,
并且去掉后不会影响数组的环形有序性质,因而将low自增1以缩短low与high的距离

int findMin(vector<int>& nums) {
    int low = 0, mid;
    int high = nums.size() - 1;

    while(low < high) {
        if(nums[low] < nums[high])
            return nums[low];

        mid = (low + high) / 2;
        if(nums[low] > nums[mid])
            high = mid;
        else if(nums[mid] > nums[high])
            low = mid + 1;
        else if(nums[low] < nums[mid])
            return nums[mid+1];
        else if(nums[mid] < nums[high])
            return nums[mid];
        else low++;
    }
    return nums[low];
}

同众多其他二分法一样,这两种二分的时间复杂度的级别均为O(log(n))
区别在于解法二属于递归,解法三属于递推,且此递推较此递推额外开销小

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值