剑指 Offer 11. 旋转数组的最小数字
在 剑指 Offer 53 - II. 0~n-1中缺失的数字 中,我们可以把数组分成 左数组和右数组,很明显这道题也可以分成左右数组,但是在那一道题中,我们可以用索引判断元素是在左数组中还是在右数组中,那么这道题该如何判断呢?
声明 left,right 分别为数组的左右两端。m = (left+right)/2 为每次的中点,接下来是判断左右数组的方法:
1. 当 numbers[m] > numbers[right] 时,m一定在左数组中(因为左数组一定大于等于右数组的元素),此时转折点应该在 [m+1,right] 之间,因此执行 left = m+1。
2. 当 numbers[m] < numbers[right] 时,m一定在右数组中(因为右数组是递增数组),此时转折点应该在 [left,m] 之间,因此执行 right = m。
3. 当 numbers[m] = numbers[right] 时,无法判断m在哪个数组中(因为可能在相同的元素中间断开),此时转折点应该在 [left,right]之间(为什么不是 [mid,right]: 因为可能根本就没有转折点,比如 1 3 3),此时中间元素已经很少了,直接遍历就行。
如果没有出现第三种情况,最终 left 应该指向 右数组的第一个元素,right 应该指向 左数组的最后一个元素(与 53题相同),因此返回 numbers[left] 即可。
class Solution { public int findRes(int[] numbers,int left,int right){ int min = numbers[left]; for(int i=left+1;i<=right;i++){ if(numbers[i]<min){ min = numbers[i]; } } return min; } //找到对应的最小值 public int minArray(int[] numbers) { int left = 0,right = numbers.length-1,mid; while(left<=right){ mid = left + (right-left)/2; if(numbers[mid] > numbers[right]){ //在左数组中 [mid+1,right] left = mid+1; }else if(numbers[mid] < numbers[right]){ //在右数组中 [left,mid] right = mid; }else{ return findRes(numbers,left,right); //返回数组的最小值 } } return numbers[left]; //left位置是右数组第一个元素,返回numbers[left] } }