剑指offer-11 旋转数组中的最小数字
一、题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
关于旋转数组:
/*传进去旋转数组,注意旋转数组的特性:
*
1
.包含两个有序序列
*
2
.最小数一定位于第二个序列的开头
*
3
.前序列的值都>=后序列的值
* 定义把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
* ^_^这个旋转思想是很经典的
* 旋转数组实例:
* {
123456
}旋转后{
456123
}
*/
考察知识点为:二分
例如:
输入:[3,4,5,1,2]
输出:[1]
二、解题
1.解题思路
1-1 优化的暴力破解
由于旋转数组的特性,一个递增数组的开始的若干元素被搬到了数组的末尾,被搬到末尾的元素依旧是按照递增顺序排列,比如{123456}旋转后变为{456123},既然要找出最小的数字,根据旋转数组的特性,数组array[i+1]<array[i],那array[i+1]则为数组中的最小数字。
1-2 利用二分查找
充分利用旋转数组的特性,使用二分查找,
1)先考虑没有重复元素的情况:(eg: 2, 3, 4, 1)、(eg: 4, 1, 2, 3)
如果mid位置的元素大于high位置的元素,则最小值一定在mid位置的右边,即mid+1到high,此时则去mid+1到high之间进行查找,则重新赋值low = mid+1;
否则最小值出现在low到mid,此时再去low到high之间进行查找,则重新赋值high = mid。
这也就解释了为什么low = mid + 1, 而high = mid。
2)再看有重复元素的情况:(eg: 3, 3, 3, 2, 3)、(eg: 3, 2, 3, 3, 3)
这种情况下,可能出现mid和low、high三个位置上的元素都相等的情况,导致我们无法判断最小值出现在那一边,解决方法是将跳过low和high位置的元素,即low++, high--。
2.代码实现
2-1 暴力优化
def minNumberInRotateArray(rotateArray):
for i in range(len(rotateArray)):
if rotateArray[i+1]<rotateArray[i]:
return rotateArray[i+1]
return 0
2-2 二分查找
public class Solution {
public int minNumberInRotateArray(int [] array) {
//判空
if (array == null || array.length == 0) {
return 0;
}
int low = 0, high = array.length - 1;
while (low < high) {
int mid = (low + high) / 2;
if (array[mid] == array[low] && array[mid] == array[high]) {
low++;
high--;
}
if (array[mid] > array[high]) {
low = mid + 1;
} else {
high = mid;
}
}
return array[low];
}
}
3.总结
从旋转数组的特性出发进行解题,如果根据其特性使用暴力优化算法以及二分查找解题。