1.题目
长度为 n 的非降序数列,比如[1,2,3,4,5],将它进行旋转,把一个数组前面的若干个元素搬到数组的最后,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]。给定这样一个数组,求数组中的最小值。
2.思路图解
如数列arr[5]={1,2,3,4,5}
如果它没有经过旋转, 第一个元素小于最后一个元素的,最小值即为第一个元素。
如果它经过旋转,如arr[5]={3,4,5,1,2};
这时我们需要做三个标记即left,right, mid。开始时right等于最后一个元素,left等于第一个元素,mid是最中间的元素。
然后我们要用最中间的元素和最后的元素比大小,目的是排除大的值,剩下小的值继续筛选。
如果 mid>right ,证明最小值在右边,left改为mid+1, mid变为left和right的中间值;
如果 mid<right , 证明最小值在左边,left改为mid, 这时我们无法缺失mid是否为最小值,所以我们无法mid-1;
如果 mid=right ,我们将right--,不能使用left++;因为我们无法确定最小值在左边,但我们能把相同的值right排除掉。
最后重复此过程知道left<right不成立为止,最小值即为arr[left].
3.代码
非降序数列旋转后求最小值 · c6f094b · 风夏/c语言初级学习 - Gitee.com
#include<stdio.h>
//找最小值
int find_min(const int* arr, int cz)
{
int left = 0;
int right = cz - 1;
//非递减数列(未经旋转)
if (arr[left] < arr[right])
return arr[left];
//(经过旋转)
while (left < right)
{
int mid = (left + right) / 2;
if (arr[mid] > arr[right])//最小值在右边
left = mid + 1;
else if (arr[mid] < arr[right])//最小值在左边
right = mid;
else
right--;
}
return arr[left];
}
//旋转
void rotate(int* arr, int cz, int n)
{
int arr1[10] = { 0 };
int i = 0;
//前几个元素的副本
for (i = 0; i < n; i++)
{
arr1[i] = *(arr + i);
}
//后几个元素复制到前面
for(i=0; i<cz-n; i++)
*(arr + i) = *(arr + n + i);
//前几个元素复制到后方
for (i = 0; i < n; i++)
*(arr + cz - n + i) = arr1[i];
}
int main()
{
int arr[5] = { 1,2,3,4,5 };
int cz = sizeof(arr) / sizeof(arr[0]);
int n = 0;
scanf("%d", &n);
rotate(arr, cz, n);
//输出旋转后的数列
for (int i = 0; i < cz; i++)
printf("%d ", arr[i]);
printf("\n");
//判断最小值
int ret=find_min(arr, cz);
printf("%d\n", ret);
}
*注:代码中旋转多少是自己设置的,当遇到考题时,一般只需写find_min的部分。
4.总结
希望大家多多支持与鼓励。
希望大家多关注和点赞。
纸上得来终觉浅,绝知此事要躬行。