题目:剑指 Offer 11. 旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为 1。
题解
本题采用二分查找的思路,旋转数组由两部分,这两部分都是有序数组,题目的目的是查找最小数字,最小的数字一定是较小的数组的第一个元素,我们创建两个指针left和right,分别指向数组numbers的首尾数字,然后计算出中间索引值middle,我们会遇到以下三种情况:
本体本质上是通过数值的比较来缩小查找范围
- numbers[middle] > numbers[right] left = middle + 1
- numbers[middle] < numbers[right] right = middle
- numbers[middle] = numbers[right] right–;(数组有重复的元素)
对于最后一种情况,中间值和右指针指向的值大小相同,那么我们就不能进行范围的缩小了
比如:4 3 4 4 4 此时numbers[mid] = numbers[right] = 4 那么就没办法移动指针,如果middle指向的数字是3,那么就可以将rigth指针移动到middle,
所以,如果middle指向的数字是3 那么就变成 4 3 3 4 4 ,此时rigth 移动到middle, middle指向第二个数字3,变成 4 3 3,这样仍然会出现numbers[middle] = numbers[right]。
所以,其实可以看到,如果发生了numbers[middle] = numbers[right],那么middle和right之间的数字一定都是相同的,那么我们只需要将rigth指针不移动即可,递减,直到numebrs[middle] != numbers[right]
代码
class Solution {
public:
int minArray(vector<int>& numbers) {
int low = 0;
int high = numbers.size() - 1;
while(low < high)
{
int middle = low + (high - low) / 2;
if(numbers[middle] > numbers[high])
{
low = middle + 1;
}
else if(numbers[middle] < numbers[high])
{
high = middle;
}
else if(numbers[middle] == numbers[high])
{
high--;
}
}
return numbers[low];
}
};