【算法导论】笔记-第一部分 基础知识

第一部分 基础知识

第1章 算法基础

1.1 插入排序

  • 关键词:我们要排序的数。

  • 伪代码:我们使用最清晰,最简洁的表示方法来说明给定的算法。

    • 约定
      • 缩进表示块结构
      • while,for与repeat-until等循环结构以及if-else等条件结构与代码类似
      • //:表示该行后面部分是个注释
      • i=j=e:将e的值赋给变量i和j
      • 数组元素通过“数组名[下标]”的形式来访问
      • 复合数据通常被组织成对象,对象又由属性组成
      • 我们按值把参数传递给过程
  • INSERTION-SORT:插入排序的伪代码过程。

    for j = 2 to A.length
        key = A[j]
        //Insert A[j] into the sorted sequence A[1..j-1].
        i = j - 1
        while i > 0 and A[i] > key
            A[i+1] = A[i]
            i = i - 1
        A[i+1] = key
    

    A[1…n]:包含长度为n的要排序的一个序列。

    A.length:A中元素的数目n

  • 循环不变式:

    • 性质:
      • 初始化:循环之前它为真
      • 保持:下次迭代依然为真
      • 终止:循环终止时,不变式为我们提供有用的性质
  • python代码:

    def insert_sort(mylist):
        length = len(mylist) #获取列表长度
        for i in range(1,length):
             j = i - 1 #设置当前值前一个元素的标识    
             if(mylist[i] < mylist[j]): #如果当前值小于前一个元素,则将当前值作为一个临时变量存储,将前一个元素后移一位
                 temp = mylist[i]
                 mylist[i] = mylist[j]
                 j = j-1 #继续往前寻找,如果有比临时变量大的数字,则后移一位,直到找到比临时变量小的元素或者达到列表第一个元素
                 while j>=0 and mylist[j] > temp:
                     mylist[j+1] = mylist[j]
                     j = j-1
                 mylist[j+1] = temp #将临时变量赋值给合适位置
        return mylist
     
    mylist = [49,38,65,97,76,13,27,49]
    print(insert_sort(mylist))
    

1.2 分析算法

  • 输入规模:概念:输入规模的最佳概念依赖于研究的问题。

    问题量度
    排序,计算离散傅里叶变换输入中的项数
    两个整数相乘用二进制记号表示输入所需的总位数
    输入是一个图该图的顶点数和边数
  • 运行时间:是指执行的基本操作数或步数

  • 增长量级: θ ( n 2 ) \theta(n^2) θ(n2)

  • 插入排序的最坏情况运行时间: T ( n ) = θ ( n 2 ) T(n)=\theta(n^2) T(n)=θ(n2)

1.3 设计算法

1.3.1 分治法
  • 思想:将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,再合并这些子问题的解来建立原问题的解。
  • 步骤:分解,解决,合并

第2章 函数的增长

2.1 渐近记号

  • 渐近紧确线: θ \theta θ

    • 运行表达式 T ( n ) T(n) T(n)中n的最大次数项。例如: T ( n ) = 30 n 4 + 20 n 3 + 40 n 2 + 46 n + 100 T(n)=30n^4+20n^3+40n^2+46n+100 T(n)=30n4+20n3+40n2+46n+100,记为 T ( n ) = θ ( n 4 ) T(n)=\theta(n^4) T(n)=θ(n4)

    • 数学含义: f ( n ) f(n) f(n) g ( n ) g(n) g(n)同阶

    • 注意: θ ( g ( n ) ) \theta(g(n)) θ(g(n))的定义要求当n足够大时, g ( n ) g(n) g(n)非负

  • 渐近上界记号: O O O

    • 渐近地给出函数的上界
    • O ( g ( n ) ) = f ( n ) O(g(n))=f(n) O(g(n))=f(n)
    • 这个上界的阶越低,评估越精确,越有价值
    • 用作算法的最坏情况运行时间
  • 渐近下界记号: Ω \Omega Ω

    • 下界的阶越高,评估越精确,越有价值
    • Ω ( g ( n ) ) = f ( n ) \Omega(g(n))=f(n) Ω(g(n))=f(n)
  • 非渐近紧确上界: o o o

    • o ( g ( n ) ) = f ( n ) o(g(n))=f(n) o(g(n))=f(n)
    • 比渐近紧确上界阶数高
  • 非渐近紧确下界: ω \omega ω

    • ω ( g ( n ) ) = f ( n ) \omega(g(n))=f(n) ω(g(n))=f(n)
    • 比渐近紧确下界阶数低
    记号含义理解
    θ \theta θ紧确界相当于“=”
    O O O紧确上界相当于“ ⩾ \geqslant
    o o o非紧确上界相当于“>”
    Ω \Omega Ω紧确下界相当于“ ⩽ \leqslant
    ω \omega ω非紧确下界相当于“<”

