挑战dp----一和零(动态规划)

474. 一和零
在计算机界中,我们总是追求用有限的资源获取最大的收益。
现在,假设你分别支配着 m 个 0 和 n 个 1。另外,还有一个仅包含 0 和 1 字符串的数组。
你的任务是使用给定的 m 个 0 和 n 个 1 ,找到能拼出存在于数组中的字符串的最大数量。每个 0 和 1 至多被使用一次。
注意:
给定 0 和 1 的数量都不会超过 100。
给定字符串数组的长度不会超过 600。

示例 1:

输入: Array = {"10", "0001", "111001", "1", "0"}, m = 5, n = 3
输出: 4
解释: 总共 4 个字符串可以通过 5 个 0 和 3 个 1 拼出,即 "10","0001","1","0" 。

示例 2:

输入: Array = {"10", "0", "1"}, m = 1, n = 1
输出: 2
解释: 你可以拼出 "10",但之后就没有剩余数字了。更好的选择是拼出 "0" 和 "1" 。

题目链接(leetcode)

思路:这是一个变形的01背包问题,只是多了一个状态,对于每一个字符串,都可以选和不选。定义一个三维数组,dp[i][j][k]表示拥有i个1、j个0在第k个数组之前可拼出的字符串最大数量。
1、如果当前的i个1、j个0多于或等于第k个字符串的01数量,可拼凑第k个字符串,第k个字符串的0、1个数为cnt0、cnt1,即dp[i][j][k]=dp[i-cnt][j-cnt0][k-1]。
2、如果当前的01个数无法拼凑出第k个字符串,此时的最大数为当前的01个数到第k-1个字符串为止的最大数,即dp[i][j][k]=dp[i][j][k-1]。

参考代码:

class Solution {
    public int findMaxForm(String[] strs, int m, int n) 
	{
		int[][][] dp = new int[n+1][m+1][strs.length+1];
		for(int i = 0;i <= n;i++)
		{
			for(int j = 0;j <= m;j++)
			{
				for(int k = 1;k <= strs.length;k++)
				{
					dp[i][j][k] = dp[i][j][k-1];
					int cnt0 = getCnt0(strs[k-1]);
					int cnt1 = strs[k - 1].length() - cnt0;
					if(j >= cnt0 && i >= cnt1)
						dp[i][j][k] = Math.max(dp[i][j][k], dp[i-cnt1][j-cnt0][k-1]+1);
				}
			}
		}
		return dp[n][m][strs.length];
    }

	private int getCnt0(String s) 
	{
		int ans = 0;
		for(int i = 0;i < s.length();i++)
			if(s.charAt(i) == '0')
				ans++;
		return ans;
	}
}
发布了72 篇原创文章 · 获赞 18 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41022094/article/details/103687771