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

来源:互联网 发布:我的世界手机js大全 编辑:程序博客网 时间:2024/04/30 00:46

算法系列博客

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))
区别在于解法二属于递归,解法三属于递推,且此递推较此递推额外开销小

0 0