- 本期主题:动态规划,及其相关oj题。
- 博客主页:小峰同学
- 分享小编的在Linux中学习到的知识和遇到的问题
小编的能力有限,出现错误希望大家不吝赐
- 动态规划是分治思想的延伸,通俗一点来说就是大事化小,小事化无的艺术。
- 在将大问题化解为小问题的分治过程中,保存对这些小问题已经处理好的结果,并供后面处理更大规模的问题时直接 使用这些结果。
动态规划具备了以下三个特点
- 1. 把原来的问题分解成了几个相似的子问题。
- 2. 所有的子问题都只需要解决一次。
- 3. 储存子问题的解。
动态规划的本质,是对问题状态的定义和状态转移方程的定义
也就是(状态以及状态之间的递推关系)
动态规划问题一般从以下四个角度考虑:
- 1. 状态定义
- 2. 状态间的转移方程定义
- 3. 状态的初始化
- 4. 返回结果
- 状态定义的要求:定义的状态一定要形成递推关系。
- 一句话概括:三特点四要素两本质
- 适用场景:最大值/最小值, 可不可行, 是不是,方案个数
牛客网_oj
方法一:递归
缺点:
- 时间复杂度0(N^2),非常低效的一个算法。
优点:
- 代码简单易理解。
int Fibonacci(int n ) {// write code hereif(n ==0){return 0;}if(n == 1 || n ==2){return 1;}return Fibonacci(n-1) + Fibonacci(n-2);
}
方法二:动态规划
优点:
- 相比于递归更高效一些。时间复杂读为O(N)。
- 代码也易懂的。
缺点:
- 其实F(n)只与它相邻的前两项有关,所以没有必要保存所有子问题的解。
- 空间复杂度为O(N),创建了一个数组,但是空间复杂度可以优化为O(1)。
class Solution {
public:int Fibonacci(int n) {//分析//1.状态:F(i)第i项的值//2.状态转换方程:F(i) = F(i-1)+F(i-2)//3.初始状态:F(0) = 0; F(1) = 1//4.返回: F(n)//我们要保存中间状态的解。就需要一个数组。//先创建一个数组int* F = new int[n+1];//注意这里的 n+1;//初始化为初始状态F[0] = 0;F[1] = 1;//状态转换方程 :F(i) = F(i-1)+F(i-2)for(int i = 2; i<=n; i++){F[i] = F[i-1]+F[i-2];}return F[n];//优化if(n==0) return 0;if(n==1) return 1;int fn,fn1 = 0,fn2 = 1;for(int i = 2; i<=n; i++){fn = fn1 + fn2;fn1 = fn2;fn2 = fn;}return fn;//再优化int a = 0,b = 1;while(n--){b = a+b;a = b-a;}return a;}
};
牛客网_oj
方法一:递归
优点:相对于暴力遍历来说,代码时间复杂度和空间复杂度都相对
class Solution {
public:bool wordBreak(string s, unordered_set &dict) {//注意这里的被分割是指,能在词典中找到。// 方法:动态规划// 状态:// 子状态:前1,2,3,...,n个字符能否根据词典中的词被成功分词// F(i): 前i个字符能否根据词典中的词被成功分词// 状态递推:// F(i): true{j can_break(s.size() + 1, false);// 初始化F(0) = truecan_break[0] = true;for (int i = 1; i <= s.size(); i++){for (int j = i - 1; j >= 0; j--){// F(i): true{j