首先来个热身的例子:
力扣总结:总结公式
这个一开始我以为就是个单纯的贪心问题,结果按照贪心的思路去做,果然wr了,提交错误。。。。。
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
Arrays.sort(strs, new Comparator<String>() {
public int compare(String a, String b) {
if(a.length() == b.length())
return a.compareTo(b);
else
return a.length()-b.length();
}
});
int res = 0;
for(int i = 0; i < strs.length; i++){
int[] temp = count(strs[i]);
if(m - temp[0] >= 0 && n - temp[1] >= 0){
m = m - temp[0];
n = n - temp[1];
res ++;
}
}
return res;
}
public int[] count(String str){
int[] res = new int[2];
for(int i = 0; i<str.length(); i++){
if(str.charAt(i) == '0') res[0]++;
if(str.charAt(i) == '1') res[1]++;
}
return res;
}
}
像这个例子,按照贪心,应该先凑成短字符串111,结果1用完了,但是先凑后面三个得到的更多。后来仔细一看,还是个背包问题,二重背包,有两个条件,再加上题干中m,n都小于100,大概懂了,应该是三重循环。
AC代码:
public int findMaxForm(String[] strs, int m, int n) {
Map<Integer, Integer[]> map = new HashMap<>();
for(int i = 0; i<strs.length; i++) {
Integer[] t = count(strs[i]);
map.put(i,t);
}
int[][] dp = new int[m+1][n+1];
for(int i = 0; i<strs.length; i++){
Integer[] r = map.get(i);
for(int j = m; j>=r[0]; j--)
for(int k = n; k>=r[1]; k--){
dp[j][k] = Math.max(dp[j][k], dp[j-r[0]][k-r[1]]+1);
}
}
return dp[m][n];
}
public Integer[] count(String str){
Integer[] res = new Integer[2];
Arrays.fill(res,0);
for(int i = 0; i<str.length(); i++){
if(str.charAt(i) == '0') res[0]++;
if(str.charAt(i) == '1') res[1]++;
}
return res;
}
}
完全背包问题:
完全背包问题模板:这里需要注意的是,我们根据问题的定义,dp的含义也有所不同,我们需要求的是多少种方式,dp[j] = dp[j]+dp[j-arr[i]]
表示就是凑成额度为j,需要两种方式相加,而非之前的两种最大
class Solution {
public int waysToChange(int n) {
if(n == 0) return 1;
int[] dp = new int[n+1];
dp[0] = 1;
int[] arr = {1,5,10,25};
for(int i = 0; i<4; i++){
for(int j = arr[i]; j<=n; j++){
dp[j] = (dp[j] + dp[j-arr[i]]) % 1000000007;
}
}
return dp[n];
}
}