玩转算法面试--01(时间复杂度分析)

目录

1.前言

                  2.究竟什么是大O?

3.数据规模的概念

4.常见的复杂度的分析:

5.时间复杂度的测试

6.递归算法的时间复杂度:(最主要的是要计算递归的深度)

7.均摊复杂度的分析:


1.前言

玩转算法面试--01(时间复杂度分析)_第1张图片

 玩转算法面试--01(时间复杂度分析)_第2张图片

2.究竟什么是大O?

   如果对于一个算法来说n是他的数据规模,O(f(n))则表示运行算法所需要执行的指令数,和f(n)成正比。

  玩转算法面试--01(时间复杂度分析)_第3张图片

  玩转算法面试--01(时间复杂度分析)_第4张图片

 时间复杂度O 衡量的是一个量级上的差距,这种量级上的差距表现在当n突破了一个点的时候,时间复杂度底的算法就一定比时间复杂度高的算法要快。而且n越大这个优势就越明显

玩转算法面试--01(时间复杂度分析)_第5张图片

 所以当数据规模比较小的时候,前面的这个常数是有意义的。在学术界严格的来讲,O(f(n))表示的是算法执行的上界。在业界,我们就使用O来表示算法执行的最低上界。

例题:

   这个题有两个维度的变量 一个是数组内字符串的长度,一个是数组有多少个元素,这两个变量毫无关联。

玩转算法面试--01(时间复杂度分析)_第6张图片

 玩转算法面试--01(时间复杂度分析)_第7张图片

 3.数据规模的概念

玩转算法面试--01(时间复杂度分析)_第8张图片

 空间复杂度:

玩转算法面试--01(时间复杂度分析)_第9张图片

 玩转算法面试--01(时间复杂度分析)_第10张图片

 4.常见的复杂度的分析:

 玩转算法面试--01(时间复杂度分析)_第11张图片

O(n)级别的算法有一个很明显的特征就是有一个循环,并且循环的次数是和n相关的。

 玩转算法面试--01(时间复杂度分析)_第12张图片

 玩转算法面试--01(时间复杂度分析)_第13张图片

所执行的指令数和n^2是成正比关系的

 玩转算法面试--01(时间复杂度分析)_第14张图片

 玩转算法面试--01(时间复杂度分析)_第15张图片

 二分查找的时间复杂度就是O(logn)

玩转算法面试--01(时间复杂度分析)_第16张图片

分析:

玩转算法面试--01(时间复杂度分析)_第17张图片

 例子:

玩转算法面试--01(时间复杂度分析)_第18张图片

 玩转算法面试--01(时间复杂度分析)_第19张图片

 由于增量的特殊性,第一重循环将循环logn次,sz+=sz 其实就是sz=sz*2,就是n经过几次除以2等于1  所以时间复杂度为O(n*logn)

 玩转算法面试--01(时间复杂度分析)_第20张图片

 玩转算法面试--01(时间复杂度分析)_第21张图片

5.时间复杂度的测试

有没有什么算法帮助我们来判断我们写的程序到底是一个什么级别的算法?数据规模每次都翻倍,观察消耗时间。

时间复杂度为O(n)的算法

    // O(n)
    public static void test1(int n) {
        int i;
        int sum;
        for (i = 0; i < n; i++) {
            /*时间复杂度为O(1)的程序*/
            sum = (1 + i) * i / 2;
        }
    }

 测试代码:

        int n = 12;
        for (int i = 1; i < n; i++) {
            int pow = (int) Math.pow(2, i);
            long before = System.nanoTime();
            test1(pow);
            long after = System.nanoTime();
            long time = after - before;
            System.out.println("数据规模为2的" + i + "次方,消耗的时间为" + time);
        }

结果:

 从2的6次方开始,数据规模增大一倍,所消耗的时间增大一倍

玩转算法面试--01(时间复杂度分析)_第22张图片

其他复杂度的算法也可以按照这种方式测试

6.递归算法的时间复杂度:(最主要的是要计算递归的深度)

不是所有的递归算法的时间复杂度都是O(nlogn),对于递归算法时间复杂度要具体问题具体分析

 玩转算法面试--01(时间复杂度分析)_第23张图片

比如二分查找法:在每一次递归中,只进行了一次的递归调用,他的递归调用的深度就是logn,因为每次都对查找的数据减少一半,还有就是在这个函数中处理问题的时间复杂度是O(1) 的,所以整个算法的时间复杂度就是O(logn)

玩转算法面试--01(时间复杂度分析)_第24张图片

 继续分析:

 每次递归减少一个元素,递归的深度为0,所以这是一个O(n)的算法

玩转算法面试--01(时间复杂度分析)_第25张图片

 继续分析下面一个计算x的n次方的案例:这个函数的每次的数据规模都除以2,他的递归深度就是logn,函数中也没有其他复杂的操作,所以这个函数的时间复杂度为O(logn)

 通常情况下,我们计算x的n次方是用n个x连乘,这个时间复杂度是O(n)的,我们做了这样的改进后就相当于把时间复杂度优化为了O(logn)

玩转算法面试--01(时间复杂度分析)_第26张图片

 如果递归函数中一次调用存在两个递归那又该怎么计算时间复杂度呢?此时我们真正关心的是递归调用的次数。

玩转算法面试--01(时间复杂度分析)_第27张图片

 这个时候我们可以画出递归树:

玩转算法面试--01(时间复杂度分析)_第28张图片

 我们可以计算出这颗递归树有多少个节点:

玩转算法面试--01(时间复杂度分析)_第29张图片

 所以这个递归的时间复杂度就是O(2^n)级别的

 继续分析归并排序的时间复杂度:首先8个元素的时候他的递归树的层级是3而不是8,层级或者深度就是logn,对于每一层都是一样的多的元素,每层总体的元素都是8,每个节点都是O(n)级别的算法.所以总体来说每一层也都是O(n)级别的算法。最终整个算法的时间复杂度就是O(nlogn)

玩转算法面试--01(时间复杂度分析)_第30张图片

 

 7.均摊复杂度的分析:

  玩转算法面试--01(时间复杂度分析)_第31张图片

 

你可能感兴趣的:(数据结构,算法,面试,职场和发展)