简述
本文主要介绍动态规划问题的解法模板,以leetcode474为例,该问题为01背包问题的变体。
题目描述
给定字符串数组,数组中的元素由“0”或者“1”构成,若给定子字符串数组中存在“0”的个数最多为m、存在“1”的个数最多为n,返回满足该条件的子字符串数组的最大长度。
注 : 原字符串数组为[“10”,“0001”,“111001”,“1”,“0”],[“1”]、[“1”,“0”]…等都为其子字符串数组。
1、确定数组下标及值含义
value = dp[i][j];其中 0 <= i <= m、 0 <= j <= n;
该数组下标的含义:
i代表“0”存在的数量,j代表“1”存在的数量。
value的含义:
代表子字符串数组满足“0”的数量不多于i,“1”的数量不多于j的条件时,该数组的最大长度。
2、确定动态转移方程
根据数组下标及值含义,我们可以确定动态转移方程为:
dp[i][j] = max(dp[i][j], dp[i - numberOfZero][j - numberOfOne] + 1)
注:其中numberOfZero代表从字符串数组中取出元素包含“0”的数量,numberOfOne代表取出元素包含"1"的数量。
该动态转移方程的含义:求满足条件的dp[i][j]的最大值。
3、dp数组初始化
dp[0][0] = 0 代表下标i,j均为零时,该字符串数组的长度。
其余元素均初始化零,因为所有的dp[i][j] >= 0,初始化为0不影响转移方程的递推。
4、确定遍历的顺序
为防止物品被重复放入,物品被放在最外层遍历,而i和j放在里层遍历。
实现代码如下
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>> vec;
for (int i = 0; i < strs.size(); ++i) {
vector<int> vecRes = calNum(strs[i]);
vec.push_back(vecRes);
}
vector<int> vecN(n + 1, 0);
vector<vector<int>> vecMN(m + 1, vecN);
for (int k = 0; k < vec.size(); ++k) {
for (int i = m; m >= vec[k][0]; --i)
for (int j = n; n >= vec[k][1]; --j) {
vecMN[i][j] = max(vecMN[i][j], vecMN[i - vec[k][0]][j - vec[k][1]] + 1);
}
}
return vecMN[m][n];
}
vector<int> calNum(string str) {
int m = 0;
int n = 0;
for (int i = 0; i < str.size(); ++i) {
if (str[i] == '0') {
m++;
}
else if (str[i] == '1') {
n++;
}
}
vector<int>vec;
vec.push_back(m);
vec.push_back(n);
return vec;
}
};