您的位置:首页 > Web前端

剑指offer系列(7)——旋转数组的最小数字

2017-12-18 13:11 190 查看
题目要求如下:

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

这个题的突破口是要发现一个这种排序数组的一个特点:即旋转将数组分成了两个部分的小数组,而后面这个小数组的每个值小于前面的小数组(这里不考虑特殊情况,默认为排序好的递增数组,且其中元素不重复,重复的在后面讨论)

当处于这种情况时,我们只需利用上面的这个特点,即最小得值一定在第二个数组中且一定小于第一个数组中的最小值(第一个数组中最小值为第一个值,eg:[3,4,5,1,2]中的3),这个时候我们可以采用类似二分查找的方法。令一个first下标遍历指针,在令一个final下标遍历指针,这两个指针分别指向第一个元素和最后一个元素,根据其中间值的大小不断缩小范围直至找到。伪代码如下:

If(middle > indexfirst)
first = middle;
else if(middle < indexfirst)
final = middle;
else
特殊情况


下面我们分析特殊情况,当这个数组中有重复值时,并且导致了middle和indexfirst相等。

这里也要分为两种情况:

1) 若first和final之间是全为某一个数的特殊情况,这是,我们只能进行循环遍历。

2) 若first值与中间值相同,但与final值不同,如[5,5,5,1,1],此时我们的算法仍旧可以处理这种情况。所以,这种情况并不用考虑。

综上,我们可以写出代码:

package com.offer;

public class MinNumberInRotatedArray {
/*
* 旋转数组找最小值
*
* 注意!只有低位高位中间位三者完全一样时才采用遍历寻找  ,防止 5,5,5,1,2 ,所以要把特殊情况放在前面
*/
public static void main(String[] args) {
int[] a = new int[]{4,5,1,2,3};
System.out.println(findMinNumber(a));

}

public static int findMinNumber(int[] array){
if (array == null || array.length <= 0) {

throw new RuntimeException("数组为空或长度小于等于零");
}
int low = 0;                    //低位遍历指针
int high = array.length - 1;    //高位遍历指针
if (array.length == 1) {        //只有一个元素
return array[0];
}
int result = 0;                 //最小值
while(Math.abs(high - low) != 1){
if (array[low] == array[high] && array[high] == array[(low + high) >> 1]) {
//中间值与低位元素与高位元素相等,无法判断,必须遍历查询
for (int i = 0; i < array.length; i++) {
result = result > array[i] ? array[i] : result;
}
break;      //跳出while循环 否则将无限执行下去 !

}else if(array[(low + high) >> 1] < array[low]){
//以最小值为界,中间值在后面
high = (low + high) >> 1;

}else{
//以最小值为界 ,中间值在前面
low = (low + high) >> 1;

}
}

result = array[high];

return result;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数组排序