题目
知识点
思路
- 我们可以把它转换为背包问题:
m
和n
作为容量,每一个字符串看作是物品,每个价值为1。那么,我们就可以把原问题转换为:在max(m)
和max(n)
情况下取得物品的最大价值。注意,字符串不能重复,因此我们还需要添加一个状态,去求得:前i
个物品,在max(m)
和max(n)
情况下取得物品的最大价值。 - 所以状态转移方程就可以得到:
dp[i][m][n] = max(dp[i - 1][m][n],dp[i - 1][m - 当前i物品所需要的m空间][n - 当前i物品所需要的n空间]
其中,dp[i - 1][m][n]
就是不取第i个物品的最大价值(即前i-1
个物品在m
和n
取得的最大价值)。dp[i - 1][m - 当前i物品所需要的m空间][n - 当前i物品所需要的n空间]
就是把第i
个物品放入背包的价值,那么,如果要放得下,就是在容量m - 当前i物品所需要的m空间
和n - 当前i物品所需要的n空间
情况下取得的最大价值加上当前物品的价值(1)。 - 这样,
dp[i][max(m)][max(n)]
得到的就是前i
个物品,在max(m)
和max(n)
情况下取得物品的最大价值。
代码
- 一些小细节放在注释中了
- 单独对第0个物品计算结果(Line 6-13),不然后面的
vis[i][m][n] = max(vis[i - 1][m][n], vis[i - 1][m - m_num[i]][n - n_num[i]] + 1)
(Line 20)溢出了。
class Solution {
public:
int vis[601][101][101];
int ed_m, ed_n;
int dp(vector<int> &m_num, vector<int> &n_num) {
for (int m = 0; m <= ed_m; m++) {
for (int n = 0; n <= ed_n; n++) {
if (m - m_num[0] >= 0 && n - n_num[0] >= 0) {
vis[0][m][n] = 1;
}
}
}
for (int i = 1; i < m_num.size(); i++) {
for (int m = 0; m <= ed_m; m++) {
for (int n = 0; n <= ed_n; n++) {
vis[i][m][n] = vis[i-1][m][n];
if (m - m_num[i] >= 0 && n - n_num[i] >= 0) {
vis[i][m][n] = max(vis[i - 1][m][n], vis[i - 1][m - m_num[i]][n - n_num[i]] + 1);
}
}
}
}
return vis[m_num.size() - 1][ed_m][ed_n];
}
int findMaxForm(vector<string> &strs, int m, int n) {
ed_m = m, ed_n = n;
memset(vis, 0, sizeof(int[601][101][101]));
vector<int> m_n(strs.size(), 0), n_n(strs.size(), 0);
for (int i = 0; i < strs.size(); i++) {
for (char j:strs[i]) {
if (j == '0') m_n[i]++;
if (j == '1') n_n[i]++;
}
}
return dp(m_n, n_n);
}
};