问题
如果有一个序列,后一个元素大于等于前一个元素,然后旋转数组的元素,把前面的元素放到序列的后面;
例如原始数据为:
1,2,3,4,5,6
其中的一个选装为:
3,4,5,6,1,2
然后求旋转后的数组中的最小值
思路:其实最简单的就是遍历一遍数组,冒泡一下,其时间复杂度为O(n);有没有什么可以改进一下那,要充分利用已知条件,旋转后的数组可以化为两个有序的子数组,对于有序的数组可以采用二分法查找;
如果中间的元素大于等于前面的元素,那么中间的元素属于第一个递增的字数组内;然后首指针指向中间元素,缩小搜索范围;
如果中间的元素小于等于后面的元素,那么中间的元素是属于第二个递增的字数组内;然后尾指针指向中间元素,缩小搜索范围;
这样保证首指针和尾指针分别在两个字数组内,当两个指针相邻时,尾指针指向的就是旋转后的最小值。可以改善O(n)的时间复杂度,本算法时间复杂度为O(logn).
代码
package edu.liangman.offer;
/**
* Created by lm on 2017/1/3.
* 旋转数组中的最小值
*/
public class MinRotatingarray {
/**
*
* @param arr 遍历的数组
* @param begin 数组的开始下标
* @param end 结束下标
* @return
*/
public int getMinEle(int[] arr,int begin,int end) throws Exception {
int result = 0;
int mid = 0;
if(arr==null)
{
throw new Exception("数组为空");
}
/*
如果第一个元素是最小值,直接返回;也就是旋转了0个元素,即数组没有选装
* */
result = begin;
while(arr[begin]>=arr[end]){
if(end-begin==1){ //后面-前面的
result=end;
break;
}
mid = (end+begin)/2; // +
if(arr[mid]==arr[begin]&&arr[mid]==arr[end]) {
return squenSearch(arr,begin,end);
}
if(arr[mid]>=arr[begin]){
begin = mid;
}
if(arr[mid]<=arr[end]){
end = mid;
}
}
return arr[result];
}
public int squenSearch(int[] arr,int begin,int end){
int min = arr[begin];
for (int i =1;i<arr.length;i++){
if(arr[i]<min)
min = arr[i];
}
return min;
}
public static void main(String[] args) throws Exception {
MinRotatingarray mra = new MinRotatingarray();
//int[] arr = {3,4,5,1,2};
int[] arr = {1,0,1,1,1}; //源数组为0,1,1,1,1
int retvalue =mra.getMinEle(arr,0,arr.length-1);
System.out.print(retvalue);
}
}