思路:
法一:
因为数组是非降序的,也就代表该数组是有序的,如果将一开始的元素旋转到后面,那么就会出现一个断点,从大值变为小值的这么一个断点(这是本题的特点)
举例如下:
此时5和1直接就出现了一个断点,那么我们就没必要再进行比较了,因为数组本来就是非降序的,说明最前面的值就是最小值,所以进行旋转后,出现的断点中,那个小值也就是没旋转之前最前面的值(即最小值)
所以我们可以假设最小值为旋转后的第一个元素(如例子中的4),然后按下标顺序开始与4比较,如果第一次碰见比4小的值(如例子中的1),那么就找到了旋转前的第一个元素(也就是最小值),后面就没必要再和4比较了(如例子中的2,3)
答案:
int minNumberInRotateArray(int* nums, int numsLen)
{
int min = nums[0], i = 0; //将旋转后第一个元素假设为最小值
for (i = 1; i < numsLen; i++) //从第二个元素(即下标为1)开始,循环到最后一个元素
{
if (nums[i] < min) //如果出现断点(即后面的值小于第一个元素的值)
{
min = nums[i]; //这个值就是最小值(也就是旋转前的第一个元素)
break; //跳出循环,没必要继续了(因为是非降序,后面的值一定比这个值大)
}
}
return min; //返回最小值
}
但是题目中的数值范围也不小,已经到了10000,如果运气差点,有可能要循环9999次,效率不高,所以我们可以采用二分法来优化
具体二分法的知识就不再本文赘述了
大致思路如下(举例):
情况一:
情况二:
情况三(特殊情况):
此时就应该缩短数组范围,将右边界往左移(即right--)
答案:
int minNumberInRotateArray(int* nums, int numsLen)
{
int left = 0, right = numsLen - 1;
while (left < right)
{
int mid = (left + right) / 2; //取中间值
if (nums[mid] > nums[right]) //情况一
{
left = mid + 1;
}
else if (nums[mid] < nums[right]) //情况二
{
right = mid;
}
else //情况三
{
right--; //缩短数组范围
}
}
return nums[left];
}