Leetcode DP java

java tip
使int[]排序,使用Arrays.sort()
使list排序,使用Collections.sort()

392

此题中dp[n][z]是指站在n的位置看,出现下一个z
dp[0][a]=2指,在0号位看,下一次出现a是在2号位
因为查找是正向查找,所以建表是逆向建表

public boolean isSubsequence(String s, String t) {
        // 预处理
        t = " " + t; // 开头加一个空字符作为匹配入口
        int n = t.length();
        int[][] dp = new int[n][26]; // 记录每个位置的下一个ch的位置
        for (char ch = 0; ch < 26; ch++) {
            int p = -1;
            for (int i = n - 1; i >= 0; i--) { // 从后往前记录dp
                dp[i][ch] = p;
                if (t.charAt(i) == ch + 'a') p = i;
            }
        }
        // 匹配
        int i = 0;
        for (char ch : s.toCharArray()) { // 跳跃遍历
            i = dp[i][ch - 'a'];
            if (i == -1) return false;
        }
        return true;
    }

1139

只有遍历到i=3,j=3,求出dp[3][3][0],dp[3][3][1]才能求出最终结果9
本题要判断一个正方形,只需判断右下角,根据min求出边长,依次找到右上角dp[i-k][j](求出上边长dp[i-k][j][1])和左下角dp[i][j-k](求出左边长dp[i][j-k][0])
但因为存在右下角dp为6,7,但正方形边长最多为4的情况,所以不能直接判断dp[i-k][j][1],而是要遍历min(6,7),求得最大边长

public int largest1BorderedSquare(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        int[][][] dp = new int[m+1][n+1][2];
        // 0 up 1 left;
        int ans = 0;
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (grid[i-1][j-1] == 0) continue; // 如果是0则不要继续了
                dp[i][j][0] = dp[i-1][j][0] + 1; // 求出up情况下连续的个数
                dp[i][j][1] = dp[i][j-1][1] + 1; // 求出left情况下连续的个数
                int min = Math.min(dp[i][j][0], dp[i][j][1]); // 拿出两者较小的长度,因为四条边都要相等。
                for (int k = 0; k < min; k++) {//拿出后并不一定就是min这个长度,有可能另外两条边比较短,没有min长,所以要一个一个判断。
                    // 判断另外的两条边是否都比当前长度大。
                    int k1=dp[i-k][j][1];
                    int k2=dp[i][j-k][0];
                    if ( k1>= k + 1 &&  k2>= k + 1)
                        ans = Math.max(ans, k + 1);
                }
            }
        }
        return ans * ans;
    }

740

若转化为打家劫舍问题,得有一个LinkedList[],每个位置是同一个数字,但这种麻烦的方法可以用两个数组代替

unsorted int[],可以用Arrays.sort()排序
再制造一个数组表明没个数字的数量
举个例子:

nums = [2, 2, 3, 3, 3, 4]

构造后:

all=[0, 0, 2, 3, 1];

这样可以利用两个数组来替代

public int deleteAndEarn(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        } else if (nums.length == 1) {
            return nums[0];
        }
        int len = nums.length;
        int max = nums[0];
        for (int i = 0; i < len; ++i) {
           max = Math.max(max, nums[i]);
        }
//      构造一个新的数组all
        int[] all = new int[max + 1];
        for (int item : nums) {
            all[item] ++;
        }
        int[] dp = new int[max + 1];
        dp[1] = all[1] * 1;
//      动态规划求解
        for (int i = 2; i <= max; ++i) {
            dp[i] = Math.max(dp[i - 1], dp[i - 2] + i * all[i]);
        }
        return dp[max];
    }

各种背包问题

322

这个方法太快了
如果amount小于coins最大的,求出i=0,然后尝试index-1的硬币大小,完美

int ans = Integer.MAX_VALUE;

    public int coinChange(int[] coins, int amount) {
        Arrays.sort(coins);
        coinChange(coins.length-1, coins, 0, amount);
        return ans == Integer.MAX_VALUE ? -1 : ans;
    }

    private void coinChange(int index, int[] coins, int count, int needAmount) {
        if (needAmount == 0) {
            ans = Math.min(count, ans);
            return;
        }
        if (index < 0) {
            return;
        }
        int i = needAmount / coins[index];
        for (int k=i; k>=0 && count+k<ans; k--) {
            coinChange(index-1, coins, count+k, needAmount-k*coins[index]);
        }
    }

474

注意char一定要转换成int
c[str.charAt(i)-‘0’]++;
the ingenious part lies in the for-loop condition!!!
first exemine that i>zero[0] then checks dp[i-zero[0]]

dp another important fact

focus on the sequence of iterating the array
sometimes is in order, sometimes is reversed order
正向赋值还是反向赋值完全由状态转移方程决定。

public int findMaxForm(String[] strs, int m, int n) {
        int[][] dp = new int[m+1][n+1];
        for(String str:strs) {
            int[] zero = countZero(str);
            for (int i = m; i>zero[0];i--){
                for(int j=n;j>zero[1];j--){
                    dp[i][j] =Math.max(1+dp[i-zero[0]][j-zero[1]],dp[i][j]);
                }

            }
        }
        return dp[m][n];
    }

    private int[] countZero(String str) {
        int[] c = new int[2];
        for(int i=0;i<str.length();i++){
            c[str.charAt(i)-'0']++;
        }
        return c;
    }

不用管逆序的方法

public class Solution {

    private int[] countZeroAndOne(String str) {
        int[] cnt = new int[2];
        for (char c : str.toCharArray()) {
            cnt[c - '0']++;
        }
        return cnt;
    }

    public int findMaxForm(String[] strs, int m, int n) {
        int len = strs.length;
        int[][][] dp = new int[len + 1][m + 1][n + 1];

        for (int i = 1; i <= len; i++) {
            // 注意:有一位偏移
            int[] cnt = countZeroAndOne(strs[i - 1]);
            for (int j = 0; j <= m; j++) {
                for (int k = 0; k <= n; k++) {
                    // 先把上一行抄下来
                    dp[i][j][k] = dp[i - 1][j][k];

                    int zeros = cnt[0];
                    int ones = cnt[1];

                    if (j >= zeros && k >= ones) {
                        dp[i][j][k] = Math.max(dp[i - 1][j][k], dp[i - 1][j - zeros][k - ones] + 1);
                    }
                }
            }
        }
        return dp[len][m][n];
    }
}

作者:liweiwei1419
链接:https://leetcode-cn.com/problems/ones-and-zeroes/solution/dong-tai-gui-hua-zhuan-huan-wei-0-1-bei-bao-wen-ti/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值