【数据结构】 算法的时间复杂度和空间复杂度 (上)(附leetcode练习题)

这篇具有很好参考价值的文章主要介绍了【数据结构】 算法的时间复杂度和空间复杂度 (上)(附leetcode练习题)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

☃️个人主页:fighting小泽
🌸作者简介:目前正在学习C语言和数据结构
🌼博客专栏:数据结构
🏵️欢迎关注:评论👊🏻点赞👍🏻留言💪🏻

1.算法效率

1.1 如何衡量一个算法的好坏

如何衡量一个算法的好坏呢?比如对于以下斐波那契数列:

long long Fib(int N)
{
 if(N < 3)
 return 1;
 
 return Fib(N-1) + Fib(N-2);
}

斐波那契数列的递归实现方式非常简洁,但简洁一定好吗?那该如何衡量其好与坏呢?

1.2 算法的复杂度

算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。
时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间
。在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。

注意:在不同的计算机上执行相同的代码也会因为计算机硬件的不同而花费不同的时间。
比如我们进行一个数量较多的冒泡排序,在 i3,1g内存的机器和 i9,16g内存的机器上花费的时间肯定不同

2.时间复杂度

2.1时间复杂度的概念

时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个分析方式。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。

即:找到某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度。

请计算一下Func1中++count语句总共执行了多少次?
void Func1(int N)
{
int count = 0;
for (int i = 0; i < N ; ++ i)
{
 for (int j = 0; j < N ; ++ j)
 {
 ++count;
 }
}
 
for (int k = 0; k < 2 * N ; ++ k)
{
 ++count;
}
int M = 10;
while (M--)
{
 ++count;
 }
 printf("%d\n", count);
}

Fun进行了一次N * N 的循环,一次 2*N 的循环和一次 10 次的循环
即 Fun=(N * N) + (2 * N) + 10

  • 当 N = 10 , F(N) = 130
  • 当 N = 100 , F(N) = 10210
  • 当 N = 1000 ,F(N) = 1002010

我们发现,随着N的增大,后面项对结果的影响越小,所以实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里我们使用大O的渐进表示法

2.2 大O的渐进表示法

大O符号(Big O notation):是用于描述函数渐进行为的数学符号。
推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
使用大O的渐进表示法以后,Func1的时间复杂度为:**O(N^2)

N = 10 F(N) = 100
N = 100 F(N) = 10000
N = 1000 F(N) = 1000000
通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。

练习1:

计算Func2的时间复杂度?
void Func2(int N)
{
 int count = 0;
 for (int k = 0; k < 2 * N ; ++ k)
 {
 ++count;
 }
 int M = 10;
 while (M--)
 {
 ++count;
 }
 printf("%d\n", count);
}

Fun2一共执行了2n+10次,所以它的时间复杂度是O(N)

练习2:

计算Func3的时间复杂度?
void Func3(int N, int M)
{
 int count = 0;
 for (int k = 0; k < M; ++ k)
 {
 ++count;
 }
 for (int k = 0; k < N ; ++ k)
 {
 ++count;
 }
 printf("%d\n", count);
}

Fun3一共执行了M+N次,由于我们不知道M和N的关系,可能M特别大,可能N特别大,也可能它俩一样大,M和N都会影响整个程序运行的时间,而M和N又是未知的,所以Fun3的时间复杂度是O(M+N)

练习3:

计算Func4的时间复杂度?
void Func4(int N)
{
 int count = 0;
 for (int k = 0; k < 100; ++ k)
 {
 ++count;
 }
 printf("%d\n", count);
}

Fun4执行了100次,为常数次,所以它的时间复杂度为O(1)

练习4:

计算strchr的时间复杂度?
const char * strchr ( const char * str, int character );

strchr就是用来从一个字符串中找某个特定的字符,可能一开始就找到了,也可能很久都没找到,但是我们在求时间复杂度的时候一般都是按照最坏打算来求的,也就是未知N次。它的时间复杂度为O(N)

补充

有些算法的时间复杂度存在最好、平均和最坏情况:
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)
例如:在一个长度为N数组中搜索一个数据x
最好情况:1次找到
最坏情况:N次找到
平均情况:N/2次找到
在实际中一般情况关注的是算法的最坏运行情况,所以数组中搜索数据时间复杂度为O(N)
所以一般我们要降低预期,用底线思维

练习5:

