01背包问题的扩展——二维费用 LeetCode 474

  上一讲的01背包问题是最基础的背包问题,只有一维费用变量。这一讲接触到二维费用变量。其实相对之前,只是多了一维而已,所以状态转移公式有所变化,如下:
  f[i][v][u]=max{f[i-1][v][u],f[i-1][v-c[i]][u-d[i]]+w[i]}
  因此,在套用01背包问题优化空间复杂度后的代码时,需要补充增加一维的工作。
  上一讲最后,对于LeetCode 494【续】中的01背包问题的代码如下,这是一维的。

 public int subsetSum(int[] nums, int s) {
    int[] dp = new int[s + 1]; 
    dp[0] = 1;
    for (int n : nums)
        for (int i = s; i >= n; i--)
            dp[i] += dp[i - n]; 
    return dp[s];
}

  对比来看看本讲的题——LeetCode 474。

In the computer world, use restricted resource you have to generate maximum benefit is what we always want to pursue.

For now, suppose you are a dominator of m 0s and n 1s respectively. On the other hand, there is an array with strings consisting of only 0s and 1s.

Now your task is to find the maximum number of strings that you can form with given m 0s and n 1s. Each 0 and 1 can be used at most once.

Note:
The given numbers of 0s and 1s will both not exceed 100
The size of given string array won’t exceed 600.
Example 1:
Input: Array = {“10”, “0001”, “111001”, “1”, “0”}, m = 5, n = 3
Output: 4

Explanation: This are totally 4 strings can be formed by the using of 5 0s and 3 1s, which are “10,”0001”,”1”,”0”
Example 2:
Input: Array = {“10”, “0”, “1”}, m = 1, n = 1
Output: 2

Explanation: You could form “10”, but then you’d have nothing left. Better form “0” and “1”.

  这里对于每一个要加入的数字,都要考虑其中“0”和“1”位数的两个因素。因此是二维的。但很明显依旧是背包问题:给定一个序列,给定一个目标,求是否能从序列中取出一定的元素,使其目标值最大。
  既然是类01背包问题,自然就可以套用该问题的一般代码公式。只是这里需要增加一维。因此需要增加一个循环。注意,01背包问题的状态转移公式一般是不变的,但是根据所求内容不同,会有所区别。494是统计达到目标和一共有多少种情况,所以用的是 dp[i] += dp[i - n]; 这种累加。而本题474是取使得目标和最大的一种情况,所以用的是 Math.max 这种判断选取。并且这两种问题的初始化也会有所区别。
  代码如下:

    public int findMaxForm(String[] strs, int m, int n) {
        int dp[][] = new int[m+1][n+1];
        //初始化和494题有区别。494题最终要求所选序列元素等于给定目标,而本题要求目标和尽可能大。
        for(int i = 0;i<=m;i++){
            for(int j = 0;j<=n;j++){
                dp[i][j] = 0;
            }
        }

        for(String s : strs){
            int[] c01 = StringHas01(s);
            //内层循环增加一个维度,注意本题不要用一个循环包含两个维度,例如for(int i = m, j = n; i >= c01[0] && j >= c01[1]; i--,j--){}。这样是错的,会导致遗漏在i等于某一个值时,其他一些j值的情况。所以需要分成两层循环。
            for(int i = m; i >= c01[0]; i--)
                for(int j = n; j >= c01[1]; j--){
                    //状态转移公式不变,但是代码与494有所区别。这里需要取最大值,而不是+=这种累加。因为本题是取使得目标和最大的一种情况。而494是统计达到目标和一共有多少种情况。
                    dp[i][j] = Math.max(1+dp[i-c01[0]][j-c01[1]],dp[i][j]);
                }
        }
        return dp[m][n];
    }
    private int[] StringHas01(String s){
        int[] c01 = {0,0};
        int l = s.length();
        for(int i = 0;iif(s.charAt(i) == '0')
                c01[0]++;
            if(s.charAt(i) == '1')
                c01[1]++;
        }
        return c01;
    }

你可能感兴趣的:(LeetCode,算法)