把一个数组最开始的若干个元素搬到数组的末尾,咱们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的全部元素都大于0,若数组大小为0,请返回0.算法
发现用二分法解决这个问题很好,{3,4,5,1,2}能够分红两个排好序的子数组{3,4,5}{1,2},而左边的每一个数必定大于右边的每一个数,因此能够声明两个索引left=0,right=length-1,mid=left(为啥这么设置初始值请看代码注释).
开始循环,循环条件为list[left] >= list[right]。咱们要作的事情就是让left一直处于第一个数组里且不断接近第一个数组尾,让right一直处于数组二且不断接近数组二的头。让mid等于(left+right)/2,当mid大于left时,说明此时mid还在第一个数组里,这时就让left=mid;继续循环mid再等于(left+right)/2,假设此时mid小于left了,那么它必定处于第二个数组里了,并且它也小于right(由于right时第二个数组当前最大的).当left+1==right的时候就能够跳出循环了,由于此时right就是咱们要找的元素。数组
public class Jianzhi{ public static void main (String[] args){ int[] num = {3,4,5,1,2}; int m = find(num ) ; System.out.println(m); } public static int find(int[] list) { if(list == null){ //数组为null时 return -1 ; } if(list.length == 0 ){ //数组长度为0则返回0 return 0 ; } int left = 0 ; int right = list.length - 1 ; int mid = left ; //注意:这一步让mid等于left是有用意的,若是list是排好序的, //那么直接返回list[mid] while(list[left] >= list[right]){ if(left + 1 == right){ return right ; } mid = (left + right) / 2 ; if(list[mid] == list[left] && list[mid] == list[right]){ return minInOrder(list,left,right); } if(list[mid] >= list[left]){ left = mid ; } if(list[mid] <= list[right] ){ right = mid ; } } return list[mid] ; } public static int minInOrder(int[] list , int left , int right ){ int result = list[left] ; for(int i = left+1 ; i < right ; i++){ if(result > list[i] ){ result = list[i] ; } } return result ; } }
可能你们比较疑惑为何有如下这句:spa
if(list[mid] == list[left] && list[mid] == list[right]){ return minInOrder(list,left,right); }
考虑下面这种状况code
此时 第一个和第二个索引以及mid索引指向的指都是1,三个数字相同。但咱们不能区分出最小的数字在mid的左边仍是右边,就无法进行判断了。此时,就不得不采用顺序查找方法:排序
public static int minInOrder(int[] list , int left , int right ){ int result = list[left] ; for(int i = left+1 ; i < right ; i++){ if(result > list[i] ){ result = list[i] ; } } return result ; }
整个算法最重要的仍是让left和right都往两个数组的公共边界靠拢。索引
完毕。图片