计算BubbleSort的时间复杂度?
void BubbleSort(int* a, int n)
{
 assert(a);
 for (size_t end = n; end > 0; --end)
 {
 int exchange = 0;
 for (size_t i = 1; i < end; ++i)
 {
 if (a[i-1] > a[i])
 {
 Swap(&a[i-1], &a[i]);
 exchange = 1;
 }
 }
 if (exchange == 0)
 break;
 }
}

在冒泡排序中会从第一个数开始不断的进行两个数的比较,然后不断的把大数排在后面,所以每次比较的次数会减一,所以冒泡排序整体进行的次数为一个等差数列,用等差数列公式即 N * (1+N) / 2。它的最高项为N ^ 2,所以冒泡排序的时间复杂度为O(N ^ 2).

练习6:


计算strchr的时间复杂度?
const char * strchr ( const char * str, int character );
// 计算BubbleSort的时间复杂度?
void BubbleSort(int* a, int n)
{
 assert(a);
 for (size_t end = n; end > 0; --end)
 {
 int exchange = 0;
 for (size_t i = 1; i < end; ++i)
 {
 if (a[i-1] > a[i])
 {
 Swap(&a[i-1], &a[i]);
 exchange = 1;
 }
 }
 if (exchange == 0)
 break;
 }
}
// 计算BinarySearch的时间复杂度?
int BinarySearch(int* a, int n, int x)
{
 assert(a);
 int begin = 0;
 int end = n-1;
 // [begin, end]:begin和end是左闭右闭区间,因此有=号
 while (begin <= end)
 {
 int mid = begin + ((end-begin)>>1);
 if (a[mid] < x)
 begin = mid+1;
 else if (a[mid] > x)
 end = mid-1;
 else
 return mid;
 }
 return -1;
}

二分查找就是每次除以2嘛,2 ^ x = n,则 x = log n 。时间复杂度就为O(logN)。

注意:当我们想在一个有序数列找一个特别大的数时,暴力查找可能要进行几百万或者几亿次查找,而二分查找只用几十次就可以了(有没有感觉二分查找很厉害)
注:qsort的时间复杂度为(N*logN),后面我们会讲到的

【数据结构】 算法的时间复杂度和空间复杂度 (上)(附leetcode练习题)
练习7:

 计算阶乘递归Fac的时间复杂度?
long long Fac(int N)
{
 if(0 == N)
    return 1;
 for(int i = 0;i < n; i++)
 {
   //....
 }
 
 return Fac(N-1)*N;
}

Fac一共进行N次递归,每次递归会进行N(当前的N)次循环,即进行1次,2次…N次循环,所以它的本质也是一个等差数列,时间复杂度为O(N^2)
【数据结构】 算法的时间复杂度和空间复杂度 (上)(附leetcode练习题)

2.3 leetcode练习题

数组nums包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?力扣 ,消失的数字

方法1

我们可以把整个数组进行排序,然后遍历。如果下一个数不是上一个数+1,则上一个数+1就是消失的数,这个方法大家可以自己尝试一下,我们就不写了

方法2(重点)

异或法:首先将sums所有的数进行异或(^)得到number1,number1再异或从0~n的数字得到number2,则得到的number2就是最终消失的那个数

int missingNumber(int* nums, int numsSize){
    int i=0;
    int x=0;
    for(i=0;i<numsSize;i++)
    {
        x ^=nums[i];
    }
    for(i=0;i<numsSize+1;i++)
    {
        x ^= i;
    }
    return x;
}

方法3

等差数列求和法:我们可以通过等差数列求出0—n的值,然后减去数组的每一个元素,剩下的就是消失的数字

int missingNumber(int* nums, int numsSize)
{     
    int add_1 = 0;
    int add_2 = 0;
    add_1 = ( (0 + numsSize) * (numsSize + 1) ) / 2;
    for(int i = 0; i < numsSize; i++)
    {
         add_2 += nums[i];
    }
    return add_1 - add_2;
}

结尾

这些就是我给大家分享的关于算法的复杂度的知识啦,希望我们都能有所收获
先赞后看,养成习惯!!^ _ ^
码字不易,大家的支持就是我坚持下去的动力,点赞后不要忘了关注我哦!

如有错误,还请您批评改正(。ì _ í。)文章来源地址https://www.toymoban.com/news/detail-412649.html

