您的位置:首页 > 新闻 > 热点要闻 > 网页制作工作_如何建立属于自己的网站_品牌营销案例分析_营销模式都有哪些

网页制作工作_如何建立属于自己的网站_品牌营销案例分析_营销模式都有哪些

2025/1/4 14:56:31 来源:https://blog.csdn.net/m0_73992740/article/details/143508008  浏览:    关键词:网页制作工作_如何建立属于自己的网站_品牌营销案例分析_营销模式都有哪些
网页制作工作_如何建立属于自己的网站_品牌营销案例分析_营销模式都有哪些

动态规划

分析:(五步)

  1. 状态表示

状态表示是什么?
dp表里面的值锁表示的含义

状态表示怎么来的?

  • 题目要求
  • 经验 + 题目要求
  • 线性状态表经验: 以i位置为结尾 以i位置为起点
  • 分析问题的过程中, 发现重复子问题
  1. 状态转移方程
    dp[i] 等于什么(一个公式)
    用之前或者之后的状态, 推导出dp[i]的值
  2. 初始化
    保证填表的时候不越界
  3. 填表顺序
    为了填写当前状态的时候, 所需要的状态已经计算过了
  4. 返回值
    题目要求 + 状态表示

编写代码: (四步)

  1. 创建dp表
  2. 初始化
  3. 填表
  4. 确定返回值

优化: 处理边界问题以及初始化问题的技巧
如果初始化和填表的逻辑类似, 我们可以把初始化塞到填表逻辑中
做法:
dp多开一个空间, 将之前的dp表整体向后移动, 前面的一个位置称为虚拟节点
注意:
1.虚拟结点里面的值, 要保证是正确的 一般情况下设置为0, 但还是要具体分析
2.下标的映射关系

一.第n个泰波那契数

第n个泰波那契数

  1. 状态表示
    dp表 表示第n个泰波那契数
  2. 状态转移方程
    dp[i] = dp[i - 3] + dp[i - 2] + dp[i - 1]
  3. 初始化
    dp[0] = 0 dp[1] = 1 dp[2] = 1
  4. 填表顺序
    从左往右
  5. 返回值
    返回dp[n]
class Solution {public int tribonacci(int n) {//处理边界情况if(n == 0) return 0;if(n == 1 || n == 2) return 1;//1. 创建dp表int[] dp = new int[n + 1];//2. 初始化dp[0] = 0;dp[1] = dp[2] = 1;//3. 填表for(int i = 3; i <= n; i++){//状态转移方程dp[i] = dp[i - 3] + dp[i - 2] + dp[i - 1];}//4. 确定返回值return dp[n];}
}

空间优化: 用滚动数组来实现(此题使用变量即可)

class Solution {public int tribonacci(int n) {//处理边界情况if(n == 0) return 0;if(n == 1 || n == 2) return 1;//空间优化int a = 0, b = 1, c = 1, d = 0;for(int i = 3; i <= n; i++){d = a + b + c;a = b;b = c;c = d;}//确定返回值return d;}
}

二. 三步问题

三步问题

  1. 状态表示
    dp[i] 表示到达i位置时, 一共有多少种方法
  2. 状态转移方程
    以i位置的状态, 最近的一步来划分问题
    1.从 i - 1 到 i dp[i - 1]
    2.从 i - 2 到 i dp[i - 2]
    3.从 i - 3 到 i dp[i - 3]
    dp[i] = dp[i - 3] + dp[i - 2] + dp[i - 1]
  3. 初始化
    dp[1] = 1 dp[2] = 1 dp[3] = 4
  4. 填表顺序
    从左往右
  5. 返回值
    返回dp[n]
class Solution {public int waysToStep(int n) {// 1. 创建dp表// 2. 初始化// 3. 填表// 4. 确定返回值int MOD = (int)1e9 + 7;if(n == 1 || n == 2) return n;if(n == 3) return 4;int[] dp = new int[n + 1];dp[1] = 1;dp[2] = 2;dp[3] = 4;for(int i = 4; i <= n; i++){dp[i] = ((dp[i - 3] + dp[i - 2]) % MOD + dp[i - 1]) % MOD;//每次做加法都有可能越界}return dp[n];}
}

三. 使用最小花费爬楼梯

使用最小花费爬楼梯
方法一: 以i位置结尾

  1. 状态表示
    dp[i] 表示到达i位置时, 最小花费
  2. 状态转移方程
    以i位置的状态, 最近的一步来划分问题
    1.先到达 i - 1 的位置, 然后支付cost[i - 1] 走一步 到 i dp[i - 1] + cost[i - 1]
    2.从先到达 i - 2 的位置, 然后支付cost[i - 2] 走两步 到 i dp[i - 2] + cost[i - 2]
  • dp[i] =min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2])
  1. 初始化
    dp[0] = dp[1] = 0
  2. 填表顺序
    从左往右
  3. 返回值
    返回dp[n]
class Solution {public int minCostClimbingStairs(int[] cost) {// 1. 创建dp表// 2. 初始化// 3. 填表// 4. 确定返回值int n = cost.length;int[] dp = new int[n + 1];for (int i = 2; i <= n; i++) {dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);}return dp[n];}
}

方法二: 以i位置开始

