**1. 322. 零钱兑换
dp数组定义:coins数组构成j的组合所需的最少硬币个数
是求组合数,因此先物品后背包
求最小值,初始化为INT_MAX-1,另外dp[0]根据定义设置为0
AC代码:
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int n = coins.size();
vector<int> dp(amount + 1, INT_MAX - 1);
dp[0] = 0;
for (int i = 0; i < n; ++i) {
for (int j = coins[i]; j <= amount; ++j) {
dp[j] = min(dp[j], dp[j - coins[i]] + 1);
}
}
return dp[amount] == (INT_MAX - 1) ? -1 : dp[amount];
}
};
和322. 零钱兑换类似,物品就是各个平方数,即: 注意i的平方可以等于n,也就是n恰好是平方数的情况
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n + 1, INT_MAX - 1);
dp[0] = 0;
for (int i = 1; i * i <= n; ++i) {
for (int j = i * i; j <= n; ++j) {
dp[j] = min(dp[j], dp[j - i * i] + 1);
}
}
return dp[n];
}
};
每个单词都可以使用多次,且不要求顺序,因此是排列问题,先背包后物品
注意递推条件,除了看子串是否与wordDict[i]相等以及前面的j-k位置是否能构成外,当不使用第i个单词也能构成目标串时,即使当前第i个单词不符合条件,因为之前有符合要求的排列组合,因此此时dp[j]也是为true的
代码如下:
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
int n = wordDict.size();
int m = s.size();
// 以wordDict[i]单词结尾,是否能构成字符串s[0...j-1]
vector<bool> dp(m + 1, false);
dp[0] = true;
for (int j = 1; j <= m; ++j) {
for (int i = 0; i < n; ++i) {
int k = wordDict[i].size();
if (j < k) {
continue;
}
dp[j] = dp[j] || (dp[j - k] && (wordDict[i] == s.substr(j - k, k)));
}
}
return dp[m];
}
};