算法题——Ones and Zeroes(JAVA)动态规划

题目描述:
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.

读题:
有一定数量的0和1,组成数组中尽量多的字符串。类似于一个二维的揹包问题。

知识储备:
揹包问题
令V(i,j)表示在前i(1<=i<=n)个物品中能够装入容量为就j(1<=j<=C)的揹包中的物品的最大价值,则可以得到如下的动态规划函数:

(1)   V(i,0)=V(0,j)=0 
(2) V(i,j)=V(i-1,j) ,j < wi
V(i,j)=max{V(i-1,j) ,V(i-1,j-wi)+vi) } ,j>wi

(1)式表明:如果第i个物品的重量大于揹包的容量,则装人前i个物品得到的最大价值和装入前i-1个物品得到的最大价是相同的,即物品i不能装入揹包;
第(2)个式子表明:如果第i个物品的重量小于揹包的容量,则会有一下两种情况:
(a)如果把第i个物品装入揹包,则揹包物品的价值等于第i-1个物品装入容量位j-wi 的揹包中的价值加上第i个物品的价值vi;
(b)如果第i个物品没有装入揹包,则揹包中物品价值就等于把前i-1个物品装入容量为j的揹包中所取得的价值。显然,取二者中价值最大的作为把前i个物品装入容量为j的揹包中的最优解。

解题思路:
动态规划:解决子问题并记录子问题的解
子问题为:要不要组建这个字符串。
在有i个待选字符串,原料为m n的情况下揹包问题下:
最优解是什么?

第i+1个字符串可以选择放进揹包或者不放进揹包?
假设放进揹包(前提是放得下),
那么f[m][n][i+1]=f[m-weight[i+1]][n-weight[i+1]][i]+1;
如果不放进揹包,
那么f[m][n][i+1]=f[m][n][i]。
也就是:
f[m][n][i+1]=max(f[m][n][i],f[m-weight[i+1]][n-weight[i+1]][i]+1)。

提交代码:

public class Solution {
    private int[][][] dpTable;//保存状态结果
    public int findMaxForm(String[] strs, int m, int n) {
        int len = strs.length;
        int arr[][] = new int[len][2]; 
        int res = 0;
        //计算字符串中0和1的个数
        for (int i = 0; i < len; i++) {
            char[] chars = strs[i].toCharArray();
            int zero = 0;
            int one = 0;
            for (int j = 0; j < chars.length; j++) {
                if (chars[j] == '1')
                    one++;
                else
                    zero++;
            }
            arr[i][0] = zero;
            arr[i][1] = one;
            arr[i][2] = one+zero;
        }
        dpTable = new int[m+1][n+1][len];
        return FormTable(arr, len, m, n, 0);
    }
    private int FormTable(int[][] arr, int len, int m, int n, int pos) {
        if (m+n == 0 || pos == len) {
            return 0;
        }
        //如果之前已经算过了,则直接取出数据
        if (dpTable[m][n][pos] > 0) {
            return dpTable[m][n][pos];
        }
        int addCount = 0;
        //加入这条字符串的情况
        if (m >= arr[pos][0] && n >= arr[pos][1]) {
            addCount = FormTable(arr, len, m-arr[pos][0], n-arr[pos][1], pos+1) + 1;
        }
        //不加入这条字符串的情况
        int unaddCount = FormTable(arr, len, m, n, pos+1);
        if (addCount > unaddCount) {
            dpTable[m][n][pos] = addCount;
        } else {
            dpTable[m][n][pos] = unaddCount;
        }
        return dpTable[m][n][pos];
    }
}
点赞