本题来源于牛客网,原题链接如下:
旋转数组的最小数字
描述:
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。
请问,给定这样一个旋转数组,求数组中的最小值。
数据范围:
1≤n≤10000
数组中任意元素的值:
0≤val≤10000
题解:
1. 解法一:BF解法
暴力破解,从旋转后的数组的最后一位开始往前找,直到找到最小值
具体找的方法是:从数组的第n项开始,与前一项进行对比。
由题目旋转数组的性质可知,因为旋转前是非降序数组,故旋转后的数组从最后一项开始,其前一项要么小于最后一项,要么等于最后一项。若当某一项的前一项大于该项,则说明该项就是要找的最小值。
那么我们就可以创建一个临时变量来保存较小者,当前一项大于后一项时结束循环(可通过创建标记变量来实现),此时临时变量的值即为最小值。
- 完整代码如下:
int minNumberInRotateArray(int* rotateArray, int rotateArrayLen )
{
int len = rotateArrayLen - 1;
int tmp = rotateArray[len];//从最后一个元素开始
int flag = 1;
while(flag && len)
{
if(tmp == rotateArray[len-1])
len--; //若相等继续往前进行比较
else if(tmp > rotateArray[len-1])//让tmp为小的,继续和前面的比较
{
tmp = rotateArray[len-1];
len--;
}
else if(tmp < rotateArray[len-1])//当前tmp即为最小
flag = 0;
}
return tmp;
}
2. 解法二:二分法
结合二分法的思想,旋转后的数组中间位置上的数要么是原数组中未旋转的部分中的数(如例中3 4 5 1 2 中的 5);要么是已旋转部分中的数(如例中 4 5 1 2 3 中的 1 )。那么就可循环通过中间位置上的数与最右边的数进行比较,逐步将查找范围缩小。
每次对比可分为一下3种情况:
设标记
int left = 0;
int right = rotateArrayLen - 1;
int mid = (left + right) / 2;
(1)中间数大于最右边:此时的中间数一定是原数组中的未旋转部分中的数(如:3 4 5 1 2),即最小的数一定在中间数右边,那么此时就可将左边界 left 的值置为 mid + 1,缩小查找范围。
(2)中间数等于最右边:此时的最小数要么就是中间数(如:2 2 2 2 2),要么就是在中间数的左边(如:1 0 1 1 1),故通过让右边界 right- -来缩小范围,此时相当于mid(= right + left / 2)的值减小了,即 mid 往左“移”了,相对地,最小的数就往右推了。
(3)中间数小于最右边:此时的中间数一定是原数组中的旋转部分中的数,即最小的数一定在中间数左边(如:5 1 2 3 4)或者直接就是中间数(如4 5 1 2 3),故此时可将右边界 right 的值置为 mid 来缩小范围
查找结束的条件:当左边界 left = 右边界 right,此时下标 left 对应的数组元素 或 下标 right 对应的数组元素就是要找的最小的数
这里用 4 5 1 2 3 作为例子:
第一次查找:
初始时,mid对应值为1,比最右边数小,比较后执行 right = mid;查找范围缩小到4 5 1
第二次查找:
mid对应值为5,比最右边数大,比较后执行 left = mid + 1;此时 left = right,查找结束。
- 完整代码如下:
int minNumberInRotateArray(int* rotateArray, int rotateArrayLen )
{
int left = 0;
int right = rotateArrayLen - 1;
int mid = 0;
while(left < right)
{
mid = (left + right) / 2;
if(rotateArray[mid] > rotateArray[right])
{
left = mid + 1;
}
else if(rotateArray[mid] == rotateArray[right])
{
right--;
}
else if(rotateArray[mid] < rotateArray[right])
{
right = mid;
}
}
return rotateArray[left];
}
看完觉得有觉得帮助的话不妨点赞收藏鼓励一下,有疑问或看不懂的地方或有可优化的部分还恳请朋友们留个评论,多多指点,谢谢朋友们!🌹🌹🌹