在之前的博客里面提到了动态规划,具体不重复说了,举了简单的例题做,现在来填坑了
记录刷题中遇到的知识点方便复习(七)(动态规划)-CSDN博客
动态规划的核心就是找方程,第i个状态和第j个状态的关系,不仅仅局限于i 与 i-1, i-2的关系,更多的是 i 与 j 不是相邻,多积累。
总结模板:
class Solution {
public:
int numSquares(int n) {
//根据需要生成一个dp数组存放i状态
vector<int> dp(n+1); //可初始化
dp[0] = 0;
//两层循环
for(int i = 1; i<=n; i++){
for(int j = 1; j*j<=i; j++){
/*
状态转移方程
*/
}
}
return dp[n];
}
};
力扣题:
198、打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
比较简单: i 与 i-1 和 i-2有关
class Solution {
public:
int rob(vector<int>& nums) {
if(nums.size() == 1) return nums[0];
vector<int> pre;
pre.push_back(nums[0]);
if(nums[1] >= nums[0]) pre.push_back(nums[1]);
else pre.push_back(nums[0]);
for(int i = 2; i<nums.size(); i++){
if(pre[i-2] + nums[i] > pre[i-1] ) pre.push_back(pre[i-2] + nums[i]);
else pre.push_back(pre[i-1]);
}
return pre[pre.size()-1];
}
};
279、完全平方数
给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
这题之后,就都是i, j 的关系了,套用模板,根据题意进行变化
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n+1);
dp[0] = 0;
for(int i = 1; i<=n; i++){
int min_num = INT_MAX;
for(int j = 1; j*j<=i; j++){
min_num = min(min_num, 1+dp[i-j*j]) ;
}
dp[i] = min_num;
}
return dp[n];
}
};
322、零钱兑换
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int n = coins.size();
vector<int> dp(amount+1);
dp[0] = 0;
for(int i = 1; i<=amount; i++){
int min_num = amount+1;
for(int j = 0; j<n; j++){
if(i-coins[j] >= 0) min_num = min(min_num, 1+dp[i-coins[j]]);
}
dp[i] = min_num;
}
return dp[amount] > amount ? -1 : dp[amount];
}
};
139、单词拆分
给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。
注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> set;
for(int i = 0; i<wordDict.size(); i++) set.insert(wordDict[i]);
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++){
if(set.find(s.substr(j,i-j)) != set.end() && dp[j]){
dp[i] = true;
break;
}
}
}
return dp[s.size()];
}
};
300、最长递增子序列
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
int ans = 1;
if(n == 0) return 0;
vector<int> dp(n, 1);
for(int i = 0; i<n; i++){
for(int j = 0; j<i; j++){
if(nums[i] > nums[j]){
dp[i] = max(dp[j]+1, dp[i]);
ans = max(ans, dp[i]);
}
}
}
return ans;
}
};
需要注意的是:数组访问不要越界