算法训练营(二) 复杂度分析、递归

算法效率的度量方法

所谓算法,是指基于特定的计算模型,旨在解决某一信息处理问题而设计的一个指令序列。

在程序编写前,需要依据统计方法对算法进行估算。

 

1.1 影响执行速度的因素

  • 算法采用的策略方案

  • 编译产生的代码质量

  • 问题的输入规模

  • 机器执行指令的速度

 

1.2 时间复杂度和空间复杂度

  • 基础概念:https://www.zhihu.com/question/21387264
  1. 写程序时需要分析时间和空间复杂度

  2. 掌握一两种编程工具,刻意练习到熟练

 

算法训练营(二) 复杂度分析、递归_第1张图片

算法训练营(二) 复杂度分析、递归_第2张图片

 

 

 

1.3 递归

分支转向是算法的灵魂;函数和过程及其之间的相互调用,是在经过抽象和封装之后,实现分支转向的一种重要机制;而递归则是函数和过程调用的一种特殊形式,即允许函数和过程进行自我调用

递归的价值在于,许多应用问题都可简洁而准确地描述为递归形式。以操作系统为例,多数文件系统的目录结构都是递归定义的。具体地,每个文件系统都有一个最顶层的目录,其中可以包含若干文件和下一层的子目录;而在每一子目录中,也同样可能包含若干文件和再下一层的子目录;如此递推,直至不含任何下层的子目录。

递归也是一种基本而典型的算法设计模式。这一模式可以对实际问题中反复出现的结构和形式做高度概括,并从本质层面加以描述与刻画,进而导出高效的算法。

 

 

1.3.1 线性递归

数组求和

1 int sum(int A[], int n) { //数组求和算法
2     if (1 > n) 
3         return 0; //直接计算
4     else //一般情况
5         return sum(A, n - 1) + A[n - 1]; 
6 } //O(1)*递归深度 = O(1)*(n + 1) = O(n)

由此实例,可以看出保证递归算法有穷性的基本技巧

首先判断并处理n = 0之类的平凡情况,以免因无限递归而导致系统溢出。这类平凡情况统称“递归基”(base case of recursion)。平凡情况可能有多种,但至少要有一种(比如此处),且迟早必然会出现。

 

线性递归

算法sum()可能朝着更深一层进行自我调用,且每一递归实例对自身的调用至多一次。于是,每一层次上至多只有一个实例,且它们构成一个线性的次序关系。此类递归模式因而称作“线性递归”(linear recursion),它也是递归的最基本形式。

 

减而治之

线性递归的模式,往往对应于所谓减而治之(decrease-and-conquer)的算法策略:递归每深入一层,待求解问题的规模都缩减一个常数,直至最终蜕化为平凡的小(简单)问题

 

 

 

1.3.2 递归分析

递归算法时间和空间复杂度的分析与常规算法很不一样,有其自身的规律和特定的技巧,以下介绍递归跟踪与递推方程这两种主要的方法。

 

递归跟踪

作为一种直观且可视的方法,递归跟踪(recursion trace)可用以分析递归算法的总体运行时间与空间。具体地,就是按照以下原则,将递归算法的执行过程整理为图的形式:

算法训练营(二) 复杂度分析、递归_第3张图片

 

递推方程

递归算法的另一常用分析方法,即递推方程(recurrence equation)法。

递归算法的另一常用分析方法,即递推方程(recurrence equation)法。与递归跟踪分析相反,该方法无需绘出具体的调用过程,而是通过对递归模式的数学归纳,导出复杂度定界函数的递推方程(组)及其边界条件,从而将复杂度的分析,转化为递归方程(组)的求解。

递归算法所消耗的空间量主要取决于递归深度。因其高度的抽象性和简洁性,递归已成为多数高级程序语言普遍支持的一项重要特性。

递归的时间复杂度求解

因为递归每一层的计算次数都是上一层需要计算次数的二倍,因此递归的时间复杂度是2的n次幂

 

 

 

1.3.3 leetcode习题

 

1. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶

思路

1.动态规划

爬到N阶,可以从第N-1阶爬1步,也可以从第N-2阶爬2步。也就是说到N阶的方式有f(N-1)+f(N-2)种方式(因为要么1步,要么2步),后面一次类推。可以看出这是个菲波那切数列。每次的结果都是前两次结果的总和。

答案:

class Solution {
public:
    int climbStairs(int n) {
        if(n<=2) return n;

        int res = 0, index = 2, i = 1, j = 2;
        while(index

算法训练营(二) 复杂度分析、递归_第4张图片

 

 

 

你可能感兴趣的:(数据结构)