版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/daaikuaichuan/article/details/84453209
题目描述:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
解题思路:
显然旋转数组可以用二分查找的方法来实现,考虑上面的例子,旋转数组中的第一个数一定是大于最后一个数的(除了一种特例),然后要找的最小的数一定是两个递增序列的分界线(此数的左边递增,右边也递增),利用二分查找的思想,设置三个指针分别指向数组的开始(begin),结尾(end),和中间(mid),然后分析过程如下:
1. 和二分查找法一样,我们用两个指针分别指向数组的第一个元素和最后一个元素;
2. 接着我们可以找到数组中间的元素。如果该中间元素位于前面的递增子数组,那么它应该大于或者等于第一个指针指向的元素。此时数组中最小的元素应该位于该中间元素的后面。我们可以把第一个指针指向该中间元素,这样可以缩小寻找的范围。移动之后的第一个指针仍然位于前面的递增子数组之中。如果中间元素位于后面的递增子数组,那么它应该小于或者等于第二个指针指向的元素。此时该数组中最小的元素应该位于该中间元素的前面;
3. 接下来我们再用更新之后的两个指针,重复做新一轮的查找。
【Note】:
对于有序数组的查找首先就要联想到二分查找。乱序数组的查找要最优首先想到哈希表。
Demo:
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
int p1 = 0;
int p2 = rotateArray.size()-1;
int mid;
while (rotateArray[p1] >= rotateArray[p2])
{
// p1和p2相差为1时,p2即为目标元素的下标
if (p2 - p1 == 1)
{
mid = p2;
break;
}
mid = (p1 + p2) / 2;
// 考虑p1和p2相等的情况(只能顺序查找了)
if (rotateArray[p1] == rotateArray[mid] && rotateArray[mid] == rotateArray[p2])
return minNumberInRotateArray2(rotateArray);
else
{
// 左指针比中间值小,则让中间值成为新的左指针
if (rotateArray[p1] <= rotateArray[mid])
p1 = mid;
// 右指针比中间值大,则让中间值成为新的右指针
else if (rotateArray[mid] <= rotateArray[p2])
p2 = mid;
}
}
return rotateArray[mid];
}
// ()顺序查找
int minNumberInRotateArray2(vector<int> rotateArray) {
int res = rotateArray[0];
int p2 = rotateArray.size()-1;
for (int i = 0; i <= p2; ++i)
{
if (res > rotateArray[i])
res = rotateArray[i];
}
return res;
}
};