vlambda博客
学习文章列表

剑指 Offer 11. 旋转数组的最小数字【暴力、二分查找】

剑指 Offer 11. 旋转数组的最小数字【暴力、二分查找】

题目

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [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

解题思路

方法一:暴力

由于旋转数组的呈现状有两种,一种为旋转后保存原样的数组形式,另一种为 数组可分为两递增排序,其中中断点定义为最大值到最小值的中断。

所以直接遍历数组,查看数组中是否有出现中断现象(当前值小于上一个值),如果有,则当前值为最小值,如果没有出现该现象,则第一个元素为最小值。

代码实现

public int minArray(int[] numbers) { if(numbers==null){ return -1; } for(int i=1;i<numbers.length;i++){ if(numbers[i]<numbers[i-1]){ return numbers[i]; } } return numbers[0];}

复杂度分析

时间复杂度:O(n)

空间复杂度:O(1)

方法二:二分查找

二分查找,对方法一的优化,方法一遍历数组中间复杂度为O(n),使用二分查找的方法来查找中断点时间复杂度只需要O(logn)。

二分查找规则:以right元素为比较对象,根据旋转数组的规律进行比较。

  • mid元素>right元素,则最小值一定存在于mid右部分。

  • mid元素

  • mid元素==right元素,无法判断存在于哪个部分,则移动right向左移动一位,不影响最后结果,如果right为最小值,mid也是最小值,所以移动right一位不影响结果。

代码实现

public int minArray2(int[] numbers) { int left=0,right=numbers.length-1; while(left<right){ int mid=left+(right-left)/2; if(numbers[mid]<numbers[right]){ right=mid; }else if(numbers[mid]>numbers[right]){ left=mid+1; }else{ right-=1; } } return numbers[left];}

复杂度分析

时间复杂度:O(log n)

空间复杂度:O(1)

资源

https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof