题目:
给你一个二进制字符串数组 strs 和两个整数 m 和 n 。
请你找出并返回 strs 的最大子集的大小,该子集中 最多 有 m 个 0 和 n 个 1 。
如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。
输入:strs = [“10”, “0001”, “111001”, “1”, “0”], m = 5, n = 3
输出:4
解释:最多有 5 个 0 和 3 个 1 的最大子集是 {“10”,“0001”,“1”,“0”} ,因此答案是 4 。
其他满足题意但较小的子集包括 {“0001”,“1”} 和 {“10”,“1”,“0”} 。{“111001”} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。
思路:
- 动态规划
- 确定最终结果:最长的字符串数组
- 状态:字符串数组长度
- 辅助数组 d p [ m + 1 ] [ n + 1 ] dp[m+1][n+1] dp[m+1][n+1]
- d p [ m ] [ n ] dp[m][n] dp[m][n]代表最终答案。
状态转移方程:
d
p
[
i
]
[
j
]
=
M
a
t
h
.
m
a
x
(
1
+
d
p
[
i
−
z
e
r
o
]
[
j
−
o
n
e
]
,
d
p
[
i
]
[
j
]
)
(1)
dp[i][j] = Math.max(1+dp[i-zero][j-one],dp[i][j])\tag 1
dp[i][j]=Math.max(1+dp[i−zero][j−one],dp[i][j])(1)
遍历字符串时,如果当前字符串加入后可以比未加入的结果数目多,就增加这个字符串。 ( 1 ) (1) (1)中的 z e r o zero zero表示当前遍历到的字符串中 0 0 0的数目, o n e one one表示1的数目。
public class Main{
public int solve(String[] str,int m,int n){
//判空条件省略
int dp[][] = new dp[m+1][n+1];
for(String s: str){
int zero = getZ(s);
int one = s.length()-zero;
//当z小于这个字符串时,这个串不可能放在dp[z][o]位置
for(int z=m;z>=zero;z--){
for(int o=n;o>=one;o--){
dp[z][o] = Math.max(1+dp[z-zero][o-one],dp[z][o]);
}
}
}
return dp[m][n];
}
/**
*return 获得0的数目
**/
public int getZ(String s){
if(s==null||s.equals(""))return 0;
for(int i=0;i<s.length();i++){
if(s.charAt(i) == '0')
count+=1;
}
return count;
}
}
来源:力扣(LeetCode) 链接