剑指offer-11 旋转数组的最小数字
微信搜索【程序员画工师】关注更多Java编程技术、数据结构与算法、面试题相关内容。
题目
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思路
原数组是非递减数组,旋转之后的数组实际上可以划分为两个排序的子数组,而前面数组的元素都大于或等于后面子数组的元素,后面子数组的第一个元素就是要找的最小元素,它比它之前的前面的子数组的最后一个元素小,所以可以遍历数组,找到比它前一位元素小的元素即是目标元素。
上代码
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length == 0){
return 0;
}
int minNum = array[0];
for(int i = 0;i < array.length-1;i++){
if(array[i] > array[i+1]){
minNum = array[i+1];
break;
}
}
return minNum;
}
}
思考
这样的解法需要遍历数组,时间负责度为o(n),也没有利用到旋转数组的特性,显然不是考察的点。既然是排序的数组那就可以用二分查找法实现时间复杂度为O(logn) 的查找。
二分查找法优化
思路如下图
上代码
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length == 0){
return 0;
}
int indexLeft = 0;
int indexRight = array.length-1;
int midIndex = indexLeft;
while (array[indexLeft] >= array[indexRight]){
if(indexRight - indexLeft ==1 || indexRight - indexLeft ==0){
return array[indexRight];
}
midIndex = (indexRight + indexLeft)/2;
if(array[midIndex] >= array[indexLeft]){
indexLeft = midIndex;
}else if(array[midIndex] <= array[indexRight]){
indexRight = midIndex;
}
}
return array[midIndex];
}
}
思考
当indexLeft、indexRight 、midIndex都相同时就无法确定中间数组是属于第一个递增子数组还是第二个递增子数组。比如{1,0,1,1,1}和{1,1,1,0,1}都可以看作{0,1,1,1,1}的旋转,这种情况下无法判断中间数字属于哪一个子数组的,也就无法移动两个指针来缩小查找范围,就得采用遍历查找的方法。
优化后代码如下
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length == 0){
return 0;
}
int indexLeft = 0;
int indexRight = array.length-1;
int midIndex = indexLeft;
while (array[indexLeft] >= array[indexRight]){
if(indexRight - indexLeft ==1 || indexRight - indexLeft ==0){
return array[indexRight];
}
midIndex = (indexRight + indexLeft)/2;
if(array[midIndex] >= array[indexLeft] && array[midIndex] <= array[indexRight]){
int min = findMinNumByOrder(array,indexLeft,indexRight);
return min;
}
if(array[midIndex] >= array[indexLeft]){
indexLeft = midIndex;
}else if(array[midIndex] <= array[indexRight]){
indexRight = midIndex;
}
}
return array[midIndex];
}
public int findMinNumByOrder(int[] array,int indexLeft,int indexRight){
int minNum = 0;
if(array.length == 1){
minNum =array[0];
}else {
for(int i = indexLeft;i < indexRight;i++){
if(array[i] > array[i+1]){
minNum = array[i+1];
break;
}
}
}
return minNum;
}
}
References
[1] 《剑指offer(第二版)》 何海涛著
程序员画工师公众号,欢迎交流