zoukankan      html  css  js  c++  java
  • <DP> (高频)139 375 374 (DP hard)312

    139. Word Break

    返回结果较为简单可用dp, 复杂用dfs

    class Solution {
        public boolean wordBreak(String s, List<String> wordDict) {
            boolean[] dp = new boolean[s.length() + 1];
            
            dp[0] = true;
            //枚举所有substring
            for(int i = 1; i <= s.length(); i++){
                for(int j = 0; j < i; j++){
                    if(dp[j] && wordDict.contains(s.substring(j, i))){
                        dp[i] = true;
                        break;
                    }
                }
            }
            return dp[s.length()];
        }
    }

     375. Guess Number Higher or Lower II

    guarantee a win。保证最小的花费能猜到即可

    建立一个二维的 dp 数组,其中 dp[i][j] 表示从数字i到j之间猜中任意一个数字最少需要花费的钱数,那么需要遍历每一段区间 [j, i],维护一个全局最小值 global_min 变量,然后遍历该区间中的每一个数字,计算局部最大值 local_max = k + max(dp[j][k - 1], dp[k + 1][i]),这个正好是将该区间在每一个位置都分为两段,然后取当前位置的花费加上左右两段中较大的花费之和为局部最大值,为啥要取两者之间的较大值呢,因为要 cover 所有的情况,就得取最坏的情况。然后更新全局最小值,最后在更新 dp[j][i] 的时候看j和i是否是相邻的,相邻的话赋为j,否则赋为 global_min。这里为啥又要取较小值呢,因为 dp 数组是求的 [j, i] 范围中的最低 cost,比如只有两个数字1和2,那么肯定是猜1的 cost 低

    class Solution {
        public int getMoneyAmount(int n) {
            int[][] dp = new int[n + 1][n + 1];
            for(int i = 2; i <= n; i++){
                for(int j = i - 1; j > 0; j--){
                    int globalMin = Integer.MAX_VALUE;
                    for(int k = j + 1; k < i; k++){
                        int localMax = k + Math.max(dp[j][k - 1], dp[k + 1][i]);
                        globalMin = Math.min(globalMin, localMax);
                    }
                    dp[j][i] = j + 1 == i ? j : globalMin;
                }
            }
            return dp[1][n];
        }
    }

    374. Guess Number Higher or Lower

    二分查找

    public class Solution extends GuessGame {
        public int guessNumber(int n) {
            if(guess(n) == 0) return n;
            int left = 1, right = n;
            
            while(left <= right){
                int mid = left + (right - left) / 2;
                if(guess(mid) == -1){
                    right = mid - 1;              
                }else if(guess(mid) == 1){
                   left = mid + 1; 
                }else
                    return mid;
            }
            return left;
        }
    }

     312. Burst Balloons

    dp[i][j] 表示打爆区间 (i, j) 中的所有气球能得到的最多金币。

    第1层循环,dp[][]长度的大小k,第一轮为1个数,第二轮为2个数。

    第2层循环,left的开始起点,都从0开始。 right为窗口的右边界

    第3层循环, i表示打爆当前的气球,依次扫描窗口内的dp, 取最大值。

      假如第i个气球最后被打爆,那么此时区间 [left, right] 被分成了三部分,[left, i],[i],和 [i, right],只要之前更新过了 [left, i] 和[i, right]这两个子区间的 dp 值,可以直接用。

      dp[left][ right] 的意义是什么呢,相当于区间 [left, right] 中除了第i个气球,其他的已经爆了,那么周围的气球只能是第 left个,和第 right 个了

    class Solution {
        public int maxCoins(int[] nums) {
            int[] iNums = new int[nums.length + 2];
            int n = 1;
            for(int x : nums) if(x > 0) iNums[n++] = x;
            iNums[0] = iNums[n++] = 1;
            
            int[][] dp = new int[n][n];
            for(int k = 2; k < n; k++){
                for (int left = 0; left < n - k; left++){
                    int right = left + k;
                    for(int i = left + 1; i < right; i++){
                        dp[left][right] = Math.max(dp[left][right],
                                                   iNums[left]* iNums[i] * iNums[right]+ dp[left][i] + dp[i][right]);
                    }
                }
            }
            return dp[0][n - 1];
        }
    }
  • 相关阅读:
    zookeeper安装(linux)
    rabbitmq安装(linux)遇到 很多坑
    关于mysql数据库连接异常处理
    git放弃修改&放弃增加文件
    git使用常见问题
    base64字符串转化成图片
    Block小结
    关闭selinux
    Ctrl快捷键和vim快捷键
    正则表达式扩展正则
  • 原文地址:https://www.cnblogs.com/Afei-1123/p/12010273.html
Copyright © 2011-2022 走看看