局部最小值问题
问题描述:有一个无序数组,且相邻两个元素间不相等,现在让我们找出该数组中的一个局部最小值,并返回对应的下标,要求程序的时间复杂度不能大于O(n)。
局部最小值:
在一个长度为n+1的数组中,局部最小值能有多个。如:
a[0]<a[1],则a[0]就是一个局部最小值。
a[n]<a[n-1],则a[n]就是一个局部最小值。
a[i]<a[i+1]&&a[i]<a[i-1],(0<i<n-1),则a[i]就是一个局部最小值
由于题目要求编写的程序时间复杂度不能大于O(n),所以我们想到使用二分查找的思想(二分查找时间复杂度为O(log2N)),但是一个无序的数组我们该怎么去查找它的局部最小值呢?
1.我们假设情况一:a[0]>a[1],a[n]>a[n-1],从图中可以看出开始a[0]到a[1]是一个数在减小往下走的趋势,而结束a[n-1]到a[n]是一个数在增大往上走的趋势,所以我们可以确定在a[0]到a[n]之间一定存在一个低谷值使得这个趋势的方向发生了改变,那这个低谷值就我们要找的一个局部最小值。
我们就可以使用二分查找将需要查找的区间减半,此时我们需要判断的就是就是a[mid]与a[mid+1]、a[mid-1]所表示的趋势,如以左边为例,如下图,若此时a[mid-1]到a[mid]是一个上升的趋势(其余情况同理)。所以在a[0]到a[mid]之间一定有一个低谷;不断减小范围,当找到一个低谷值,也就是局部最小值就返回。
注意:若此时a[mid]到a[mid+1]为下降趋势时,以mid为基准的两边我们就选择一边就行。
2.情况二:a[0]>a[1]&&a[n]<a[n-1]或a[0]<a[1]&&a[n]>a[n-1],此时a[n]或a[0]就是一个局部最小值。
3.情况三:a[0]<a[1]&&a[n]<a[n-1],则此时a[0]、a[n]都是一个局部最小值,选择一边返回下标即可。
具体代码如下:
#include <stdio.h>
#include <malloc.h>
int* creatArray(int* p,int length);
int binarySearchMin(int* p,int length);
int compare(int* p,int i);
int main()
{
int length = 0;
scanf_s("%d",&length);
int* p = (int*)malloc(length * sizeof(int));//定义长度为length的
if (p == NULL)
{
printf("内存分配失败!");
return 0;
}
p = creatArray(p,length);
int index = binarySearchMin(p,length);
printf("%d\n",index);
free(p);
p = NULL;
return 0;
}
int* creatArray(int* p,int length)
{
for (int i = 0; i < length; i++)
{
scanf_s("%d", &p[i]);
}
return p;
}
//查找
int binarySearchMin(int* p,int length)
{
int left = 0,right = length-1;
int mid = 0;
if (compare(p,left)==1&&compare(p,right-1)==-1)//头大尾大
{
while (left <= right)
{
mid = left + ((right - left) >> 1);
if (compare(p, mid) == -1 && compare(p, mid - 1) == 1) //p[mid]<p[mid+1]&&p[mid]<p[mid-1]
{
return mid;
}
else if (compare(p, mid) == 1)//左右只看一边
{
left = mid + 1;
}
else if (compare(p, mid - 1) == -1)
{
right = mid - 1;
}
}
}
else if (compare(p, left) == -1&&compare(p,right-1)==-1)//头小尾大
{
return left;
}
else if (compare(p,left)==1 && compare(p, right - 1) == 1)//头大尾小
{
return right;
}
else if (compare(p, left) == -1 && compare(p, right - 1) == 1)//头小尾小,(可以任选头尾返回)
{
return left;
}
return 0;
}
int compare(int* p, int i)
{
return p[i] > p[i + 1] ? 1 : -1;
}
总结:这个题其实就是用二分查找的思想减小时间复杂度。然后在使用二分查找时,并不是只有有序的数组才能使用,无序的也可以。同时这段代码其实还可以在使用递归的思想再去改良一下。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」