474. Ones and Zeroes

来源:互联网 发布:linux cdn搭建 编辑:程序博客网 时间:2024/05/21 09:35

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".

思路:最开始想BS,因为是需要满足一定条件的最值问题,但是怎么判断能不能组成n个的情况呢?
 如果遍历每个字符串的,采用不采用这个貌似都可以转换为与原问题类似的问题这好像有点像DP,先写个递归版本理一下思路(其实熟练了可以直接写DP)

public class Recusive {Map<String, Integer> map = new HashMap<String, Integer>();    public int findMaxForm(String[] strs, int m, int n) {        return findMaxForm(strs, 0, m, n);    }private int findMaxForm(String[] strs, int i, int m, int n) {if(map.containsKey(i+" "+m+" "+n))return map.get(i+" "+m+" "+n);if(i == strs.length)return 0;char[] cs = strs[i].toCharArray();int c1=0, c0=0;for(char c : cs)if(c=='1')c1++;else c0++;int ret = findMaxForm(strs, i+1, m, n);if(m>=c0 && n>=c1)ret = Math.max(ret, 1+findMaxForm(strs, i+1, m-c0, n-c1));map.put(i+" "+m+" "+n, ret);return ret;}}

因为不能重复使用一个数,所以用dp数组的话需要3维数组,额,还是先看下优化下memo能不能AC把,TLE后有2中想法

(1)c0, c1先算出来,但是从TLE的case来看并不是这个

(2)map里面不要单纯的放数组的index,这丢失了每个字符串实际的信息,尝试吧Str数组转换为String

public class Memo_TLE {Map<String, Integer> map = new HashMap<String, Integer>();String[] ss;    public int findMaxForm(String[] strs, int m, int n) {    Arrays.sort(strs);// 先排序一下可以调整计算方向        ss = new String[strs.length];   for(int i=strs.length-1; i>=0; i--)   if(i == strs.length-1)ss[i] = strs[i];   else ss[i] = strs[i]+" " + ss[i+1];            return findMaxForm(strs, 0, m, n);    }private int findMaxForm(String[] strs, int i, int m, int n) {if(i == strs.length)return 0;String key = ss[i]+" "+m+" "+n;if(map.containsKey(key))return map.get(key);char[] cs = strs[i].toCharArray();int c1=0, c0=0;for(char c : cs)if(c=='1')c1++;else c0++;int ret = findMaxForm(strs, i+1, m, n);if(m>=c0 && n>=c1)ret = Math.max(ret, 1+findMaxForm(strs, i+1, m-c0, n-c1));map.put(key, ret);return ret;}}

还是TLE,那就用3维数组把

public class WA {    public int findMaxForm(String[] strs, int m, int n) {    // dp[n]好像并不能由dp[n-1]推出,比如Input: Array = {"10", "0", "1"}, m = 1, n = 1        int[][] cnt = new int[strs.length][2];    for(int i=0; i<strs.length; i++) {    char[] cs = strs[i].toCharArray();    for(char c : cs)cnt[i][c-'0']++;    }        int[][][] dp = new int[1+m][1+n][1+strs.length];    for(int i=1; i<=m; i++)    for(int j=1; j<=n; j++)    for(int k=1; k<=strs.length; k++)     if(i-cnt[k-1][0]>=0 && j-cnt[k-1][1]>=0)    dp[i][j][k] = Math.max(dp[i][j][k-1], 1+dp[i-cnt[k-1][0]][j-cnt[k-1][1]][k-1]);    else    dp[i][j][k] = dp[i][j][k-1];            return dp[m][n][strs.length];    }}

但是其实上面的状态转移方程是错的,dp[0..n-1]最佳并不能推出dp[n]最佳,关系建立不起来

换一种思路:来一个string,就全部更新dp[][]数组中的值,每次更新完dp[][]都是:就目前这些字符串的最佳结果
感觉有点类似floyd算法,policy iteration算法


因为字符串是一个个来的,在更新当前字符串对应的dp时就只能用之前的dp数组值,也就是要考虑数组被覆盖的问题
从另外一个角度来说就是:因为不能重复用一个数,如果先求小的dp[i][j],小的dp可能已经用了当前字符串,大的dp再求max的时候仍然可以再次使用当前字符串,所以dp求的顺序是先大后小(缓存dp数组又另当别论)

public class Solution {    public int findMaxForm(String[] strs, int m, int n) {        int[][] cnt = new int[strs.length][2];    for(int i=0; i<strs.length; i++) {    char[] cs = strs[i].toCharArray();    for(char c : cs)cnt[i][c-'0']++;    }        int[][] dp = new int[1+m][1+n];    for(int k=0; k<strs.length; k++)    for(int i=m; i>=cnt[k][0]; i--)    for(int j=n; j>=cnt[k][1]; j--)    dp[i][j] = Math.max(dp[i][j], 1+dp[i-cnt[k][0]][j-cnt[k][1]]);            return dp[m][n];    }}


之前是怎么想的,不就是“以什么什么结尾”的套路吗?