大致思路:
首先要把题多读几遍,理解题意!
题意:给你一个旋转后的数组,让你找最小值。
发现数字规律:由于是非递减序列,可以先认为就是递增序列,再去考虑相等的情况。以{3,4,5,1,2}这个旋转数组为例,可以知道其实分为两区,左区是更大的。而我们要找的最小的元素,就是左右区的临界元素,这里是1.
对于这种“顺序查找”可以解决的题目,为了优化,最好采用“二分查找”——用left和right两个指针,看mid元素。
而二分查找的nuance就在于:
① 如何判断“找到”。传统:看Mid元素是否是所查找的值。本题:看left和right是否到了临界区,满足left==right-1,则取array[right]
② mid指针如何变化。传统:将mid元素与所查找的值比大小。本题:将mid元素与旋转数组的第一个元素(这里是3)作比较,如果大于说明mid在左区,令left=mid;如果小于说明mid在右区,令right=mid。
最后,再考虑相等的特殊情况:
我们看一组例子:{1,0,1,1,1} 和 {1,1, 1,0,1} 都可以看成是递增排序数组{0,1,1,1,1}的旋转。
这种情况下我们无法继续用上一道题目的解法,去解决这道题目。因为在这两个数组中,第一个数字,最后一个数字,中间数字都是1。因此,这种特殊情况就直接顺序遍历求最小值来解决。
AC代码:
#include<bits/stdc++.h>
#include<iostream>
using namespace std;
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
if(rotateArray.size()==0)
return 0;
int left=0; //指向左区
int right=rotateArray.size()-1; //指向右区
int mid;
//二分查找最小的元素
while(rotateArray[left]>=rotateArray[right])
{
mid = (left+right)/2;
//此处找到的条件不是来判断mid元素的值,而是看left和right的关系
if(left==right-1)
{
mid = right;
break;
}
//处理特殊情况:相等。只能遍历找最小值
if(rotateArray[left]==rotateArray[right]&&rotateArray[left]==rotateArray[mid])
{
return findMin(rotateArray,left,right);
}
//对于一般情况,Left位于左区,right位于右区,需要找到左右区的临界元素,则为最小值
//二分查找的思想,去判断Mid元素
if(rotateArray[mid]>=rotateArray[left]) //mid位于左区
left = mid;
else //mid位于右区
right = mid;
}
return rotateArray[mid];
}
public:
int findMin(vector<int>rotateArray,int left,int right)
{
int minn=1e9;
for(int i=left;i<=right;i++)
{
minn = min(minn,rotateArray[i]);
}
return minn;
}
};