leetcode 474. Ones and Zeroes

来源:互联网 发布:北航网络教育平台 编辑:程序博客网 时间:2024/05/23 18:22

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:

  1. The given numbers of 0s and 1s will both not exceed 100
  2. The size of given string array won't exceed 600.

Example 1:

Input: Array = {"10", "0001", "111001", "1", "0"}, m = 5, n = 3Output: 4Explanation: 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 = 1Output: 2Explanation: You could form "10", but then you'd have nothing left. Better form "0" and "1".
这道题用纯粹的递归做会TLE。我用了递归with memory就AC了。

public int findMaxForm(String[] strs, int m, int n) {int[][] str01Count=new int[strs.length][2];for(int i=0;i<strs.length;i++){char[] cs=strs[i].toCharArray();int count0=0;int count1=0;for(int j=0;j<cs.length;j++){if(cs[j]=='0'){count0++;}else {count1++;}}str01Count[i]=new int[]{count0,count1};}Integer[][][] memo=new Integer[strs.length][m+1][n+1];return helper(str01Count, 0, m, n, memo);}public int helper(int[][] str01Count,int index,int m,int n,Integer[][][] memo){if(index>=str01Count.length){return 0;}if(memo[index][m][n]!=null){return memo[index][m][n];}int maxCount=0;int count1=helper(str01Count, index+1, m, n,memo);int count2=0;if(m>=str01Count[index][0]&&n>=str01Count[index][1]){count2=1+helper(str01Count, index+1, m-str01Count[index][0], n-str01Count[index][1],memo);}maxCount=Math.max(count1, count2);memo[index][m][n]=maxCount;return maxCount;}
大神说这是个典型的0/1背包问题,用DP做。

构造三维数组:dp[i][j][k] 表示:限制使用 j 个0,k个 1,从 0~i 范围内的strs  能构造最多几个字符串。

对于 dp[i][j][k], 当前判断的字符串是 strs[i], 我们要么取它,要么抛弃它。因此 dp[ i ][ j ][ k ] = dp[ i-1 ][ j-numOf0(strs[i]) ][ i-numOf1(strs[i]) ] 或者dp[ i ][ j ][ k ] = dp[ i-1 ][ j ][ k ]; 我们只需要取两者中较大的那个,来赋值给 dp[i][j][k]。

public int findMaxForm(String[] strs, int m, int n) {    int l = strs.length;    int[][][] dp = new int[l+1][m+1][n+1];        for (int i = 1; i <= l; i++) {        int[] nums = new int[]{0,0};        nums = calculate(strs[i-1]);        for (int j = 0; j < m+1; j++) {            for (int k = 0; k < n+1; k++) {                if (j>=nums[0] && k>=nums[1]) {                    dp[i][j][k] = Math.max(dp[i-1][j][k], dp[i-1][j-nums[0]][k-nums[1]]+1);                } else {                    dp[i][j][k] = dp[i-1][j][k];                }            }        }    }        return dp[l][m][n];}private int[] calculate(String str) {    int[] res = new int[2];        for (char ch : str.toCharArray()) {        if (ch == '0') {            res[0]++;        } else if (ch == '1') {            res[1]++;        }    }        return res;}

背包问题我们无法减少时间复杂度,但是可以减少空间复杂度,从 ijk 减少到 j*k 。

对于每个 str, 假定它有 a 个"0"s 和 b 个"1"s。关系式为 dp[i][j] = Math.max(dp[i][j], dp[i - a][j - b] + 1) 。

public int findMaxForm(String[] strs, int m, int n) {    int l = strs.length;    int[][] dp = new int[m+1][n+1];    int[] nums = new int[]{0,0};    for (String str : strs) {        nums = calculate(str);        for (int j = m; j >= nums[0]; j--) {            for (int k = n; k >= nums[1]; k--) {                if (j>=nums[0] && k>=nums[1]) {                    dp[j][k] = Math.max(dp[j][k], dp[j-nums[0]][k-nums[1]]+1);                } else {                    dp[j][k] = dp[j][k];                }            }        }    }        return dp[m][n];}private int[] calculate(String str) {    int[] res = new int[2];        for (char ch : str.toCharArray()) {        if (ch == '0') {            res[0]++;        } else if (ch == '1') {            res[1]++;        }    }        return res;}

If you know Chinese, http://love-oriented.com/pack/P01.html would help you a lot.


原创粉丝点击