DSA_02:复杂度分析

真正掌握了复杂度分析,可以说 DSA 便掌握了一小半。

复杂度分析分为:时间复杂度分析、空间复杂度分析。

时间复杂度的定义:

  并不是指代码执行的具体、确定时间。

  它表示的是一个算法执行效率与数据规模增长的变化趋势。

  即便代码需要执行成千上万次,只要它不随数据规模变化而变化,那么它的复杂度就是 O(1)。

空间复杂度的定义:
  类似的,它表示空间占用与数据规模增长的变化趋势

  同样,哪怕占用再多的空间,只要它不随数据规模变化而变化,那么它的复杂度就是 O(1)。

复杂度的两种表示方法:

  1. T(n) 表示法:表示算法随数据规模增长的确切公式,如:T(n) = 4n^2 + 3n + 2。

  2. O(n) 表示法:去掉 T(n) 中的常数和低量级,只留下最大的量级,如上式:O(n) = n^2。

  3. 同样,若 T(n) = 1000000n^2,O(n) 同样为 n^2。

  4. 最常用的 O(n) 表示法。

  5. 常数复杂度是 O(1),不存在 O(100),O(1000)等。

  6. 我们常说的复杂度 logn,其底数到底是多少呢?

    答:一般来说是 2 为底。如果是 5,7,10 等值为底,由高中数学换底公式知道,可以转化为 一个常数*以 2 为低的对数,因此可去掉常数。

以下给出一些常用的复杂度(这几乎包含了所有你会遇到的复杂度):

  由低至高:O(1)、O(logn)、O(n)、O(nlogn)、O(n^2)、O(n^3)、O(n^k)、O(2^n)、O(n!)。

  两个特殊的复杂度(由两个数据规模决定):O(m+n)、O(mn)。

  空间复杂度会比时间复杂度更简单,常用的有:O(1)、O(n)、O(n^2)

一般的复杂度分析笔者就不再啰嗦了,下面重点讲解一下复杂度分析中的:最好最坏平均均摊 时间复杂度

先看一个例子:从一个无序数组中查找某个值是否存在,若存在,则返回下标,否则返回 -1(以 C/C++ 代码给出,不涉及高级语法,相信完全可以看懂)。

// n 是数组大小
int find(int arr[], int n, int target)
{
    int pos = -1;
    for (int i = 0; i < n; ++i)
        if (arr[i] == target) pos = i;
    return pos;
}

你可以看出,需要遍历整个数组,其时间复杂度是 O(n),空间复杂度是 O(1)。

当然你肯定也看处问题了,这段代码可以优化,即找到后提前退出:

// n 是数组大小
int find(int arr[], int n, int target)
{
    int pos = -1;
    for (int i = 0; i < n; ++i)
    {
        if (arr[i] == target)
        {
            pos = i;
            break;
        }
    }
    return pos;
}

那么问题来了,优化后的时间复杂度还是 O(n) 吗??

现在引出主题:

  1. 最好时间复杂度:第一个元素就是我们要查找的,因此时间复杂度是 O(1)

  2. 最坏时间复杂度:最后一个元素是我们要查找的,或 target 不在数组内,时间复杂度 O(n)。

  3. 平均复杂度:

    要查找的变量在数组中的位置,有n+1种情况:在数组的0~n-1位置中和不在数组中。

    我们把每种情况下,查找需要遍历的元素个数累加起来,然后再除以n+1, 就可以得到需要遍历的元素个数的平均值,即:

      (1+2+3+...+n-1+n+n) / (n+1) = (n(n+3)) / (2(n+1))  即:O(n)

    前面的推导过程中存在的最大问题就是,没有将各种情况发生的概率考虑进去,如果 target 在数组中的概率为 1/2 会怎么样呢?1/3 呢? 1/5 呢?

    我们以 1/2 为例计算:

      (1 * 1/2n + 2 * 1/2n +...+ n * 1/2n + n * 1/2) = (3n+1) / 4  即:O(n)

    尽管上面方法得出的结果均为 O(n),但是我们需要根据实际情况,通常不能丢弃概率。

再看一个例子:有一个数组,当压入数据时数组空间不足了,就将数组扩大至原大小的两倍,将原数据拷贝到新数组中去。

这个操作复杂度是多少呢?

首先要明确:数组空间充足时,压入数组的时间复杂度为 O(1),当空间不足时,需要重新开辟空间,并将原有的 n 个数据拷贝过来,时间复杂度 O(n)。

但是怎么评估整体复杂度呢?

这就用到最后一点:均摊时间复杂度

将一次开辟消费的 O(n) 复杂度,均摊给后面 n-1 次的 O(1) 复杂度,不难得出,均摊复杂度为 O(1)。

这是很重要的复杂度分析方法,后续还会提及。

