算法—时间复杂度

正文

前言

数学跟我一样不好的同学可以看下附录。好的就不必看了。
另外文末Thanks标题下贴出的博客链接也是本篇博客的来源,在此感谢这些大佬们的知识分享。
个人水平有限,有错误还请指出,感谢。

概念:

学习具体的算法之前,我们要先搞清楚它里边的一些基本概念

  • 算法中的语句执行次数定义为频度。
  • 算法的运行时间刻画为一个函数,定义为 T(n) 。
  • n称为问题的规模,当n不断变化时,T(n)也随之变化。
  • 但我们想知道n与T(n)之间的大致规律,所以我们引入渐进符号 O 来刻画算法的运行时间。——>大O出现的原因。

常见的时间复杂度:

按增长量级递增排列,常见的时间复杂度有:

  • 常数阶O(1)
  • 对数阶O(log2n)
  • 线性阶O(n)
  • 线性对数阶O(nlog2n)
  • 平方阶O(n^2)
  • 立方阶O(n^3)
  • k次方阶O(n^k)
  • 指数阶O(2^n)

推导时间复杂度的依据

  • 1.用常数1来取代运行时间中所有加法常数。
  • 2.修改后的运行次数函数中,只保留最高阶项
  • 3.如果最高阶项存在且不是1,则去除与这个项相乘的常数。

练习:常数阶O(1)

   private static void 常数阶() {
        System.out.println("哈哈");//执行1次
        System.out.println("呵呵");//执行1次
        System.out.println("嘿嘿");//执行1次
    }

得出结果是O(3),根据原则1,得出最终结果是O(1)。

练习:线性阶O(n)

线性阶主要要分析单循环结构的运行情况。


    private static void 线性阶() {
        int n = 100;
        for (int i = 0; i < n; i++) {//执行 n 次 O(n)
            System.out.println("哈哈");//执行1次  O(1)
        }
    }

总体下来,这个算法的时间复杂度就是O(n),因为循环内部O(1)的执行语句随着n的执行次数而增长。

练习:平方阶O(n^2)

这个平方阶主角要是分析嵌套循环的情况,但是注意这个嵌套循环分析的思路分为俩种,比较绕的一种是第二层循环的值随着第一层循环形成一个等差数列的情况,我称他们为平民嵌套循环,和等差数列嵌套循环,名儿我自己取的,方便理解,所以不必纠结它的名字,主要看分析内容。

平民嵌套循环

    private static void 平民平方阶() {
        int n = 100;
        for (int i = 0; i < n; i++) {//执行n次
            for (int j = 0; j < n; j++) {//执行n次
                System.out.println("哈哈");
            }
        }
    }

这种就是2层循环嵌套起来,都是执行n次,属于乘方关系,它的时间复杂度为O(n^2)。

等差数列嵌套循环

    private static void 等差数列平方阶() {
        int n = 100;
        for (int i = 0; i < n; i++) {//执行n次
            for (int j = i; j < n; j++) {//执行n - i次
                System.out.println("哈哈");
            }
        }
    }

基本式:

  • i = 0,循环执行次数是 n 次。
  • i = 1,循环执行次数是 n-1 次。
  • i = 2,循环执行次数是 n-2 次。
  • ……
  • i = n-1,循环执行的次数是 1 次。

换算式:

  • result = n + (n - 1) + (n - 2) … + 1
  • 被加数递减,抽象为一个等差数列求n项和的问题,公差为1,带入公式,Sn = n(a1 + an ) ÷2
  • result = (n(n+1))/2
  • result = (n^2+n)/2
  • result = (n^2)/2 + n/2

粗略计算时间复杂度的三部曲:

  • 1.去掉运行时间中的所有加法常数。
    没有加法常数,不考虑。
  • 2.只保留最高阶项。
    最高阶参考上面列出的按增长量级递增排列,于是只需要保留result = (n^2)/2
  • 3.如果最高阶项存在且不是1,去掉与这个最高阶相乘的常数得到时间复杂度
    除以2相当于是乘以二分之一,去掉它,就得到,result = n^2,所以这个算法的时间复杂度为O(n^2)。

平方阶综上:

虽然结果都是O(n^2),但是思维过程不一样。所以要特别注意。

练习:对数阶O(log2n)

    private static void 对数阶() {
        int number = 1;//执行1次
        int n = 100;//执行1次

        while (number < n) {
            number = number * 2; // 执行n/2次
            System.out.println("哈哈");//执行1次
        }

    }

这里思考方式又不一样了。

假设n为100,number是1,小于100退出循环。

  • 第1次循环,number = 2,2^1。
  • 第2次循环,number = 4, 2^2。
  • 第3次循环,number = 8, 2^3。
  • 第x次循环,number = 2^x

也就是2^x=n得出x=log₂n。因此它的复杂度为O(logn)。

本文代码

https://github.com/zj614android/algorithm/blob/master/O.java

Thanks

时间复杂度:https://www.cnblogs.com/Bw98blogs/p/7168748.html
Veda 原型:http://www.nowamagic.net/librarys/veda/detail/2195
刘望舒的博客:https://blog.csdn.net/itachi85/article/details/54882603

附录

对数函数:

概念

  • a^x = N,(a>0 && a!=1),那么x即是以a为底,N的对数,记作
  • 其中a叫做对数的底数,N叫做真数

常用对数

自然对数

例1

例2

等差数列

概念

一般地,如果一个数列从第2项起,后一项与它的前一项的差等于同一个常数,那麽这个数列就叫做等差数列。
这个常数叫做等差数列的公差,公差通常用字母d表示。

例1:

  • {1,3,5,7,9} 公差为2
  • {5,15,25,35,45} 公差为10
  • {2,68,134,200,266} 公差为66
  • {5,5,5,5,5} 公差为0

等差数列的通项公式:

an = a1 + ( n –1 ) d

a为整个数列,n为下标索引,d为公差

等差数列的前n项和公式:

Sn = n(a1 + an ) ÷2

Sn表示前n项和,a为数列,n为下标索引。

例2、判断下面数列是不是等差数列?判断下面数列是不是等差数列?是的话求数列和。

{1,3,5,7,9,11,……197,199}

解析:是等差数列,公差是2。

根据通项公式变形:求项数n:

  • (n - 1)d = an - a1;
  • n - 1 = (an - a1)d;
  • n = (an - a1)d + 1;

得出项数: (199-1)÷2+1=100(项)

根据:Sn = n(a1 + an ) ÷2 >> 得出数列和:(1+199)×100÷2=10000

例3:已知等差数列3,6,9,12,……问273是第几项?573是第几项?

(273-3)÷3+1=91(项)
(573-3)÷3+1=191(项)

例4:已知等差数列2,6,10,14……122,问这个数列共有多少项?

(122-2)÷4+1=31项

猜你喜欢

转载自blog.csdn.net/user11223344abc/article/details/81485842