剑指offer题解汇总 Java实现
https://blog.csdn.net/guliguliguliguli/article/details/126089434
本题链接
知识分类篇 - 02 算法 - 搜索算法 - JZ11 旋转数组的最小数字 Java实现
题目
题目主要信息
-
有一个长度为n的非降序数组,把一个数组最开始的若干元素“平移”到数组的末尾,变成一个旋转数组
-
找到这个旋转数组的最小值
方案 分治法
分治即“分而治之”
-
“分”指的是将一个大而复杂的问题划分成多个性质相同但是规模更小的子问题,子问题继续按照这样划分,直到问题可以被轻易解决
-
“治”指的是将子问题单独进行处理
分治后的问题需要将解进行合并才能得到原问题的解,因此整个过程经常用递归来实现
思路
旋转数组将原本有序的数组分成了两部分有序的数组,因为在原始有序数组中,最小的元素一定是在首位,那个“断崖式”突然下降的点,就是最小的数字,不过,一个数组中的每个数都一样的话,那就不是了…
可以将旋转前的前半段命名为A,旋转后的前半段命名为B,旋转数组即将AB变成了BA
因为A部分和B部分都是各自有序的,所以可以使用分治,每次比较中间值,确认目标值(最小元素)所在的区间。
具体做法
- 双指针指向旋转后数组的首尾,作为区间端点
- 若区间中点值大于区间右边界值,则最小值一定在中点右边
- 若区间中点值等于区间右边界值,则不好判断最小值在哪半个区间,应逐个缩减右边界
[1,0,1,1,1,1,1]
[1,1,1,1,1,0,1]
- 若区间中点值小于区间右边界值,则最小值一定在中点左边(包括中点)
- 调整整个区间后,即可缩小最小值所在的区间范围
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int[] array) {
int left = 0;
int right = array.length - 1;
int mid;
while (left <= right) {
mid = (left + right) / 2;
if (array[mid] > array[right]) {
left = mid + 1;
} else if (array[mid] < array[right]) {
right = mid;
} else {
right--;
}
}
return array[left];
}
}
能不能以左边界值为参考呢?
应该是不能不能,如[1,0,1,1,1],left的值和mid的值相同,left++
在进入第二次循环的时候,会变成[0,1,1,1],这时,mid的值大于left的值,执行left=mid+1,会把0这个真正的最小值排除在外了
原问题和子问题也不是同一性质的题了