322. 零钱兑换
dp数组存储amount=j时的最少硬币数。
状态转移方程:
d
p
[
j
]
=
m
i
n
(
d
p
[
j
]
,
d
p
[
j
−
c
o
i
n
s
[
i
]
]
+
1
)
dp[j] = min(dp[j], dp[j-coins[i]]+1)
dp[j]=min(dp[j],dp[j−coins[i]]+1)
因为是取最小,所以初始化需要赋值为最大值。根据题目数据范围可知:coins[i]>=1,因此可以组成amount的硬币数至多amount个。所有将dp数组初始化为amount+1。dp[0]需要初始化为0,因为amount=0时不需要取硬币,因此硬币数为0。
时间复杂度:
O
(
n
∗
m
)
O(n*m)
O(n∗m)
空间复杂度:
O
(
n
)
O(n)
O(n)
// c++
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
if(amount==0) return 0;
vector<int> dp(amount+1, amount+1);
dp[0] = 0;
for(int i=0; i<coins.size(); i++){
for(int j=coins[i]; j<=amount; j++){
dp[j] = min(dp[j], dp[j-coins[i]]+1);
}
/*
// 输出dp数组
for(int j=0;j<=amount;j++) cout<<dp[j]<<" ";
cout<<endl;
*/
}
return dp[amount]==amount+1?-1:dp[amount];
}
};
279. 完全平方数
和上题思路完全一致,只是需要自行初始化一个完全平方数数组,相当于上题的硬币数组。
时间复杂度:
O
(
n
∗
n
)
O(n*\sqrt{n})
O(n∗n)
空间复杂度:
O
(
n
)
O(n)
O(n)
版本一(存储平方数)
// c++
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n+1, n+1);
vector<int> square;
for(int i=0; i<=sqrt(n); i++){
square.emplace_back(i*i);
}
dp[0] = 0;
for(int i=1; i<square.size(); i++){
for(int j=square[i]; j<=n; j++){
dp[j] = min(dp[j], dp[j-square[i]]+1);
}
/*
// 输出dp数组
for(int j=0;j<=n;j++) cout<<dp[j]<<" ";
cout<<endl;
*/
}
return dp[n];
}
};
版本二(不存储平方数)
// c++
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n+1, n+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);
}
/*
// 输出dp数组
for(int j=0;j<=n;j++) cout<<dp[j]<<" ";
cout<<endl;
*/
}
return dp[n];
}
};
*139. 单词拆分
一开始想的是用回溯暴力搜索,动规毫无思路……
时间复杂度:
O
(
n
3
)
O(n^3)
O(n3)
空间复杂度:
O
(
n
)
O(n)
O(n)
// c++
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> wordset(wordDict.begin(), wordDict.end());
vector<bool> dp(s.size()+1, false);
dp[0] = true;
for(int i=1; i<=s.size(); i++){
for(int j=0; j<i; j++){
string str = s.substr(j, i-j);
if(wordset.find(str)!=wordset.end() && dp[j]){
dp[i] = true;
}
}
}
return dp[s.size()];
}
};