动态规划
70. 爬楼梯
题意:假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
实例:
思路:本题我们之前也讲解过,实在有点简单,还不会的朋友,可以看我第一期的动态规划算法练习
C++代码:
int climbStairs(int n) {
vector<int> dp(n+1,0);
dp[0]=1,dp[1]=1;
for(int i=2;i<=n;i++)
{
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
322. 零钱兑换
题意:给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
实例:
思路:本题我们还是使用动态规划的思想,先去创建一个数组dp[amount+1],每个位置表示该大小下的最小硬币个数;并且在初始化时,给0号位置赋0,其他位置变为INT_MAX-1,这里本来可以使用INT_MAX,但是在测试用例中系统会去计算INT_MAX+1,越界了,因此我们给出INT_MAX-1。
然后在来说下递推公式,这个就比较简单了,每个元素无限次使用,因此背包和物品的遍历顺序无所谓;公式为dp[i]=min(dp[i],dp[i-coins[j]]+1)
最后,当dp数组的最后一个元素改变时,就说明有符合条件的元素集合,否则没有符合条件的元素集合,返回-1.
C++代码:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount+1,INT_MAX-1);//凑足总额为n所需钱币的最少个数为dp[n]
dp[0]=0;
for(int i=0;i<=amount;i++)
{
for(int j=0;j<coins.size();j++)
{
if(i-coins[j]>=0)
{
dp[i]=min(dp[i],dp[i-coins[j]]+1);
}
}
}
return dp[amount]==INT_MAX-1?-1:dp[amount];
}
279.完美方块
题意:给你一个整数 ,返回 和为 n 的完全平方数的最少数量 。n完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,、、 和 都是完全平方数,而 和 不是。14916311
实例:
思路:本题和上一道题可以说是一模一样,只有两个区别:
- 目标值n必定有解
- 我们需要遍历的硬币方从1到根号n了,更加简单了
代码方面也和上道题一样,直接上代码!!!
C++代码:
int numSquares(int n) {
vector<int> dp(n+1,INT_MAX-1);
dp[0]=0;
for(int i=0;i<=n;i++)
{
for(int j=0;j<=sqrt(n);j++)
{
if(i-j*j>=0)
{
dp[i]=min(dp[i],dp[i-j*j]+1);
}
}
}
return dp[n];
}
139.分词
题意:给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。
注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
实例:
思路:本题我们使用完全背包的思想,先创建一个动态规划数组dp[s.size()+1],dp[i]表示s字符串长度i以及之前的元素都可以由字典中的元素组成。
开始先将数组初始化为false,然后对0长度的位置设置为true,我们判断[i,j]这个区间的元素可以找到的条件是:
- (i,j]组成的元素可以在字典中找到
- dp[i]必须被标记为true
满足以上两点dp[j]才能被标记true。动态规划的思想也就在这里,前免得判断结果会影响到后面的判断结果。
C++代码:
bool wordBreak(string s, vector<string>& wordDict) {
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 ss=s.substr(j,i-j);
if(find(wordDict.begin(),wordDict.end(),ss)!=wordDict.end()&&dp[j]==true)
{
dp[i]=true;
}
}
}
return dp[s.size()];
}