[剑指-Offer] 11. 旋转数组的最小数字(二分法、分治、递归)

1. 题目来源

链接:旋转数组的最小数字
来源:LeetCode——《剑指-Offer》专项

2. 题目说明

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

示例 :

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

示例 2:

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

3. 题目解析

方法一:二分法

这个题目与[每日一题] 142. 寻找旋转排序数组中的最小值II(数组、二分法、分治、多方法一模一样,有兴趣的也可看看[每日一题] 141. 寻找旋转排序数组中的最小值(数组、二分法、分治、多方法)难度比 142 题偏小一点,大体思路一致。

当数组中存在大量的重复数字时,就会破坏二分查找法的机制,将无法取得 O ( l o g n ) O(logn) 的时间复杂度,又将会回到 O ( n ) O(n)

比如这两种情况:{1, 0, 1, 1, 1}{1, 1, 1, 0, 1}

在这里插入图片描述可以发现,当第一个数字和最后一个数字,还有中间那个数字全部相等的时候,二分查找法就崩溃了,因为它无法判断到底该去左半边还是右半边,就无法缩小范围。

针对这种情况,需要打开思路,拿起我们的顺序查找

  • 将右指针左移一位(或者将左指针右移一位),略过一个相同数字,这对结果不会产生影响,因为只是去掉了一个相同的数字而已
  • 然后对剩余的部分继续用二分查找法,在最坏的情况下,比如数组所有元素都相同,时间复杂度会升到 O ( n ) O(n)

参见代码如下:

// 执行用时 :4 ms, 在所有 C++ 提交中击败了96.03%的用户
// 内存消耗 :14.5 MB, 在所有 C++ 提交中击败了100.00%的用户

class Solution {
public:
    int minArray(vector<int>& numbers) {
        int left = 0, right = numbers.size() - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (numbers[mid] > numbers[right]) 
                left = mid + 1;
            else if (numbers[mid] < numbers[right]) 
                right = mid;
            else 
                --right;
        }
        return numbers[right];
    }
};

方法二:分治法、递归

思想和前一道大致相同,分治、递归即可,不过写法跟之前那道略有不同,只有在 nums[start] < nums[end] 的时候,才能返回 nums[start],等于的时候不能返回。

比如 [3, 1, 3] 这个数组,或者当 start 等于 end 成立的时候,也可以直接返回 nums[start],后面的操作跟之前那道题相同,每次将区间 [start, end] 从中间 mid 位置分为两段,分别调用递归函数,并比较返回值,每次取返回值较小的那个即可。

参见代码如下:

// 执行用时 :4 ms, 在所有 C++ 提交中击败了96.03%的用户
// 内存消耗 :14.6 MB, 在所有 C++ 提交中击败了100.00%的用户

class Solution {
public:
    int minArray(vector<int>& numbers) {
        return helper(numbers, 0, numbers.size() - 1);
    }
    int helper(vector<int>& nums, int start, int end) {
        if (start == end) 
            return nums[start];
        if (nums[start] < nums[end]) 
            return nums[start];
        int mid = (start + end) / 2;
        return min(helper(nums, start, mid), helper(nums, mid + 1, end));
    }
};
发布了307 篇原创文章 · 获赞 125 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/yl_puyu/article/details/104438789
今日推荐