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

文章目录

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


题目

链接: 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的索引一致
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Python】科研代码学习:二 dataclass,pipeline

【Python】科研代码学习&#xff1a;二 dataclass&#xff0c;pipeline 前言dataclasspipeline 前言 后文需要学习一下 transformers 库&#xff0c;必要时会介绍其他相关的重要库和方法。主要是从源代码、别人的技术文档学习&#xff0c;会更快些。 dataclass Python中的数…

AHU 汇编 实验五

实验名称&#xff1a;实验五 分支与循环程序设计 二、实验内容&#xff1a;从键盘输入一个四位的16进制数&#xff08;其中字母为大写&#xff09;&#xff0c;将其转化为二进制数提示输出。 实验过程&#xff1a; 源代码: data segmentbuff1 db Please input a number(H):$b…

CSS 02

1.复合选择器 &#xff08;1.1&#xff09;后代选择器 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0&q…

C++实现引用计数(二)

实现引用计数 引言实现集成开发环境项目结构实现代码运行结果 注意 引言 C中经常使用智能指针来管理内存。对于共享指针shared_ptr的原理&#xff1a;每当有一个指针指向这块内存&#xff0c;引用计数的值加一&#xff0c;每当一个指针不再指向这块内存&#xff0c;引用计数的…

CircuitBreaker断路器(服务熔断,服务降级)

分布式系统面临的问题: 复杂分布式体系结构中的应用程序有数十个依赖关系&#xff0c;每个依赖关系在某些时候将不可避免地失败。 1.服务雪崩 多个微服务之间调用的时候&#xff0c;假设微服务A调用微服务B和微服务C&#xff0c;微服务B和微服务C又调用其它的微服务&#xff…

【代码随想录】【二叉树】day18:二叉树的左下角的值,路径总和、构造二叉树

1二叉树左下角的值 左下角的值&#xff1a;最后一层最左侧的节点的值 递归 from collections import deque class TreeNode:def __init__(self,val,leftNone,rightNone):self.val valself.left leftself.right rightclass solution:def leftBottomNode(self,root):self.m…

计算机网络-第4章 网络层(1)

主要内容&#xff1a;网络层提供的两种服务&#xff1a;虚电路和数据报&#xff08;前者不用&#xff09;、ip协议、网际控制报文协议ICMP、路由选择协议&#xff08;内部网关和外部网关&#xff09;、IPv6,IP多播&#xff0c;虚拟专用网、网络地址转换NAT&#xff0c;多协议标…

C++作业day1

2> 试编程 提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数 要求使用C风格字符串完成 #include <iostream> #include <string.h>using namespace std;int main() {string str;cout << "请输…

文档版面分析数据集整理

版面分析数据集 这里整理了常用版面分析数据集&#xff0c;持续更新中&#xff1a; publaynet数据集CDLA数据集TableBank数据集D4LA 数据集DocLayNet文档布局分割数据集M6Doc数据集 版面分析数据集多为目标检测数据集&#xff0c;除了开源数据&#xff0c;用户还可使用合成工…

应用方案丨 D55125ADA A型漏电保护芯片

一、应用领域 新能源充电桩&#xff08;充电枪&#xff09;、智能空开&#xff08;智能微断开关&#xff09;等工业产品&#xff0c;以及电热水器、电烤箱、电烤炉等小家电产品。 二、功能介绍 D55125ADA 是一款高性能 CMOS 漏电保护器专用电路。芯片内部包含稳压电源、放大电…

【CSP试题回顾】201609-3-炉石传说

CSP-201609-3-炉石传说 解题思路 1.类和结构定义 Servant&#xff1a;定义了随从的结构&#xff0c;包含攻击力&#xff08;attack&#xff09;和生命值&#xff08;health&#xff09;。 MyPlayer&#xff1a;定义了玩家的类&#xff0c;包含玩家英雄的生命值&#xff08;h…

GRC宝石实验室鉴定证书,你真的读懂了吗?

随着人们审美需求的提升,兼具审美价值和收藏价值的彩色宝石成为越来越多人的心头好,市面上也随之涌现出许多宝石鉴定机构。在众多选择中,GRC宝石实验室以其高速度、专业化和高标准等诸多优势,成为许多宝石爱好者信赖的选择。 熟悉彩石圈的人,几乎都知道GRC宝石实验室,其总部位于…

网络模块使用Hilt注入

retrofit的异步回调方法已经做了线程切换&#xff0c;切换到了主线程 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android"><uses-permission android:name"andr…

中医把脉笔记

目录 寸关尺对应的五脏六腑把脉的时间、姿势、指法自己给自己把脉把脉五步法定寸关尺分浮中沉分快慢辨阴阳看虚实 参考文章 寸关尺对应的五脏六腑 把脉的时间、姿势、指法 时间&#xff1a;应选在清晨病人未活动时&#xff0c;若病人活动&#xff0c;应休息15分钟左右再进行脉…

不会用虚拟机装win10?超详细教程解决你安装中的所有问题!

前言&#xff1a;安装中有任何疑问&#xff0c;可以在评论区提问&#xff0c;博主身经百战会快速解答小伙伴们的疑问 BT、迅雷下载win10镜像&#xff08;首先要下载win10的镜像&#xff09;&#xff1a;ed2k://|file|cn_windows_10_business_editions_version_1903_updated_sep…

前端开发的发展史:框架与技术栈的演变

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

开发跨平台 App 推荐 React Native 还是 Flutter?

Hello大家好我是咕噜铁蛋&#xff01;今天我要和大家一起探讨一个备受关注的话题&#xff1a;“开发跨平台 App 推荐 React Native 还是 Flutter&#xff1f;”在移动应用开发领域&#xff0c;选择合适的跨平台开发框架对于开发者来说至关重要。而React Native和Flutter作为两种…

eclipse maven 项目导入报错

错误&#xff1a;Internal compiler error: java.lang.NullPointerException at org.eclipse.jdt.internal.compiler.apt.dispatch.AnnotationDiscoveryVisitor 环境&#xff1a;eclipse Kepler Service Release 2 ,JDK1.7 解决办法&#xff1a;编码不对&#xff0c;修改

微信视频号视频下载全攻略:轻松保存至手机的步骤!

微信视频号已经成为了我们获取信息、分享生活的重要平台。其中丰富的短视频内容&#xff0c;让我们流连忘返。然而&#xff0c;有时我们想要将这些精彩瞬间保存到手机&#xff0c;以便日后观看或分享&#xff0c;那么如何操作呢&#xff1f;本文将详细解析微信视频号保存视频到…

ceph跨集群迁移ceph pool rgw

1、跨集群迁移ceph pool rgw 我这里是迁移rgw的pool l老环境 [rootceph-1 data]# yum install s3cmd -y [rootceph-1 ~]# ceph config dump WHO MASK LEVEL OPTION VALUE RO mon advanced au…