算法

217 阅读2分钟

动态规划

英文:Dynamic Programming,简称DP,将问题分解为互相重叠的子问题,通过反复求解子问题来解决原问题就是动态规划,如果某一问题有很多重叠子问题,使用动态规划来解是比较有效的。 求解动态规划的核心问题是穷举

经典问题:背包问题,打家劫舍,股票问题,子序列问题

题目:1 1 2 3 5 8 求斐波那契数列

// 动规五部曲
// 1. 确定dp数组(dp table)以及下标的含义
dp[i]:第i个斐波那契数值为dp[i]
// 2. 确定递推公式
dp[i] = dp[i - 1] + dp[i - 2]
// 3. dp数组如何初始化
dp[0] = 1 dp[i] = 1
// 4. 确定遍历顺序
从前向后
// 5. 打印dp数组let dp = []
dp[0] = 0 dp[1] = 1
for(i = 2; i < n; i ++)
     dp[i] = dp[i - 1] + dp[i - 2]
return dp[n]

股票问题

image-20220222162703742.png

kmp算法

题目:文本串 aabaabaaf, 模式串 aabaaf, 求是否存在匹配模式串

根据kmp算法需要求next[](prefix) ,及最长相等前后缀的数组,next值,代表下次开始匹配的位置下标。首先初始 j (前缀末尾 )i (后缀末尾)next[],然后判断前后缀不相同时条件j > 0 && s[i] !== s[j]时,j赋值为next数组前面一位的值,判断前后缀相同时j 向前移动一位,最后给next赋值

getNext(s) {
    const j = 0;
    const next = []
    const next[0] = j
    for (let i = 1; i < s.length; i++) {
        while(j > 0 && s[i] !== s[j]) {
            j = next[j - 1]
        }
        if (s[i] === s[j]) {
            j++
        }
        next[i] = j
    }
}
​
let eg = aabaabaaf
let template = aabaaf
// next [0 1 0 1 2 0]
// 最长相等前后缀
// a        0
// aa       1
// aab      0
// aaba     1
// aabaa    2
// aabaaf   0
// 前缀 a aa aab aaba aabaa
// 后缀 f af aaf baaf abaaf

回溯算法

经典问题:解决一组数的组合,切割,子集,排列,棋盘问题

确认递归函数参数,返回值,设置终止条件,编写单层递归逻辑代码

void backtracking(参数) {
    if (终止条件)
    收集结果
    return
    for(集合元素)
    处理节点
    递归函数
    回溯操作
}

题目:从0-n的数,数组长度为k长度的组合,求所有组合

image-20211110235249130.png

// 二维数组 result
// 一维数组 path
const path = []
const backtracking = (n, k, startIndex) => {
  if (path.length === k) {
    console.log(path)
    return
  }
  for (let i = startIndex; i < n.length - (k - path.length) + 1; i++) {
    path.push(n[i])
    backtracking(n, k, i + 1)
    path.pop()
  }
}
backtracking([1, 2, 3, 4], 2, 0)
// [ 1, 2 ]
// [ 1, 3 ]
// [ 1, 4 ]
// [ 2, 3 ]
// [ 2, 4 ]
// [ 3, 4 ]
// for 代表的是单前层的遍历,递归是往树的深处遍历,剪枝一般在for循环里做处理
// 比如i < n.size => i < n - (k - path.size) + 1 ()

image.png

\