原文地址:https://www.cnblogs.com/teternity/p/DSA_02.html

时间: 2024-10-14 05:01:41

DSA_02:复杂度分析的相关文章

算法录 之 复杂度分析。

一个算法的复杂度可以说也就是一个算法的效率,一般来说分为时间复杂度和空间复杂度... 注意接下来说的均是比较YY的,适用与ACM等不需严格分析只需要大致范围的地方,至于严格的算法复杂度分析的那些数学证明,主定理什么的在<算法导论>这本书上有十分详细的讲解,网上应该也会有人写过,这里就不多说了(其实,是我不会而已o(╯□╰)o...). — 到底啥是复杂度呢?先来个栗子. 小明有10个苹果,有一天他饿了,然后准备吃掉一个苹果,但是小明有中二病,他要吃里面重量最大的那个,于是...他需要一个找到那

相似度分析的地址

相似度分析的,其中的分词可以采用HanLP即可: http://www.open-open.com/lib/view/open1421978002609.htm

Python 文本相似度分析

环境 Anaconda3 Python 3.6, Window 64bit 目的 利用 jieba 进行分词,关键词提取 利用gensim下面的corpora,models,similarities 进行语料库建立,模型tfidf算法,稀疏矩阵相似度分析 代码 # -*- coding: utf-8 -*- import jieba from gensim import corpora, models, similarities from collections import defaultdi

斐波那契数与二分法的递归与非递归算法及其复杂度分析

1. 什么是斐波那契数? 这里我借用百度百科上的解释:斐波那契数,亦称之为斐波那契数列(意大利语: Successione di Fibonacci),又称黄金分割数列.费波那西数列.费波拿契数.费氏数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.--在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=Fn-1+Fn-2(n>=2,n∈N*),用文字来说,就是斐波那契数列列由 0 和 1 开始,之后的斐波那契数列系数就由之前的两数相加.特别指出:0不是第一

递归算法复杂度分析方法

递归算法的复杂度分析方法. a.分析出复杂度公式(关于n的规模) b.求解这个公式 1.齐次 例如求fabonaci的第n项,f(n) = f(n-1)+f(n-2) => f(n)-f(n-1)-f(n-2)=0 =>特征方程:x^2-x-1=0 => x1,x2 => f(n)=a*x1n + b*x2n 2.master method T(n) = aT(n/b) + f(n) 3.采用分析树的方式 举个例子 f(n) = 2*f(n-1) + 1 1 1 ---------

杨辉三角(Pascal Triangle)的几种C语言实现及其复杂度分析

说明 本文给出杨辉三角的几种C语言实现,并简要分析典型方法的复杂度. 本文假定读者具备二项式定理.排列组合.求和等方面的数学知识. 一  基本概念 杨辉三角,又称贾宪三角.帕斯卡三角,是二项式系数在三角形中的一种几何排列.此处引用维基百科上的一张动态图以直观说明(原文链接http://zh.wikipedia.org/wiki/杨辉三角): 从上图可看出杨辉三角的几个显著特征: 1. 每行数值左右对称,且均为正整数. 2. 行数递增时,列数亦递增. 3. 除斜边上的1外,其余数值均等于其肩部两数

算法9-4:最大流算法复杂度分析

前面一节介绍了Ford-Fulkerson算法.那么这个算法是否一定能够在有限步骤内结束?要多少步骤呢? 这个问题的答案是,该算法确实能够在有限步骤之内结束,但是至于需要多少步骤,就要仔细分析. 为了分析问题,需要假定图中所有边的容量都是整数.但是有个严重的问题,比如下图中,如果使用Ford-Fulkerson算法,需要迭代200次才能结束. 首先将所有边的容量都初始化为0. 第一次迭代和第二次迭代之后,两条边各增加了1. 到最后200次迭代之后整个算法才结束. 这还不算最坏的情况.因为整数最多

比较排序算法及复杂度分析

比较排序算法分类 比较排序(Comparison Sort)通过对数组中的元素进行比较来实现排序. 比较排序算法(Comparison Sorts) Category Name Best Average Worst Memory Stability  插入排序  (Insertion Sorts) 插入排序 (Insertion Sort) n n2 n2 1 Stable 希尔排序 (Shell Sort) n n log2 n n log2 n 1 Not Stable  交换排序 (Exc

转 算法复杂度分析

转自 http://www.cnblogs.com/gaochundong/p/complexity_of_algorithms.html 为什么要进行算法分析? 预测算法所需的资源 计算时间(CPU 消耗) 内存空间(RAM 消耗) 通信时间(带宽消耗) 预测算法的运行时间 在给定输入规模时,所执行的基本操作数量. 或者称为算法复杂度(Algorithm Complexity) 如何衡量算法复杂度? 内存(Memory) 时间(Time) 指令的数量(Number of Steps) 特定操作