【LeetCode】【二分查找】剑指 Offer 11. 旋转数组的最小数字 思路解析和代码

剑指 Offer 11. 旋转数组的最小数字

题目链接

个人思路

题意

题目中的数组被分割成两部分,且两部分均为递增序列,找出序列中的最小元素,要利用递增数组的特性,要采用二分查找

思路

  • 循环条件:根据旋转数组的特点,序列应满足第一个元素大于最后一个元素(特例1,2,3,4,5)
  • 二分查找(此处的mid,left,right表示数值):如果mid大于等于left,说明mid属于前一个递增数组,最小元素应该在mid 的后面;如果mid小于等于right,说明mid属于后一个递增数组,最小元素应该在mid前面,也可能就是mid
  • 循环终止条件:当right和left相差1时,此时left指向前一个递增数组的最后一个元素,right指向后一个递增数组的第一个元素,right即为最小元素,返回right

注意

此题有许多特例

  • 当数组为已经排序的数组,即1,2,3,4,5,此时第一个元素小于最后一个元素,应返回left
  • 当最小元素夹在相同元素中,即10,1,10,10,10,此时会出现mid== left ==right的情况,此时无法判断当前的mid在哪一个递增数组中,只能顺序遍历

个人错误思路代码

  • 判断条件没有搞清楚
  • 对于mid== left ==right的特例没有处理好
class Solution {
public:
    const int inf = 0x3fffffff;
    int minArray(vector<int>& numbers) {
        if(numbers.size() == 0){
            return 0;
        }
        int left = 0, right = numbers.size() - 1;
        if(left == right){
            return numbers[left];
        }
        int temp = inf;
        if(numbers[left] <= numbers[right]){
            temp = numbers[left];
        }
        while(left <= right){
            
            int mid = (left + right) / 2;//下标
            int midData = numbers[mid];//数据

            //cout << left << " " << mid << " " << right << endl;
            if(right - left == 1){//此时是最小元素,即分界处
                if(numbers[right] > temp){
                    return temp;
                }else{
                    return numbers[right];
                }
            }
            if(midData >= numbers[left]){//说明当前元素在前面的递增数组中,最小元素则在后半段
                left = mid;
                continue;
            }
            if(midData <= numbers[right]){
                right = mid;
                continue;
            }
        }   
        return numbers[left];
    }
};

正确解题代码

class Solution {
public:
    int minArray(vector<int>& numbers) {
        if(numbers.size() == 0){
            return 0;
        }
        int left = 0, right = numbers.size() - 1;
        if(numbers[left] < numbers[right]){//说明数组是排序的
            return numbers[left];
        }
        while(numbers[left] >= numbers[right]){
            int mid = (left + right) >> 1;
            //cout << left << " " << mid << " " << right << endl;
            
            if(right - left == 1){//左右指针位置相差1
                return numbers[right];
            }
            if(numbers[left] == numbers[mid] && numbers[mid] == numbers[right]){//当三个指针数值相同时,无法判断最小元素的位置
                int temp = numbers[left];
                for(int i = left + 1; i < right; ++i){
                    if(numbers[i] < temp){
                        temp = numbers[i];
                    }
                }
                return temp;
            }
            if(numbers[mid] >= numbers[left]){//说明当前元素属于前一个递增数组中,最小元素在当前元素后面
                left = mid;
                continue;
            }
            if(numbers[mid] <= numbers[right]){//说明当前元素属于后一个递增数组,最小元素可能是当前元素,也可能在当前元素前面
                right = mid;
                continue;
            }
        }
        return numbers[right];
    }
};

测试样例

input:1,2,3,4,5
output:1

input:10,1,10,10,10
output:1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值