• 动态规划 八月八日


    #该博客根据九章算法视频课程总结#

            动态规划,用空间换时间的算法,避免重复节点的计算,将计算过的结果记录在hash等容器中,用来减少在计算的时间,也叫作记忆化搜索。

    目录

    目录

    #该博客根据九章算法视频课程总结#

    动态规划题的特点:

    1.计数

    2.求最大值最小值

    3.求存在性

    动态规划题四个步骤

    1.确定状态

    递归和动态规划的区别:

    2.转移方程

    3.初始条件和边界情况

     4.计算顺序

    例题:

            1.有三种面值的硬币,2 5 7 使用最少的硬币拼出27元。

    2.机器人

    3.青蛙

    4.最长回文字符串(力扣)

    5.接雨水(力扣)



    动态规划题的特点:

    1.计数

    •         有多少种方式走到右下角
    •         有多少种方式选出K个数求出最大值Sum

    2.求最大值最小值

    •         从左下角走到右下角路径的最大数字之和
    •         最长上升子序列的值

    3.求存在性

    •         取石子游戏,先手是否必胜
    •         能不能选出K个数使得和为Sum

    动态规划题四个步骤

    1.确定状态

            简单地说,解动态规划题需要开一个数组,每个数组的F[i]或F[i][j]代表什么

            确定状态需要两个意识:

                    1.最后一步(最后的一个数)

                    2.子问题

    递归和动态规划的区别:

     在图中我们看到,用递归法求解,计算中,有很多点使我们重复计算多次的,当数据量极大的时候,时间复杂度是很大的。为了避免该问题,我们将计算过的值记录下来,以减少计算的时间。

    2.转移方程

     [ ]代表数组的下标。

    3.初始条件和边界情况

     4.计算顺序

    例题:

            1.有三种面值的硬币,2 5 7 使用最少的硬币拼出27元。

    1. class Solution {
    2. public int demo(int[] A,int M) {
    3. /*
    4. 假设最后一个硬币是a 则剩下的钱为27-a
    5. f(27)=f(27-a)+1
    6. 转移方程则为 f(27)=min{f(27-2)+1,f(27-5)+1,f(27-7)+1}
    7. f(x)=min{f[x-2]+1,f[x-5]+1,f[x-7]+1}
    8. 初始条件:f[0]=0;
    9. 边界情况:x-{2,5,7}>0
    10. * */
    11. //建立存储数组
    12. int[] f=new int[M+1];
    13. int n=A.length;
    14. f[0]=0;
    15. for (int i=1;i
    16. //如果拼不出来,就定义为MAX
    17. f[i]=Integer.MAX_VALUE;
    18. for (int j=0;j
    19. if (i>=A[j]&&f[i-A[j]]!=Integer.MAX_VALUE){
    20. f[i]=Math.min(f[i-A[j]]+1,f[i]);
    21. }
    22. }
    23. }
    24. if (f[M]==Integer.MAX_VALUE)
    25. f[M]=-1;
    26. return f[M];
    27. }
    28. }

    2.机器人

    1.确定状态

            最后只能从右下角的格子的上或左两个格子

            子问题:有X种方式走到上边的格子,有Y中方式走到左边的格子,则最后有X+Y种方式走到右下角的格子

            问题则转为走到这两个格子的问题,因为机器人只能向下走和向右走,因此当到达最右边和最下边时,就变成了只有一种行进方式。

    2.转移方程

            f[i][j]=f[i-1][j]+f[i][j-1]

    3.初始条件和边界情况

            初始条件: f[0][0]=1

            边界条件:当i==0或j==0时,机器人都只有一种方式从前一个格子行进过来

    4.计算顺序

            依次计算0-n行

    1. public class Solution {
    2. public int demo(int a,int b){
    3. int[][] f=new int[a][b];
    4. for (int i=0;i
    5. for (int j=0;j
    6. if (i==0||j==0){
    7. f[i][j]=1;
    8. }
    9. f[i][j]=f[i][j-1]+f[i-1][j];
    10. }
    11. }
    12. return f[a-1][b-1];
    13. }
    14. }

    3.青蛙

    1.确定状态

            如果青蛙能调到n-1块石头,我们考虑他左后跳的依次。

            满足两个条件:

                    1.青蛙能调到石头i

                    2.青蛙最后一跳的距离大于等于 n-1-i

                     子问题:

                            f[j]表示青蛙能否调到j石头

    2.转移方程

            

     OR表示:枚举,即是在for循环中的可能性,只要有一中可能满足,结果就是true

    AND表示:并且

    3.初始条件和临界情况

            初始条件:f[0]=true

            临界情况:无

    4.计算顺序

            从左到右

    1. class Solution1 {
    2. public boolean demo(int A[]){
    3. boolean[] f=new boolean[A.length];
    4. f[0]=true;
    5. for (int j=1;j
    6. f[j]=false;
    7. for (int i=0;i
    8. if (f[i]==true&&(i+A[i]>=j)){
    9. f[j]=true;
    10. break;
    11. }
    12. }
    13. }
    14. return f[A.length-1];
    15. }
    16. }

    第二层循环检索的是,在在此之前的石头上青蛙有无可能跳过来。

    4.最长回文字符串(力扣)

    1.确认状态

            字符串是回文字符串,则他的[i+1,j-1]串也是回文字符串

    2.转换方程

                    P(i,j)=P(i+1,j−1)∧(Si==Sj)

    3.临界条件

                     P(i,i)=true

                      P(i,i+1)=(Si==Si+1)

    4.计算顺序

                    先填充对角线上的结果,单个字符肯定是回文字符串

    1. public class Solution {
    2. public String longestPalindrome(String s) {
    3. int len = s.length();
    4. if (len < 2) {
    5. return s;
    6. }
    7. int maxLen = 1;
    8. int begin = 0;
    9. // dp[i][j] 表示 s[i..j] 是否是回文串
    10. boolean[][] dp = new boolean[len][len];
    11. // 初始化:所有长度为 1 的子串都是回文串
    12. for (int i = 0; i < len; i++) {
    13. dp[i][i] = true;
    14. }
    15. char[] charArray = s.toCharArray();
    16. // 递推开始
    17. // 先枚举子串长度
    18. for (int L = 2; L <= len; L++) {
    19. // 枚举左边界,左边界的上限设置可以宽松一些
    20. for (int i = 0; i < len; i++) {
    21. // 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
    22. int j = L + i - 1;
    23. // 如果右边界越界,就可以退出当前循环
    24. if (j >= len) {
    25. break;
    26. }
    27. if (charArray[i] != charArray[j]) {
    28. dp[i][j] = false;
    29. } else {
    30. if (j - i < 3) {//j-1-i-1<1
    31. dp[i][j] = true;
    32. } else {
    33. dp[i][j] = dp[i + 1][j - 1];
    34. }
    35. }
    36. // 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
    37. if (dp[i][j] && j - i + 1 > maxLen) {
    38. maxLen = j - i + 1;
    39. begin = i;
    40. }
    41. }
    42. }
    43. return s.substring(begin, begin + maxLen);
    44. }
    45. }

    5.接雨水(力扣)

    1. class Solution {
    2. public int trap(int[] height) {
    3. int n = height.length;
    4. if (n == 0) {
    5. return 0;
    6. }
    7. int[] leftMax = new int[n];
    8. leftMax[0] = height[0];
    9. for (int i = 1; i < n; ++i) {
    10. leftMax[i] = Math.max(leftMax[i - 1], height[i]);
    11. }
    12. int[] rightMax = new int[n];
    13. rightMax[n - 1] = height[n - 1];
    14. for (int i = n - 2; i >= 0; --i) {
    15. rightMax[i] = Math.max(rightMax[i + 1], height[i]);
    16. }
    17. int ans = 0;
    18. for (int i = 0; i < n; ++i) {
    19. ans += Math.min(leftMax[i], rightMax[i]) - height[i];
    20. }
    21. return ans;
    22. }
    23. }

    从左右两边分别遍历,最后累加差值

  • 相关阅读:
    Linux下的文件IO
    什么是关系数据库,你知道吗?
    C Primer Plus(6) 中文版 第5章 运算符、表达式和语句 5.4 表达式和语句
    【Springboot】Springboot如何优雅停机?K8S中Pod如何优雅停机?
    Spring 基于注解的容器配置有哪些?
    自适应模糊神经网络与bp神经网络的区别
    KT148A电子语音芯片ic方案适用的场景以及常见产品类型
    rpm(基本命令、Makefile、建立rpmbuild编包)
    星戈瑞FITC-Cytochrome C:荧光标记细胞色素C的研究与应用
    Springboot+JPA+ORACLE12C项目hibernate生成的SQL语句中schema."小写表名"导致的“ORA-00942 表或视图不存在”问题,求解决方案。
  • 原文地址:https://blog.csdn.net/weixin_45799228/article/details/126222529