LeeCode Practice Journal | Day36_DP04

1049. 最后一块石头的重量 Ⅱ

题目:1049. 最后一块石头的重量 II - 力扣(LeetCode)
题解:代码随想录 (programmercarl.com)
背包问题的难点:看不出为啥是背包问题。。。

solution
public class Solution {
    public int LastStoneWeightII(int[] stones) {
        int totalWeight = 0;
        foreach (int stone in stones)
        {
            totalWeight += stone;
        }

        int halfWeight = totalWeight / 2;
        bool[] dp = new bool[halfWeight + 1];
        dp[0] = true;

        foreach (int stone in stones)
        {
            for (int j = halfWeight; j >= stone; j--)
            {
                dp[j] = dp[j] || dp[j - stone];
            }
        }

        for (int j = halfWeight; j >= 0; j--)
        {
            if (dp[j])
            {
                return totalWeight - 2 * j;
            }
        }

        return 0; // 虽然实际情况中不可能到达这里
    }
}
summary

1、问题转化:
使两个组的重量差最小 ---> 选择一些石头使得其总重量尽可能接近总重量的一半。
设总重量为 totalWeight,那么每组的目标是 totalWeight / 2。需要找到一个子集,使得其重量尽可能接近 totalWeight / 2。

2、dp
dp[j] :是否存在一个子集,其总重量为 j
初始化 dp[0] = true

494. 目标和

题目:494. 目标和 - 力扣(LeetCode)
题解:代码随想录 (programmercarl.com)
这题好想一点!
综合上一题看出dp题目的突破口还在递推公式,递推公式的突破口在找到前后元素的关系
发现dp的题使用图解法有奇效

solution
public class Solution {
    public int FindTargetSumWays(int[] nums, int target) {
        int sum = nums.Sum();
        if(target > sum || target < -sum) return 0;


        int[,] dp = new int[nums.Length, 2*sum + 1];
        for(int i = 0; i < nums.Length; i ++)
        {
            for(int j = 0; j <= 2*sum; j ++)
            {   
                if(i == 0)
                    dp[0, j] = (nums[i] == j - sum ? 1 : 0) + (-nums[i] == j - sum ? 1 : 0);

                else 
                    dp[i, j] = (j - nums[i] >= 0 ? dp[i - 1, j - nums[i]] : 0) + (j + nums[i] <= 2*sum ? dp[ i - 1, j + nums[i]] : 0);
            }
        }
        
        return dp[nums.Length - 1, sum + target];
    }
}
summary

我真的恨0

474. 一和零

题目:474. 一和零 - 力扣(LeetCode)
题解:代码随想录 (programmercarl.com)

solution
public class Solution {
    public int FindMaxForm(string[] strs, int m, int n) {
        // 创建一个二维数组 dp,大小为 (m + 1) x (n + 1)
        int[,] dp = new int[m + 1, n + 1];

        // 遍历所有字符串
        foreach (string str in strs)
        {
            int zeroCount = 0;
            int oneCount = 0;

            // 计算当前字符串中的 '0' 和 '1' 的数量
            foreach (char c in str)
            {
                if (c == '0') zeroCount++;
                if (c == '1') oneCount++;
            }

            // 从背包的最大容量开始倒序更新 dp 数组
            for (int i = m; i >= zeroCount; i--)
            {
                for (int j = n; j >= oneCount; j--)
                {
                    // 选择放入当前字符串或不放入当前字符串
                    dp[i, j] = Math.Max(dp[i, j], dp[i - zeroCount, j - oneCount] + 1);
                }
            }
        }

        // 返回使用最多 m 个 '0' 和 n 个 '1' 时可以获得的最大字符串数量
        return dp[m, n];
    }
}
summary
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值