剑指Offer-旋转数组中的最小数

剑指Offer-旋转数组中的最小数

题目如下

LCR 128. 库存管理 I

仓库管理员以数组 stock 形式记录商品库存表。stock[i] 表示商品 id,可能存在重复。原库存表按商品 id 升序排列。现因突发情况需要进行商品紧急调拨,管理员将这批商品 id 提前依次整理至库存表最后。请你找到并返回库存表中编号的 最小的元素 以便及时记录本次调拨。

示例 1:

输入:stock = [4,5,8,3,4]
输出:3

示例 2:

输入:stock = [5,7,9,1,2]
输出:1

提示:

  • 1 <= stock.length <= 5000
  • -5000 <= stock[i] <= 5000

思路

这道题在力扣上需要通过不难,因为数据集并不是很大,甚至可以直接暴力解法,这里要分享的是用二分法搜索。

二分查找

通过题意我们可以知道,原数组原本是一个递增数组,后面由于一些原因旋转了。

如下面一个例子:

[5,7,9,1,2]

[5…9]是递增的

[1…2]也是递增的

但是两个部分并不连续递增,我们目的就是要找出中间开始变化的那个点。

定义left指针和right指针

left:指向区间的最左边

right:指向区间的最右边

每一次循环用mid = (left+right)/2right指向的值比较(下面解释

  • 若stock[mid] > stock[right],则left = mid+1

  • 若stock[mid] < stock[right],则right = mid

  • 若stock[mid] = stock[right], 则right–

循环终止条件为:left=right

可行性说明

  • 为什么不和left比较而是和right比较呢?

举个例子:

[1,2,3,4,5]

[3,4,5,1,2]

假设left=0,right=4,那么mid=2,即指向中间值,此时mid指向的值均大于left指向的值,但是两种数组的情况是不一样的。

这就证明了为什么不能与left比较,原因是有二义性。

  • 为什么当stock[mid] > stock[right],left = mid+1,而stock[mid] < stock[right],却不是right = mid - 1呢?

首先解释为什么要mid+1

也是一样的例子

[3,4,5,1,2]

如果stock[mid] > stock[right],则说明:此时数组在继续往下的话就会遇到断点,在此之前数组是正常递增

因此区间[left,mid]都是正常的,这里是闭区间

所以下一个区间应该收缩到[mid+1,right]

而如果stock[mid] < stock[right],则说明:mid此时的位置已经在异常区间里头,不能保证mid-1是正常的递增区间

因此区间[mid,right]是不正常的,且不能保证[mid-1,right]也正常。

[3,4,5,6,1,2,3]

此时mid=5,指向val = 2,触发第二个条件,而如果right = mid-1就把前一个的值(1)给略过了。

  • 为什么等于时无法判断,而且要right–?

若mid 指向的值等于最右边,由于数组可重,因此不能说明在哪个区间。

至于为什么要right–?不知道,我也没搞懂(双手摊开)

代码如下

class Solution {
public:
    int stockManagement(vector<int>& stock) {
        int left = 0, right = stock.size()-1;
        int mid;
        while(left<right){
            mid = (left+right)/2;
            if(stock[mid] > stock[right]){ // 位于右边的序列
                left = mid + 1;
            }else if(stock[mid] < stock[right]){ // 位于左边的序列
                right = mid ;
            }else{
                right--;
            }
        }
        return stock[left];
    }
};

你可能感兴趣的:(算法,算法,数据结构)