dp算法练习(1)

下降路径最小和

931. 下降路径最小和

给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径  最小和 。

下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)(row + 1, col) 或者 (row + 1, col + 1) 。

class Solution {
    public int minFallingPathSum(int[][] matrix) {
        int n = matrix.length;
        int m = matrix[0].length;
        int[][] dp = new int[n + 1][m + 1];
        for (int i = 0; i < m; i++)
            dp[0][i] = matrix[0][i];

        for (int i = 1; i < n; i++) {
            for (int j = 0; j < m; j++) {
                // 根据当前位置,拿到上一行位置上当前下一个位置的数据,比较得到一个最小值
                int left = j > 0 ? dp[i - 1][j - 1] : Integer.MAX_VALUE;
                int now = dp[i - 1][j];
                int right = j < m - 1 ? dp[i - 1][j + 1] : Integer.MAX_VALUE;
                //将最小值与当前值相加
                int minV = Math.min(left, Math.min(now, right));
                dp[i][j] = matrix[i][j] + minV;
            }
        }
        //比较最后一行中,得到实际上最小的值
        int minV = Integer.MAX_VALUE;
        for (int i = 0; i < m; i++) {
            minV = Math.min(minV, dp[n - 1][i]);
        }
        return minV;
    }
}

最大正方形

221. 最大正方形

在一个由 '0' 和 '1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。

class Solution {
    public int maximalSquare(char[][] matrix) {
        int maxSide = 0;
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return maxSide;
        }
        int n = matrix.length;
        int m = matrix[0].length;
        int[][] dp = new int[n + 1][m + 1];
        int maxV = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (matrix[i][j] == '1') {
                    if (i == 0 || j == 0) {
                        dp[i][j] = 1;
                    } else {
                        //找当前位置上、左、左上三个位置,判断是否都为1,代表是一个正方形
                        int minV = Math.min(dp[i][j - 1], Math.min(dp[i - 1][j], dp[i - 1][j - 1]));
                        dp[i][j] = minV + 1;
                    }
                    maxV = Math.max(maxV, dp[i][j]);
                }
            }
        }
        return maxV * maxV;
    }
}

最长回文串

5. 最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

输入:s = "cbbd"
输出:"bb"

下面是多种解题方法 

1、暴力判断

class Solution {
    public String longestPalindrome(String s) {
        String res = "";
        int n = s.length();
        if (n == 1)
            return s;
        for (int i = 0; i < n; i++) {
            for (int j = n ; j > i; j--) {
                String str = getPalindrome(s.substring(i, j));
                res = str.length() > res.length() ? str : res;
            }
        }
        return res;
    }

    String getPalindrome(String s) {

        int len = s.length() - 1;
        int start = 0;
        while (start <= len && s.charAt(start) == s.charAt(len)) {
            start++;
            len--;
        }
        return start >= len ? s : "";
    }
}

2、中心扩散方法,先左右判断是否可回文,最后再从左右后节点判断回文

class Solution {
    public String longestPalindrome(String s) {
            if (s == null || s.length() == 0) {
                return "";
            }
            int strLen = s.length();
            int left = 0;
            int right = 0;
            int len = 1;
            int maxStart = 0;
            int maxLen = 0;

            for (int i = 0; i < strLen; i++) {
                left = i - 1;
                right = i + 1;
                while (left >= 0 && s.charAt(left) == s.charAt(i)) {
                    len++;
                    left--;
                }
                while (right < strLen && s.charAt(right) == s.charAt(i)) {
                    len++;
                    right++;
                }
                while (left >= 0 && right < strLen && s.charAt(right) == s.charAt(left)) {
                    len = len + 2;
                    left--;
                    right++;
                }
                if (len > maxLen) {
                    maxLen = len;
                    maxStart = left;
                }
                len = 1;
            }
            return s.substring(maxStart + 1, maxStart + maxLen + 1);
    }
}

3、动态规划:记录left到right是否为回文串,减少判断次数 

class Solution {
    public String longestPalindrome(String s) {
        if(s == null || s.length() == 1)    return s;

        int len = s.length();
        int maxStart = 0;
        int maxLen = 1;
        int maxEnd = 0;

        // dp[i][j] 代表的是dp数组中i位置到j位置,是否为回文串的判断值
        boolean[][] dp = new  boolean [len][len];

        for(int r = 1; r < len; r++){
            for(int l = 0; l < r;l++){
                if(s.charAt(l) == s.charAt(r) && (r-l <= 2 || dp[l+1][r-1])){
                    dp[l][r] = true;
                    if(r - l + 1 > maxLen){
                        maxLen = r - l +1;
                        maxStart = l;
                        maxEnd = r;
                    }
                }
            }
        }
        return s.substring(maxStart,maxStart + maxLen);
    }
}

 

单次拆分

139. 单词拆分

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true

注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

示例 1:

输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。

示例 2:

输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。
     注意,你可以重复使用字典中的单词。

示例 3:

输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
输出: false

dp直接暴力判断做就行了

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        int len = s.length();
        boolean[] dp = new boolean[len + 1];
        dp[0] = true;

        for (int i = 0; i <= len; i++) {
            for (String word : wordDict) {
                int wordLen = word.length();
                // 从i-wordLen 位置到 i位置的字符串,判断是否能与字典表中匹配
                if (i >= wordLen && dp[i - wordLen] && word.equals(s.substring(i - wordLen, i))) {
                    dp[i] = true;
                }
            }
        }
        return dp[len];
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值