算法分析与设计 期末总结

一、算法及基础

  • 排序
    • 冒泡、插入、归并、桶排序,稳定
    • 选择、希尔、堆、快速、组合,不稳定
  • 伪代码
    • 循环后跟do
    • if后跟then
  • 算法:对特定问题求解步骤的一种描述,是若干条指令的有穷序列
    • 特性
      • 输入(0个或多个)
      • 输出(至少一个)
      • 确定性(无歧义)
      • 有限性
  • 程序:是算法用某种程序设计语言的具体实现
  • 算法求解一般过程
    • 理解问题
    • 设计算法:选择数据结构,算法策略
    • 证明正确性
    • 分析算法
    • 设计程序
  • 算法分析:事后统计、事前分析
    • O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(2n)<O(n!)<O(n^n)
    • 渐进上界 O
    • 渐近下界 Ω
    • 渐近精确界 Θ

二、分治

  • 基本思想:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之
  • 正确性证明:
    • 循环不变量 (初始化、迭代、终止)
    • 结构归纳
  • 二分查找
    • 时间复杂度 O(logn)
    • 空间复杂度 非递归O(1) 递归O(logn)
  • 循环日程赛
    • n=2^k个选手,递归将选手分为两半
ROUND-ROBIN-CALENDAR-REC(A,n)
    if n == 1
        then A[1][1] = 1
        return
    ROUND-ROBIN-CALENDAR-REC(A,n/2)
    COPY(n,A)
        
COPY(n,A)
    m = n/2
    for i = 1 to m
        for j = 1 to m
            do A[i][j+m] = A[i][j] + m;  //左 加上m 到右上
               A[i+m][j] = A[i][+m];     // 右上 到 左下 
               A[i+m][j+m] = A[i][j];    // 左上到右下
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(logn)
  • 快排
    • 第一部分元素均不大于基准元素,第二个是基准元素,第三部分元素均不小于基准元素
    • 基准元素的选取
      • 取第一个
      • 取最后一个
      • 取中间位置
      • 三者取中
      • 随机
QUICK-SORT(A,low,high)
    if low < high
        then mid = PARTITION(A,low,high) // 划分序列
        QUICK-SORT(A,low,mid-1)
        QUICK-SORT(A,mid+1,high)
        
PARTITION(A,low,high)
     i = low
     j = high
     mid = A[low]
     while i < j
         do 
             while i < j &&  A[j] >= mid
                 do j--
             while i < j &&  A[i] <= mid
                 do i++
             if i < j
                 then tmp = A[i]
                      A[i] = A[j]
                      A[j] = tmp
     A[low] = A[i]
     A[i] = mid
     return i       
  • 时间复杂度:最好,平均 O(nlogn) 最坏O(n^2)
  • 空间复杂度:最好,平均 O(logn) 最坏O(n)

三、动态规划

  • 基本性质
    • 最优子结构 :问题最优解包含其子问题的最优解。为动态规划的基础。
    • 子问题重叠:解决冗余
  • 基本要素:自底向上
  • 求解步骤
    • 分析最优解性质,是否具备最优子结构
    • 递归定义最优值 (状态转移方程)
    • 自底向上求出最优值
    • 构造最优解
  • 矩阵连乘
//m[1..n][1..n]二维数组记录最优值,s[][]记录最优解
DP(n,P)
    for i = 1 to n
        do m[i] = 0
    for l = 2 to n  // 区间长度 m[i][j] j-i+1 = l
        do for i = 0 to n-l+1 // 起点
            do j = i+l-1 // 终点
               m[i][j] = m[i][i]+m[i+1][j]+p[i-1]p[i][j]
               s[i][j] = i
               for k = i+1 to j-1 // 分割点k
                   do q = m[i][k] + m[k+1][j] + P[i-1]P[k]P[j]
                   if q < m[i][j]
                       then m[i][j] = q
                       s[i][j] = k
return m and s 
// 时间复杂度 O(n^3)
// 空间复杂度 O(n^2) 


// 构造最优解  A[]代表矩阵
PRINt(s,i,j)
    if i == j
        then print "A[" + i + "]"
    else print "("
         PRINT(s,i,s[i][j])
         PRINT(s,s[i][j]+1,j]
         print ")"
// 时间复杂度 O(n)
// 空间复杂度 O(n)               
  • 备忘录方法 为动态规划的变形
    • 备忘录采用自顶向下的递归方式
  • 最长公共子序列(LCS)
// dp[][]记录最优值,state[][]记录最优解
LCS(X,Y)
    m = length(X)
    n = length(Y)
    for i = 1 to m
        do dp[i][0] = 0
    for j = 1 to n
        do dp[0][j] = 0
    for i = 1 to m
        do for j = 1 to n
            do if X[i] == Y[j] // 来自左上角
                then dp[i][j] = dp[i-1][j-1] + 1
                state[i][j] = 1
            else if dp[i-1][j] >= dp[i][j-1] // 来自上边
                then dp[i][j] = dp[i-1][j]
                state[i][j] = 3
            else dp[i][j] = dp[i][j-1] // 来自左边
                state[i][j] = 2
// 时间复杂度 O(mn) ==> O(n^2)

//构造最优解                
PRINT(state,X,i,j)
    if i == 0 or j == 0
        then return
    else if state[i][j] = 1
        then PRINT(state,X,i-1,j-1)
        PRINT(X[i])
    else if state[i][j] = 2
        then PRINT(state,X,i,j-1)
    else PRINT(state,X,i-1,j)
// 时间复杂度 O(m+n) ==>  O(n)	        
  • 0-1背包
    • w为重量,v为价值,W为容量