  1. 状态表示
    dp[i] 表示从i位置, 到达顶点的最小花费
  2. 状态转移方程
    以 i 位置的状态, 最近的一步来划分问题
    1.先支付cost[i] 走一步, 从 i 位置到达 i + 1 的位置, 然后到终点 dp[i + 1] + cost[i]
    2.先支付cost[i] 走两步, 从 i 位置到达 i + 2 的位置, 然后到终点 dp[i + 2] + cost[i]
  • dp[i] =min(dp[i + 1] + cost[i], dp[i + 2] + cost[i])
  1. 初始化
    dp[n] = cost[n], dp[n - 1] = cost[n - 1]
  2. 填表顺序
    从右往左
  3. 返回值
    返回min(dp[0], dp[1])
class Solution {public int minCostClimbingStairs(int[] cost) {// 1. 创建dp表// 2. 初始化// 3. 填表// 4. 确定返回值int n = cost.length;int[] dp = new int[n];dp[n - 2] = cost[n - 2];dp[n - 1] = cost[n - 1];for(int i = n - 3; i >= 0; i--){dp[i] = Math.min(dp[i + 1] + cost[i], dp[i + 2] + cost[i]);}return Math.min(dp[0], dp[1]);}
}

四. 解码方法

解码方法

  1. 状态表示
    dp[i] 表示以 i 位置结尾, 解码方法的总数
  2. 状态转移方程

1.只解码 i 位置, 可以分成成功和失败两种情况
成功, s[i] 一定是>= 1 && <= 9, 说明从头开始到i位置, 都是可以正常解码的, 只需在解码成功的字符串后面加上一个字符, 那么dp[i] = dp[i - 1]
失败 说明不管前面解码是否成功, i位置失败了, 就不算解码成功, dp[i] = 0
2.解码 i 位置和 i - 1 位置, 也可以分成成功和失败两种情况
成功, s[i - 1] * 10 + s[i] 一定是>= 10 && <= 26, 说明从头开始到i位置, 都是可以正常解码的, 只需在解码成功的字符串(dp[i - 2])后面加上一个字符, 那么dp[i] = dp[i - 2]
失败 说明不管前面解码是否成功, i位置失败了, 就不算解码成功, dp[i] = 0

  • 成功条件: dp[i] =dp[i - 1] + dp[i - 2]
  1. 初始化
    dp[0] 一个字符的解码总数: 成功为1, 失败为0
    dp[1] 一个字符: 成功为1, 失败为0, 两个字符: 成功为1, 失败为0, 所以dp[1]可能为1, 2, 0
  2. 填表顺序
    从左往右
  3. 返回值
    返回dp[n - 1]
class Solution {public int numDecodings(String ss) {// 1. 创建dp表// 2. 初始化// 3. 填表// 4. 返回值char[] s = ss.toCharArray();int n = s.length;int[] dp = new int[n];//初始化dp[0]if (s[0] != '0')dp[0] += 1;//注意字符长度if (n == 1)return dp[0];//初始化dp[1]if (s[1] != '0' && s[0] != '0')dp[1] += 1;int t = (s[0] - '0') * 10 + s[1] - '0';if (t >= 10 && t <= 26)dp[1] += 1;//填表for (int i = 2; i < n; i++) {if (s[i] != '0')dp[i] += dp[i - 1];int tt = (s[i - 1] - '0') * 10 + s[i] - '0';if (tt >= 10 && tt <= 26)dp[i] += dp[i - 2];}return dp[n - 1];}
}

优化:
此题中, 虚拟节点dp[0]中的值, 应该为1
因为当dp[1]和dp[2]两个字符一起看的时候, 如果能映射成字符, 那么dp[2] = dp[2 - 2] = dp[0], 此时应该算作一个结果, 应该为1

class Solution {public int numDecodings(String ss) {// 1. 创建dp表// 2. 初始化// 3. 填表// 4. 返回值char[] s = ss.toCharArray();int n = s.length;int[] dp = new int[n + 1];// 初始化dp[0]dp[0] = 1;// 虚拟节点// 初始化dp[1]if (s[0] != '0')dp[1] = 1;// 填表for (int i = 2; i <= n; i++) {if (s[i - 1] != '0')dp[i] += dp[i - 1];int tt = (s[i - 2] - '0') * 10 + s[i - 1] - '0';if (tt >= 10 && tt <= 26)dp[i] += dp[i - 2];}return dp[n];}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com