动态规划

动态规划一直是很经典的算法,题目有很多,最近重刷了一些很经典的
但是感觉有时候就还像第一次写一样,所以记录下每到题的思路


n个骰子的点数https://leetcode-cn.com/problems/nge-tou-zi-de-dian-shu-lcof/
这题目不难,但是我第一次写的时候还是没写出来,因为光想到dp转移方程不难,我第一时间想到的是骰子的和情况是有前面的情况加这一次丢出的决定的,但是如果你这么做会被各种越界情况弄的头晕
其实这个题目得换一思路,每次投出的值会对后面的结果造成什么影响,记录下来
dp[i][j],第i次丢出骰子对j值的影响,我们空间优化一下用dp[]和temp[]交替储存
解题代码如下:

  public double[] dicesProbability(int n) {
    double[] dp = new double[6];
    Arrays.fill(dp, 1.0 / 6.0);
    for(int i=2;i<=n;i++){
        double[] temp = new double[5*i+1];
        for(int j=0;j<dp.length;j++){
            for(int x=0;x<6;x++){
                temp[j+x] += dp[j]/6.0;
            }
        }
        dp = temp;
    }
    return dp;
}

通配符匹配
https://leetcode-cn.com/problems/wildcard-matching/

话不多说,直接先列出dp方程
dp[i][j],表示第一个字符串前i个字符是否和第二个字符串前j个字符所匹配,匹配则为true
当char[i] = char[j] 或者 char[j] = ? 时  dp[i][j] = dp[i-1][j-1]
当char[j] = * 时   dp[i][j] = dp[i-1][j] 
可能会有人不能理解第二种方程了,如果我们不使用这个星号,那么就会从dp[i][j-1]dp[i][j−1] 转移而来;如果我们使用这个星号,那么就会从 dp[i-1][j]dp[i−1][j] 转移而来。

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/wildcard-matching/solution/tong-pei-fu-pi-pei-by-leetcode-solution/
只要有一种为真此时状态为真
下面是解题代码

public boolean isMatch(String s, String p) {
    int len1 = s.length()+1;
    int len2 = p.length()+1;
    boolean[][] dp = new boolean[len1][len2];
    dp[0][0] = true;
    for(int j=1;j<len2;j++){
        if(p.charAt(j-1)=='*'){
            dp[0][j] = dp[0][j-1];
        }
    }
    for(int i=1;i<len1;i++){
        for(int j=1;j<len2;j++){
            if(s.charAt(i-1)==p.charAt(j-1)||p.charAt(j-1)=='?'){
                dp[i][j] = dp[i-1][j-1];
            }else if(p.charAt(j-1)=='*'){
                dp[i][j] = dp[i-1][j] | dp[i][j-1];
            }
        }
    }
    return dp[len1-1][len2-1];
}

青蛙过河
https://leetcode-cn.com/problems/frog-jump/
当我们看完题目的时候,肯定就已经感觉出来这是一道dp题目了(判断是不是dp最简单的方法就是当前状态是否和前面状态有关系)
而这一题能否跳到现在的石头上肯定跟前面状态有关(假如你回到上一跳能跳的最远距离之内还没石头你跳水吧直接)
这样我们列出dp方程
dp[i][k],表示跳到第i块石头上,跳的距离是k,能跳到为true
怎么判断可不可以跳过去呢
这个k的距离是前面的石头到现在的石头的距离,(j的含义是i前面的石头)当dp[j][k]、dp[j][k-1]、dp[j][k+1]有一个为真即代表能跳过去为true
当然还可以做一些细节的优化
下面是解题代码:

public boolean canCross(int[] stones) {
    int len =stones.length;
    boolean[][] dp=new boolean[len][len];
    dp[0][0]=true;
    for(int i=1;i<len;i++){
        if(stones[i]-stones[i-1]>i)
            return false;
    }
    for(int i=1;i<len;i++){
       for(int j = i - 1; j >= 0; --j){
         int k=stones[i]-stones[j];
         if(k>j+1){
             break;
         }
          if(dp[j][k-1] || dp[j][k] || dp[j][k+1]){
              dp[i][k]=true;
          }
          if(i==len-1&&dp[i][k]){
              return true;
          }
       }
    }
    return false;
}
上一篇:关于JAVA,SpringMVC接口返回is开头字段变量,丢失is问题


下一篇:println