二分法查找数组最小值_旋转数组的最小数字(剑指offer第九题)

47d672aba7e36e8cc7c80a23c8aebc88.png

旋转数组的最小数字

题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。

示例 1:
输入:[3,4,5,1,2]
输出:1

示例 2:
输入:[2,2,2,0,1]
输出:0

解题思路

首先看到题目后直接用暴力排序的方法来进行解题。利用sort算法将vector容器中的元素从小到大排序,然后取出排序后容器里的第一个元素就是数组的最小值。不过运行后这种解法结果很不理想。
代码如下:

class Solution {
public:
    int minArray(vector<int>& numbers) {
        sort(numbers.begin(),numbers.end());
        return numbers.front();
    }
};
执行用时:28 ms, 在所有 C++ 提交中击败了8.07%的用户
内存消耗:12.3 MB, 在所有 C++ 提交中击败了7.68%的用户

解法二

对于排序数组的查找问题我们也比较容易想到二分法来解决。
数组旋转以后其实就是将原先有序递增的数组分为左右两个递增子数组,左边区间的任意一个元素>=右区间的任意一个元素。

e7702f49b5ea0b3cf5613ab3ba961094.png

利用二分法我们可以定义i指向数组第一个元素,j指向数组最后一个元素。当i<j时我们进入循环进行比对。定义mid=(i+j)/2,此时比对应该分为三种情况:

  1. 当num[mid]<num[j]时,我们可以判断出最小值一定在[i,mid]区间内;
  2. 当num[mid]>num[j]时,我们可以判断出最小值一定在[mid,j]区间内;
  3. 当num[mid]=num[j]时,此时我们无法判断出最小值在哪个区间内
    原因如下:
    设以下两个旋转点值为0的示例数组,则当 i = 0, j = 4时 m = 2,两示例结果不同。
    示例一 [1, 0, 1, 1, 1]:旋转点 x = 1,因此 m = 2在右排序数组中。
    示例二 [1, 1, 1, 0, 1]:旋转点 x = 3,因此 m = 2在左排序数组中。
    但我们可以判断出此时左区间[i,mid]所有元素相等,或者右区间[mid,j]所有元素相等,或者是整个区间[i,j]所有元素相等。所以我们可以跳出二分法,转而使用线性遍历的方法来进行查找,直到查找到最小值后返回其值。

代码如下:

class Solution {
public:
    int minArray(vector<int>& numbers) {
        int i=0,j=numbers.size()-1;
        while(i<j)
        {
            int mid=(i+j)/2;
            if(numbers[mid]<numbers[j])
                j=mid;
            else if(numbers[mid]>numbers[j])
                i=mid+1;
            else
            {
                int tem=i;
                for(int a=tem+1;a<j;a++)
                {
                    if(numbers[a]<numbers[tem])
                        tem=a;
                }
                return numbers[tem];
            }
        }
        return numbers[i];
    }
};
执行用时:8 ms, 在所有 C++ 提交中击败了93.98%的用户
内存消耗:12.2 MB, 在所有 C++ 提交中击败了31.08%的用户
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值