非递减数列数列旋转后求最小值

发布于:2023-01-11 ⋅ 阅读:(247) ⋅ 点赞:(0)

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.总结

希望大家多多支持与鼓励。

希望大家多关注和点赞。

纸上得来终觉浅,绝知此事要躬行。


网站公告

今日签到

点亮在社区的每一天
去签到