到了这里,关于【数据结构】 算法的时间复杂度和空间复杂度 (上)(附leetcode练习题)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构与算法—时间复杂度和空间复杂度

    目录 1、什么是数据结构? 2、什么是算法? 3、算法的复杂度 4、时间复杂度 (1) 时间复杂度的概念:  (2) 大O的渐进表示法:  六个例题: (3) 时间复杂度对比:  三个例题:  OJ题分析时间复杂度 5、空间复杂度 (1)常见复杂度对比  (2)OJ题分析空间复杂度 小结 数据结构 (D

    2024年02月07日
    浏览(39)
  • 【数据结构与算法篇】时间复杂度与空间复杂度

       目录 一、数据结构和算法 1.什么是数据结构?  2.什么是算法? 3.数据结构和算法的重要性 二、算法的时间复杂度和空间复杂度 1.算法效率 2.算法的复杂度 3.复杂度在校招中的考察 4.时间复杂度 5.空间复杂度  6.常见复杂度对比 7.复杂度的OJ练习   👻内容专栏:《数据结

    2023年04月24日
    浏览(47)
  • 数据结构 | 算法的时间复杂度和空间复杂度【详解】

    数据结构(Data Structure)是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。 算法(Algorithm):就是定义良好的计算过程,他取一个或一组的值为输入,并产生出一个或一组值作为输出。简单来说算法就是一系列的计算步骤,用来将输入数据转

    2024年02月08日
    浏览(34)
  • 【数据结构与算法】1.时间复杂度和空间复杂度

    📚博客主页:爱敲代码的小杨. ✨专栏:《Java SE语法》 ❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️ 🙏小杨水平有限,欢迎各位大佬指点,相互学习进步! 算法效率分为两种:第一种是时间效率;第二种是空间效率。时间效率又称为时间

    2024年01月20日
    浏览(35)
  • 学习数据结构:算法的时间复杂度和空间复杂度

    衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。 时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间。 算法的时间复杂度 算法中的基本操作的执行次数,为算法的时间复杂度。 算法的

    2024年04月11日
    浏览(32)
  • 【数据结构与算法篇】之时间复杂度与空间复杂度

    ❤️博客主页: 小镇敲码人 🍏 欢迎关注:👍点赞 👂🏽留言 😍收藏 🌞友友们暑假快乐,好久不见呀!!!💖💖💖 🍉 有人曾经问过我这样一个问题,“人终其一身,执着追求的东西究竟是什么?”我是这样回答的,”我们终其一生都在寻找着那个和我们灵魂极其契合

    2024年02月12日
    浏览(33)
  • 【数据结构初阶】算法的时间复杂度和空间复杂度

    1.1 如何衡量一个算法的好坏 如何衡量一个算法的好坏呢? 比如对于以下斐波那契数列: 斐波那契数列的递归实现方式非常简洁,但简洁一定好吗?那该如何衡量其好与坏呢? 1.2 算法的复杂度 算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此

    2024年02月08日
    浏览(36)
  • 从头开始:数据结构和算法入门(时间复杂度、空间复杂度)

        目录 文章目录 前言 1.算法效率 1.1 如何衡量一个算法的好坏 1.2 算法的复杂度 2.时间复杂度  2.1 时间复杂度的概念 2.2 大O的渐进表示法 2.3常见时间复杂度计算 3.空间复杂度 4.常见复杂度对比 总结 前言         C语言的学习篇已经结束,今天开启新的篇章——数据结构

    2024年02月14日
    浏览(39)
  • 数据结构——算法的时间复杂度

    🌇个人主页:_麦麦_ 📚今日名言: 生命中曾经有过的所有灿烂,都终究需要用寂寞来偿还。 ——《百年孤独》 目录 一、前言 二、正文         1.算法效率                 1.1如何衡量一个算法的好坏                 1.2算法的复杂度         2. 时间复杂度      

    2024年02月03日
    浏览(29)
  • 算法之时间复杂度---数据结构

    目录 前言: 1.时间复杂度 1.1时间复杂度的理解 1.2规模与基本操作执行次数 1.3大O渐进表示法 1.4计算基本操作的次数 2.常见的时间复杂度及其优劣比较 ❤博主CSDN:啊苏要学习     ▶专栏分类:数据结构◀   学习数据结构是一件有趣的事情,希望读者能在我的博文切实感受到

    2024年02月05日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包