DP(w,v,W)
    n = length(w)
    for i = 1 to n
        do dp[i][0] = 0
    for j = 1 to W
        do dp[0][j] = 0
    for i = 1 to n
        do for j = 1 to W
            do if w[i] > j // 装不下
                then dp[i][j] = dp[i-1][j]
            else dp[i][j] = max{dp[i-1][j],dp[i-1][j-w[i]] + v[i]}
    return dp
    
// 构造最优解
PRINT(dp,w,W)
    n = length(w)
    j = W
    for i = n to 1
        do if dp[i][j] != dp[i-1][j]
            then x[i] = 0
        else x[i] = 1
            j -= w[i]
    return x
  • 改进 跳跃点
  • 贪心 按单位价值递减排序

三、贪心

  • 性质
    • 贪心选择性质
    • 最优子结构性质
  • 解题步骤
    • 分解 相互独立
    • 解决 贪心选择
    • 合并
  • 与动态规划区别
    • 动态规划依赖相关子问题的解,贪心仅考虑当前状态
    • 动态规划自底向上 ,贪心自顶向下
  • 会场安排
    • 选择最早结束时间且不与当前会议重叠
// 开始时间B,结束时间E
GREEDY(B,E)
    SORT(B,E) // 按结束时间E排序
    n = length(B)
    A = {1}  // 选择1
    k = 1
    for m = 2 to n
        do if B[m] > E[k]
            then A = A{m}
            k = m
    return A
    
    // 时间复杂度 O(nlogn)
    // 空间复杂度 O(logn)
  • 单源最短路径(SSSP)
    • Dijkstra,w[][]记录权值,dist[]记录从源点到其他顶点的长度,pre[]记录路径,前直节点
// 优先队列Q
DIJLSTRA(G,w,s)
    d[s] = 0
    for each v ∈ G.V - {s}
        do d[v] =S = 空集
    Q = G.v
    while Q != 空集
        do u = min(Q)
           S = S{u}
        for each v ∈ G.Adj[u]
            do if d[v] > d[u] + w[u][v]
                then d[v] = d[u]+w[u][v]
// 时间复杂度 O(n^2)                
// 空间复杂度 O(n)            
  • 最小生成树
    • Prim算法
MST-PRIM(G, w, r) //r为根结点
    for each u∈G.V //初始化
        u.key =//u.key为连接u和树中结点所有边中最小边的权重
        u.p = NIL //u.p为结点u的父结点
    r.key = 0
    Q = G.V //优先队列。后述的U=V-Q
    while Q ≠ Φ
        u = EXTRACT-MIN(Q)
        for each v∈G.Adj[u]
            if(v∈Q and w(u, v) < v.key
                v.p = u
                v.key = w(u, v) //DECREASE-KEY
//时间复杂度 O(n^2)
// 空间复杂度 O(n)

四、回溯 (dfs)

能进则进,不进则换,不换则退

  • 0-1背包
backtrack-knapsack-01 (t, w, v, W)
 if cw + w[t] <= W //搜索左子树
     x[t]=1
     cw += w[t] //当前背包中物品的总重量
     cp += v[t] //当前背包中物品的总价值
     backtrack-knapsack-01(t+1,w,v,W-cw);
     cw -= w[t]
     cp -= v[t]
 if bound(t+1,W-cw,cp,w,v) > bestp //搜索右子树
     x[t]=0
     backtrack-knapsack-01(t+1,w, v, W-cw)

bound(i, cleft, cp, w, v) //i为第i层, cleft为背包的剩余容量,cp为当前背包中物品的总价值
 b = cp
 while i <= n && w[i] <= cleft
     cleft -= w[i]
     b += v[i]
     i ++
 if i <= n //装满背包
     b += v[i] / w[i] * cleft
 return b
 
 
//时间复杂度:O(n2^n)
//空间复杂度:O(n)

五、分支限界(bfs)

  • 0-1背包
q-knapsack-01(w, v, W)
 i=1, cw=0, cp=0, up=0, bestp=0, q=φ, stNode=NULL 
 while TRUE{
     if cw+w[i] < W //左结点
         bestp=(cp+v[i]>bestp)?cp+v[i]:bestp
         enqueue (q, new QNode(cw+w[i], cp+v[i], up, true, i+1)
     up = bound(i+1) 
     if up > bestp //右结点
         enqueue(q, new QNode(cw, cp, up, false, i+1)
         QNode node = dequeue(q)
     if node==NULL
         break
     if node != NULL
         cw = node.cw
         cp = node.cp
         up = node.up
         i = node.level
         if i == n+1
         	stNode = node.ptr
             if stNode != NULL
                 for j=n to 1 by -1
                     bestx[j] = stNode.isLeft ? 1:0
                     stNode = stNode.parent
 }
 output(bestx)
 return cp
 
 // 时间复杂度:O(n2^n)
//空间复杂度:O(2^n)

六、概率算法

  • 数值概率算法、蒙特卡罗算法、拉斯维加斯算法、舍伍德算法
  • 线性同余法是产生伪随机数的常用方法
  • 数值概率算法
    • 计算Π的值
      • 圆的面积/正方形面积 = Π/4 = k/n ==> Π = 4k/n
    • 计算定积分
      • I = m/n
  • 舍伍德算法
    • 设法消除最坏情形行为与特定实列之间的关联性
    • 快排
      • 选择基准元素时引入随机性
  • 拉斯维加斯算法
    • 不会得到不正确的解
  • 蒙特卡罗算法
    • 求准确解,但未必正确
  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值