2.2 标准记号与常用函数

  • 单调性

  • 向下取整与向上取整: x − 1 < ⌊ x ⌋ ⩽ x ⩽ ⌈ x ⌉ < x + 1 x-1<\lfloor x\rfloor \leqslant x\leqslant\lceil x\rceil<x+1 x1<xxx<x+1

  • 模运算: a m o d n = a − n ⌊ a / n ⌋ amodn=a-n\lfloor a/n\rfloor amodn=ana/n,商a/n的余数

  • 阶乘: n ! n! n!

  • 多重函数

  • 多重对数函数

  • 斐波那契数: F 0 = 0 F_0=0 F0=0

    F 1 = 1 F_1=1 F1=1

    F i = F i − 1 + F i − 2 F_i=F_{i-1}+F_{i-2} Fi=Fi1+Fi2


第3章 分治策略

  • 步骤:
    • 分解
    • 解决
    • 合并
  • 递归情况:当子问题足够大
  • 基本情况:当子问题足够小
  • 递归式:刻画分治算法的运行时间
  • 求解递归式的方法:
    • 代入法
    • 递归树法
    • 主方法

3.1 最大子数组

  • 例题: 买股票,使利益最大化

  • 思路:低价买进,高价卖出

  • 暴力解决问题:尝试每对可能的买进和卖出日期组合。n天中共有 ( 2 n ) (_2^n) (2n)种日期组合。运行时间为 Ω ( n 2 ) \Omega(n^2) Ω(n2)

  • 问题变换:寻找一段日期,使得从第一天到最后一天的股票净变值。问题转化为寻找A的和最大的非空连续子数组。称这样的连续子数组为最大子数组

  • 使用分治策略的求解方法:将子数组划分为两个规模尽量相等的子数组,分别求解两个子数组的最大子数组。

    FIND-MAX-CROSSING-SUBARRAY(A, low, mid, high)

    left-sum = 负无穷
    sum = 0
    for i = mid downto low
        sum = sum + A[i]
        if sum > left-sum
            left-sum = sum
            max-left = i
    
    right-sum = 负无穷
    sum = 0
    for j = mid + 1 to high
        sum = sum + A[j]
        if sum > right-sum
            right-sum = sum
            max-right = j
    return(max-left, max-right, left-sum + reght-sum)
    

    FIND-MAXIMUN-SUBARRAY(A, low, high)

    if high == low
        return(low, high, A[low])
    else mid=(low+high)/2的下限
        (left-low, left-high, left-sum) = FIND-MAXIMUM-SUBARRAY(A, low, mid)
        (right-low, right-high, right-sum) = FIND-MAXIMUM-SUBARRAY(A, mid+1, high)
        (cross-low, cross-high, cross-sum) = FIND-MAX-CROSSING-SUBARRAY(A, low, mid, high)
        if left-sum>=right-sum and left-sum>=cross-sum
            return (left-low, left-high, left-sum)
        elseif right-sum>=left-sum and right-sum>=cross-sum
            return (right-low, right-high, right-sum)
        else return (cross-low, cross-high, cross-sum)
    
  • python代码

    def FIND_MAX_CROSSING_SUBARRAY(A, low, mid, high):
        left_sum = 0
        sum = 0
        for i in range(low, mid):
            sum = sum + A[i]
            if sum > left_sum:
                left_sum = sum
        right_sum = 0
        sum = 0
        for j in range(mid+1, high):
            sum = sum + A[j]
            if sum > right_sum:
                right_sum = sum
        return left_sum, right_sum, left_sum + right_sum
    
    def FIND_MAXIMUM_SUBARRAY(A, low, high):
        if high == low:
            return low, high, A[low]
        else:
            mid = (low+high)//2
            left_low, left_high, left_sum = FIND_MAXIMUM_SUBARRAY(A, low, mid)
            right_low, right_high, right_sum = FIND_MAXIMUM_SUBARRAY(A, mid+1, high)
            cross_low, cross_high, cross_sum = FIND_MAX_CROSSING_SUBARRAY(A, low, mid, high)
        if left_sum>=right_sum and left_sum>=cross_sum:
            return left_low, left_high, left_sum
        elif right_sum>=left_sum and right_sum>=cross_sum:
            return right_low, right_high, right_sum
        else:
            return cross_low, cross_high, cross_sum
        
    B = [2,4,5,-3,-5,2,-6,2,7,-5,4,1,3,6,-9,-2,-4,8]
    B_low = 0
    B_high = 16
    B_mid = 8
    print(FIND_MAXIMUM_SUBARRAY(B, B_low, B_high))
    
  • 分治算法的分析

    • 运行时间:
      { θ , n = 1 2 T ( n / 2 ) + θ ( n ) , n > 1 \left\{ \begin{array}{c} \theta,n=1\\ 2T(n/2)+\theta(n),n>1 \end{array} \right. {θ,n=12T(n/2)+θ(n),n>1

3.2 矩阵乘法的Strassen算法

  • SQUARE-MATRIX-MULTIPLY(A,B)

    n = A.rows
    let C be a new n×n matrix
    for i = 1 to n
        for j = 1 to n
            Cij = 0
            for k = 1 to n
                Cij = Cij + aik * bkj
    return C
    
  • 运行时间: θ ( n 3 ) \theta(n^3) θ(n3)

  • 分治算法:

    • 伪代码:SQUARE-MATRIX-MULTIPLY-RECURSIVE(A,B)

      n = A.rows
      let C be a new n×n matrix
      if n == 1
          c11=a11 * b11
      else partition A, B, and C as in equations(4,9)
          C11=SQUARE-MATRIX-MULTIPLY-RECURSIVE(A11,B11) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A12,B21)
          C12=SQUARE-MATRIX-MULTIPLY-RECURSIVE(A11,B12) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A12,B22)
          C21=SQUARE-MATRIX-MULTIPLY-RECURSIVE(A21,B11) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A22,B21)
          C22=SQUARE-MATRIX-MULTIPLY-RECURSIVE(A21,B12) + SQUARE-MATRIX-MULTIPLY-RECURSIVE(A22,B22)
      return C
      
    • 运行时间:
      T ( n ) = { θ ( 1 ) , n = 1 8 T ( n / 2 ) + θ ( n 2 ) , n > 1 T(n)=\left\{ \begin{array}{c} \theta(1),n=1\\ 8T(n/2)+\theta(n^2),n>1 \end{array} \right. T(n)={θ(1),n=18T(n/2)+θ(n2),n>1

  • Strassen方法

    • 步骤:

      • 将输入矩阵A,B和输出矩阵C各分解为四个 n / 2 × n / 2 n/2\times n/2 n/2×n/2的子矩阵。
      • 创建10个 n / 2 × n / 2 n/2\times n/2 n/2×n/2的空矩阵 S 1 , S 2 , ⋅ ⋅ ⋅ , S 10 S_1,S_2,···,S_{10} S1,S2,,S10,每个矩阵保存步骤1中创建的两个子矩阵的和与差。花费时间为 θ ( n 2 ) \theta(n^2) θ(n2)
      • 用步骤1中创建的子矩阵和步骤2中创建的10个矩阵,递归地计算7个矩阵积 P 1 , P 2 , ⋅ ⋅ ⋅ , P 7 P_1,P_2,···,P_7 P1,P2,,P7。每个矩阵 P i P_i Pi都是 n / 2 × n / 2 n/2\times n/2 n/2×n/2的。
      • 通过 P i P_i Pi矩阵的不同组合进行加减运算,计算出结果矩阵C的子矩阵 C 11 , C 12 , C 21 , C 22 C_{11},C_{12},C_{21},C_{22} C11,C12,C21,C22。花费时间 θ ( n 2 ) \theta(n^2) θ(n2)
    • 运行时间:
      T ( n ) = { θ ( 1 ) , n = 1 7 T ( n / 2 ) + θ ( n 2 ) , n > 1 T(n)=\left\{ \begin{array}{c} \theta(1),n=1\\ 7T(n/2)+\theta(n^2),n>1 \end{array} \right. T(n)={θ(1),n=17T(n/2)+θ(n2),n>1

3.3 用代入法求解递归式

  • 代入法求解递归式:
    • 步骤:
      • 猜测解的形式
      • 用数学归纳法求出解中的常数,并证明解是正确的
  • 做出好的猜测
  • 避免陷阱
  • 改变变量

3.4 用递归树方法求解递归式

  • 递归树中,每个结点表示一个单一子问题的代价,子问题对应某次递归函数调用。创建递归树之后,对树的每层的各子问题的代价进行求和,得到每一层的代价,然后将所有层的代价加起来,得到整棵递归树的总代价,这个总代价就是递归式的解。

3.5 用主方法求解递归式

  • 主定理:令 a≥1和b>1是常数, f ( n ) f(n) f(n)是一个函数, T ( n ) T(n) T(n)是定义在非负整数上的递归式: T ( n ) = a T ( n / b ) + f ( n ) T(n) = aT(n/b) + f(n) T(n)=aT(n/b)+f(n)

第4章 概率分布和随机分布

4.1 雇用问题

  • 题目:代理公司帮你物色办公助理候选人,面试一个候选人支付代理公司1K。

  • 策略:在面试完每个应聘者后,如果该应聘者比目前的办公助理更合适,就辞退当前的办公助理,然后雇佣新的。

  • 伪代码:HIRE-ASSISTANT(n)

    best = 0
    for i = 1 to n
        interview candidate i
        if candidate i is better than candidate best
            best = i
            hire candidate i
    
  • 最坏情形分析:当应聘者质量按出现次序严格递增时。此时雇佣n次,总费用为 O ( c k n ) O(c_kn) O(ckn)

  • 概率分析:对所有可能输出产生的运行时间取平均。称其为平均情况运行时间

  • 随机算法:一般地,如果一个算法的行为不仅由输入决定,而且也由随机数生成器产生的数字决定,则称这个算法是随机的

4.2 指示器随机变量

  • 指示器随机变量:
    I A = { 1 , A 发 生 0 , A 不 发 生 I{A}=\left\{ \begin{array}{c} 1,A发生\\ 0,A不发生 \end{array} \right. IA={1,A0,A

  • 给定一个样本空间S和S中的一个时间A,设 X A = I { A } X_A=I\{A\} XA=I{A},那么 E [ X A ] = P r { A } E[X_A]=Pr\{A\} E[XA]=Pr{A}

  • 用指示器随机变量分析雇用问题问题:
    X ( i ) = I { 应 聘 者 i 被 雇 佣 } = { 1 , 应 聘 者 i 被 雇 用 0 , 应 聘 者 i 不 被 雇 用 X(i)=I\{应聘者i被雇佣\}=\left\{ \begin{array}{c} 1,应聘者i被雇用\\ 0,应聘者i不被雇用 \end{array} \right. X(i)=I{i}={1,i0,i

  • E [ X ] = ln ⁡ n + O ( 1 ) E[X]=\ln n+O(1) E[X]=lnn+O(1),平均只雇用 ln ⁡ n \ln n lnn个人

4.3 随机算法

  • 思想:随机排列应聘者,以加强所有排序都是等可能出现的性质。

  • 伪代码:RANDOMIZED-HIRE-ASSISTANT(n)

    randomly permute the list of candidates
    best = 0
    for i = 1 to n
        interview candidate i
        if candidate i is better than candidate best
            best = i
            hire candidate i
    
  • 随机排列数组:

    • 方法一:为数组的每个元素 A [ i ] A[i] A[i]赋一个随机的优先级 P [ i ] P[i] P[i],然后依据优先级对数组A中的元素进行排序。
      • 伪代码:PERMUTE-BY-SORTING(A)
    n = A.length
    let P[1..n] be a new array
    for i = 1 to n
        P[i] = RANDOM(1,n^3)
    sort A, using P as sort keys
    
    • 方法二:原址排列给定数组

      • 伪代码:RANDOMIZE-IN-PLACE(A)

        n = A.length
        for i = 1 to n
            swap A[i] with A[RANDOM(i,n)] 
        
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

From Star.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值