【C语言】【时间复杂度】Leetcode 153. 寻找旋转排序数组中的最小值

news2024/9/29 3:28:41

文章目录

  • 题目
  • 时间复杂度
    • 概念
    • 时间复杂度的计算
  • 解题思路
  • 代码呈现


题目

链接: link
在这里插入图片描述

时间复杂度

概念

时间复杂度是一种函数,定量地描述了该算法运行的时间。既然是一种函数,就涉及到自变量与因变量。因变量代表是时间复杂的规模,自变量是时间复杂度的执行时间。这里的执行时间并不是秒,分钟这类的具体时间 ,它表示的是一种“执行次数”。要想计算时间复杂度首先得找到该算法中的循环,算法中循环执行的次数就是算法的时间复杂度

算法的时间复杂度的具体表示为:用大写的 O 来体现算法时间复杂度如O(f(n)),称之为 大 O 记数法。

时间复杂度的计算

注:可以理解为最坏情况下,算法的最高量级

一,单层for循环(线性阶

判断一个数是偶数还是奇数,只需要求它除上 2 的余数是 0 还是 1,把所有数都判断一遍,并且对符合条件的情况进行计数,最后返回这个计数器就是答案,需要遍历所有的数,因此代码为:

int count(int n, int a[]) {
    int cnt = 0;
    for(int i = 0; i < n; ++i) {
        if(a[i] % 2)
            ++cnt;
    }
    return cnt;
}

我们可以发现这里的算法只有一层fo循环,执行过程中需要遍历n遍,所以这里的时间复杂度为O(n)。


二 ,多层for循环(指数阶

int fun(int n)
{
   int cnt = 0;
  for(int i = 0;i < n;i++)
   {
     for(int j = 0; j<n; j++)
      {
        cnt++; 
      }
   }//两层循环,每次循环n次,因此为n*n
 
 
  for(int k = 0; k<n; k++)
   {
     ++cnt;
   }//一层循环,循环n次
  
  for(int l = 0;l<10;l++)
   {
     ++cnt;
   }//一层循环,循环10次
 
return cnt;
}

这里假如把所有的循环都算进去的话,时间复杂度就是O(nn+n+10),但是我们并不能这样写。这是因为对于时间复杂度我们不需算出精确的数字,只需要算出这个算法属于什么量级即可。
所以在这里,为知道这个算法两级为多少,我们将字母n取为无穷大,这样10就无足轻重,然后时间复杂度就变成O(n
n+n),又因为nn远大于n,原式也可以表达成n(n+1),即使-1也无关紧要,所以时间复杂度演变成O(n*n)。这就是大O渐近表示法,只是一种量级的估算,而不是准确的值。


三,冒泡排序(指数阶

void bubblesort(int* a,int n)
{
   assert(a);
for(int end = n; end>0; end--)
    {
      int exchange = 0;
       for(int i = 1; i<end; i++)
           {
              if(a[i-1]>a[i])
              {
                swap(&a[i],&a[i-1]);
                 exchange = 1;
               }
            }
    
       if(exchange==0)
           break;
     }
}

在这里我们会发现这边不是简单的两层for循环,而是呈现一个等差数列,第一次循环第一次循环n-1次,第二次n-2次…一直到1,如果这样的话,难道时间复杂度就要写成O(n*(n+1)/2)了吗。
然而并不用,通过上面的例子我们看出,我们所采用大O渐近表示法去掉了对结果影响不大的项,并且在实际情况中一般只关注算法的最坏运行情况。
因此这里的算法复杂度只要把一些加法常数、保留最高项就行,例如在上述冒泡排序中,如果给定的数组就已经是有序的了,那么就是它的最好情况,时间复杂度为O(N).但是如果有非常多的数据很显然我们看不出它到底是否为最好情况,所以我们必须用最坏的期望来计算所以它是O(N*N).


四,指定常数循环(常数阶

int fun(int n)
{
  int i = 0;int cnt = 0;
   for( i; i<100;i++)
     {
       cnt++;
      }
  return cnt;
}

此时时间复杂度为O(1),这里的1不是指一次,而是常数次,该循环执行了100次,不管n多大,他都执行100次,所以是O(1)


五,二分查找(对数阶

int binary(int n, int a[], int k) 
{
	int left = 0, right = n - 1;
	while(l <= r) {
		mid = (l + r)/2;
		if(a[mid] == k) 
		    return mid;
		else if(a[mid] < k)
			right = mid + 1;
		else
			left = mid + 1;
	}
	return -1;
}

常见于二分查找中在有序数组中查找目标元素的算法。每次查找都将目标元素与数组中间的元素进行比较,如果相等则返回,如果目标元素小于中间元素,则在左半部分继续查找,否则在右半部分继续查找。每次查找都将搜索范围缩小一半
先找n/2,n/4,n/8一直到n等于1

因为这种算法,每多一次循环相当于,循环地覆盖范围变成了2^n,因此我们可以推出这个算法的时间复杂度为O( l o g 2 x log_{2}x log2x)


由此我们可以得出结论

1.去除表达式中所有加法常数
2.修改的表达式中只保留最高阶项,因为只有它对最终结果产生影响
3.如果最高阶项系数存在且不是1,则将其系数变为1,得出最后的表达式
4.如果循环过程中只有常数时,,取常数次为时间复杂度

常见的时间复杂度

线性阶就像上面第一题一样,只有一层循环,时间复杂度随n的增大线性增加,函数在图像上表示为一条经过原点的直线,O(N)
指数阶指数阶一般是算法题的暴力解法,一般是多层循环的嵌套,例如上面题二中,最大是两层n次循环的嵌套,因此时间复杂度为O(N^2),n的平方次
常数阶函数内循环为常数次或者没有循环,例如上面第四题,时间复杂度为O(1)
对数阶表示算法的时间复杂度与输入模 n 的对数成正比,其中对数的底数未指定,默认为2,10或e,根据具体情况而定。这意味着算法的运行随着输入规模的增加而增加但增长速度较慢。


解题思路

题目中要求我们把时间复杂度控制在O(log⁡n)里面,一般来说,这里的时间复杂度在没有设置底数的时候我们默认为10,这种算法随n增长较缓慢。

对于题目中找到最小的元素,我们第一个想到的就是最最暴力的冒泡排序,一个一个数遍历。

int findMin(int* nums, int numsSize) {
    int count = 1;
    for (int i = 0; i < numsSize; i++) {
        if (nums[i + 1] > nums[i])
            count++;
        else
            break;
    }
    return nums[count];
}

这种方法固然可行,但是此时的时间复杂度为O(n),比O( l o g 2 x log_{2}x log2x)大,对于算法复杂度的大小比较我们可以看成x随y的变换量,所以我们可以直观地知道这种粗暴的排序方法是不能够满足条件的,因此我们可以转变为二分查找,这种方法恰好符合题目所要求的时间复杂度

在这里插入图片描述
小tip:https://www.geogebra.org/download 是个很好的数学软件,可以画出函数等数学模型,更加直观便捷地感受数据


重新整理本题,一个不包含重复元素的升序数组在经过旋转之后,可以得到下面可视化的折线图
在这里插入图片描述

其中横轴表示数组元素的下标,纵轴表示数组元素的值。而图中标出了最小值的位置,就是我们需要查找的目标。

倘若使用二分查找的方法,我们就我们考虑数组中的最后一个元素 xxx:在最小值右侧的元素(不包括最后一个元素本身),它们的值一定都严格小于 xxx;而在最小值左侧的元素,它们的值一定都严格大于 xxx。因此,我们可以根据这一条性质,通过二分查找的方法找出最小值。

代码呈现

前者是基于left与right索引相同时出结果,即二分查找到数组只剩一个元素,然后直接输出left或right就行

int findMin(int* nums, int numsSize) {
    int left = 0;
    int right = numsSize - 1;
    while(left < right)
    {
        int mid = (left + right) / 2;
        if (nums[mid] < nums[right])
            right = mid;
        else
            left = mid + 1;
    }
    return nums[left];//因为此时left与right的索引一致
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1516674.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTTP代理的特性、功能作用是什么样的?

在当今互联网时代&#xff0c;HTTP代理作为网络通信中的一项重要技术&#xff0c;在各行各业都有着广泛的应用。然而&#xff0c;对于许多人来说&#xff0c;HTTP代理的特性和功能作用并不十分清晰。在本文中&#xff0c;我们将深入探讨HTTP代理的各种特性和功能&#xff0c;帮…

Linux系统Docker部署Plik系统结合内网穿透实现公网访问本地文件

文章目录 1. Docker部署Plik2. 本地访问Plik3. Linux安装Cpolar4. 配置Plik公网地址5. 远程访问Plik6. 固定Plik公网地址7. 固定地址访问Plik 本文介绍如何使用Linux docker方式快速安装Plik并且结合Cpolar内网穿透工具实现远程访问&#xff0c;实现随时随地在任意设备上传或者…

jenkins+maven+gitlab自动化构建打包、部署

Jenkins自动化部署实现原理 环境准备 1、jenkins已经安装好 docker安装jenkins 2、gitlab已经安装好 docker安装gitlab 一、Jenkins系统配置 1.Global Tool Configuration 任务构建所用到的编译环境等配置&#xff0c;配置参考&#xff1a; jdk配置&#xff08;jenkins自带…

C# ListView 控件使用

1.基本设置 listView1.Columns.Add("序号", 60); //向 listView1控件中添加1列 同时设置列名称和宽度listView1.Columns.Add("温度", 100); //下同listView1.Columns.Add("偏移", 100);listView1.Columns.Add("分割", 50);listView1…

广州虚拟动力 | AI智能交互型虚拟数字人解决方案

广州虚拟动力整合自研的AI数字人技术与AI大语言模型技术&#xff0c;推出AI智能交互型虚拟数字人解决方案&#xff0c;面向旅游景区、博物馆、银行、医院、营业厅、酒店住宿、大型商场等&#xff0c;以AI数字人为载体&#xff0c;承担公共服务职能&#xff0c;根据各行业特性和…

学习Java的第十天

本章来讲一下什么是字符串 一、什么是字符串 在Java中&#xff0c;最常见的基本类型就是字符串了&#xff0c;哪哪都能见到&#xff0c;如输入语句&#xff0c;输出语句等&#xff01;那么&#xff0c;什么是字符串呢&#xff0c;字符串就是String类&#xff0c;String类是Ja…

1361:产生数(Produce)

【解题思路】 1、将数字拆分保存在数组中&#xff0c;而后转换每一位。 2、将数字变化规则保存在x、y两个一维数组中&#xff0c;x[i]到y[i]是一种转换规则。 3、从n的初始值开始搜索&#xff0c;对n做数字拆分&#xff0c;将拆分后的各位数字保存在一个数组中。针对数组中的每…

使用timm库的一些知识点

timm&#xff08;Torch Image Models&#xff09;是一个在PyTorch上构建的图像模型库&#xff0c;它提供了一系列预训练的深度学习模型&#xff0c;使得研究人员和开发者可以方便地进行图像分类、目标检测等任务。 使用timm库创建模型时&#xff0c;如何确定模型的名字 使用…

3-14八股文学习

八股学习是看别人面试被问到的问题&#xff0c;然后把它发给GPT&#xff0c;让gpt讲一讲&#xff0c;自己再理解一下&#xff0c;真的很想拿offer&#xff0c;想去暑期实习啊啊啊啊啊 你用过什么 SpringBoot 里的什么注解&#xff1f;Spring Boot 中有很多常用的注解&#xff…

Ele admin pro和iView Admin pro的用户管理页面对比

Ele admin pro和iView Admin pro都是非常优秀的B端框架&#xff0c;功能大同小异&#xff0c;本文就着重比对一下二者的用户案例页面&#xff0c;让老铁们感知一些细节。 一、用户列表 用户列表 用户列表 二、用户编辑 三、用户添加 四、角色管理 五、权限分配 六、角色添加

Web前端开发学习路线图

Web前端开发学习路线图可以为你提供一个明确的学习路径&#xff0c;帮助你逐步掌握Web前端开发的各项技能。以下是一个基本的学习路线图&#xff0c;你可以根据自己的实际情况进行调整和补充。 一、基础阶段 HTML&#xff1a;学习HTML的基本语法&#xff0c;了解HTML文档的结构…

【Linux网络】应用层协议——http协议

目录 HTTP协议 认识URL urlencode和urldecode HTTP协议格式 HTTP请求协议格式 获取浏览器的HTTP请求 HTTP响应协议格式 构建HTTP响应给浏览器 构建处理HTTP请求类及代码完善 HTTP的方法 GET方法和POST方法 HTTP的状态码 HTTP常见Header Cookie&Session HTT…

c++ 常用函数 集锦 整理中

c 常用函数集锦 目录 1、string和wstring之间转换 1、string和wstring之间转换 std::string convertWStringToString(std::wstring wstr) {std::string str;if (!wstr.empty()){std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;str converter.to_b…

java 数据结构 优先级队列(PriorityQueue)

目录 优先级队列 堆的概念 堆的性质 堆的存储方式 堆的创建 堆的插入 堆的删除 用堆模拟实现优先级队列 PriorityQueue的特性 PriorityQueue常用接口介绍 堆排序 优先级队列 前面介绍过队列&#xff0c;队列是一种先进先出(FIFO)的数据结构&#xff0c;但有些情况下…

【BUG 弹药库】Tortoise git 绿色的勾 ✔ 和 红色的 !突然不见了该如何解决呢?

文章目录 1. 出现的问题描述如下所示&#xff1a;2. 如何解决这个问题呢 &#xff1f; 1. 出现的问题描述如下所示&#xff1a; 用 TortoiseGit 提交代码的时候&#xff0c;红色的 ! 和 绿色的 ✔ 突然消失了&#xff1b; 2. 如何解决这个问题呢 &#xff1f; ① 首先按住快…

新版Android Studio火烈鸟 在新建项目工程时 无法选java的语言模板解决方法

前言 最近下载最新版androidstudio时 发现不能勾选java语言模板了 如果快速点击下一步 新建项目 默认是kotlin语言模板 这可能和google主推kt语言有关 勾选1 如图所示 如果勾选 No Activity 这个模板 是可以选java语言模板的 但是里面没有默认的Activity 勾选2 和以前的用法…

SL6015B 耐压60V高调光比LED驱动IC 支持1.5A 输出30W功率

SL6015B是一款耐压60V、高调光比LED驱动IC&#xff0c;支持1.5A输出电流&#xff0c;最大输出功率达到30W。这款驱动IC专为LED照明应用而设计&#xff0c;具有出色的性能表现和广泛的应用前景。 首先&#xff0c;SL6015B的高耐压能力使其能够适用于各种高电压的LED照明场合。无…

如何免费获取基于公网 IP 的 SSL 证书 (无需域名)

现在给网站安装SSL证书来实现网站的HTTPS安全访问已经成了大多数人的共识&#xff0c;但是有一些特殊情况&#xff1a;比如对于个别的应用IP地址不需要绑定域名&#xff0c;只是单纯用IP来访问网站&#xff0c;这种情况下&#xff0c;可以实现HTTPS访问吗&#xff1f; 先说答案…

python基础——列表【创建,下标索引,常见操作方法】

&#x1f4dd;前言&#xff1a; 这篇文章主要讲解一下python中常见的数据容器之一——列表 本文主要讲解列表的创建以及我们常用的列表操作方法 &#x1f3ac;个人简介&#xff1a;努力学习ing &#x1f4cb;个人专栏&#xff1a;C语言入门基础以及python入门基础 &#x1f380…

第十四届蓝桥杯省赛真题 Java 研究生 组【原卷】

文章目录 发现宝藏【考生须知】试题 A: 特殊日期试题 B: 与或异或试题 C: 棋盘试题 D: 子矩阵试题 E : \mathrm{E}: E: 互质数的个数试题 F: 小蓝的旅行计划试题 G: 奇怪的数试题 H: 太阳试题 I: 高塔试题 J \mathrm{J} J : 反异或 01 串 发现宝藏 前些天发现了一个巨牛的人…