赞
踩
//递归做法
class Solution {
public:
int fib(int n) {
if(n==0)
return 0;
else if(n==1)
return 1;
else{
return fib(n-1)+fib(n-2);
}
}
};
//动态规划做法 class Solution { public: int fib(int n) { if (n <= 1) return n; int dp[2]; dp[0] = 0; dp[1] = 1; for (int i = 2; i <= n; i++) { int sum = dp[0] + dp[1]; dp[0] = dp[1]; dp[1] = sum; } return dp[1]; } };
class Solution {
public:
int climbStairs(int n) {
vector<int> dp(n+2);
dp[0]=0;
dp[1]=1;
dp[2]=2;
for(int i=3;i<=n;i++)
{
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
};
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n=cost.size();
vector<int> dp(n+1);
dp[0]=0;
// dp[1]=dp[0]+cost[0];
dp[1]=0;
for(int i=2;i<=cost.size();i++)
{
dp[i]=min(cost[i-1]+dp[i-1],cost[i-2]+dp[i-2]);
}
return dp[cost.size()];
}
};
class Solution { public: int uniquePaths(int m, int n) { vector<vector<int>> dp(m, vector<int>(n, 0)); dp[0][0] = 0; for(int i=1;i<n;i++) dp[0][i]=1; for(int i=1;i<m;i++) dp[i][0]=1; for (int i = 1; i <= m - 1; i++) { for (int j = 1; j <= n - 1; j++) { dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; } } // 打印 dp 数组 cout << "DP Array:" << endl; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { cout << dp[i][j] << " "; } cout << endl; } return dp[m - 1][n - 1]; } };
class Solution { public: int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) { int m = obstacleGrid.size(); int n = obstacleGrid[0].size(); vector<vector<int>> dp(m,vector<int>(n,0)); if(obstacleGrid[0][0]==1 || obstacleGrid[m-1][n-1]==1) { return 0; } dp[0][0]=1; for(int i=0;i<n && obstacleGrid[0][i]==0;i++){ dp[0][i]=1; } for(int i=0;i<m && obstacleGrid[i][0]==0;i++){ dp[i][0]=1; } for(int i=1;i<m;i++) for(int j=1;j<n;j++) { if(obstacleGrid[i][j]!=1) dp[i][j]=dp[i-1][j]+dp[i][j-1]; } for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { cout<<dp[i][j]<<' '; } cout<<endl; } return dp[m-1][n-1]; } };
class Solution { public: int integerBreak(int n) { vector<int> dp(n+1,0); dp[0]=0; dp[1]=0; dp[2]=1; for(int i=3;i<=n;i++) for(int j=1;j<i;j++) { dp[i]=max(dp[i], max((i - j) * j, dp[i - j] * j)); } return dp[n]; } };
class Solution { public: int numTrees(int n) { vector<int> dp(n+2,0); dp[0]=1; dp[1]=1; dp[2]=2; // dp[3] = 头1+头2+头3=(左0*右2+左1*右1+左2*右0) for(int i=3;i<=n;i++) { for(int j=1;j<=i;j++) { dp[i]+=dp[j-1]*dp[i-j]; } } return dp[n]; } };
我怎么看不懂这个呢!!
有一堆石头,每块石头的重量都是正整数。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:
如果 x == y,那么两块石头都会被完全粉碎;
如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块石头。返回此石头最小的可能重量。如果没有石头剩下,就返回 0。
示例:
输入:[2,7,4,1,8,1]
输出:1
解释:
组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1],
组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。
⭐️ 相当于尽量将石头分配为重量相近的两堆——sum为复数且两堆重量相等,则最后不剩下来石头了。这个是01背包问题!
01背包的递推公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
循环注意事项:
先循环石头,再倒序循环背包(因为一个物品只能装一次)。j>stones[i]
的条件一是因为在装入的时候要确认背包容量还够用,(通过dp[j-stones[i]]
不能越界来记住条件要求!)
class Solution { public: int lastStoneWeightII(vector<int>& stones) { int sum = 0; for(int i=0;i<stones.size();i++){ sum+=stones[i]; } int halfsum = sum / 2; vector<int> dp(halfsum+1,0); for(int i=0;i<stones.size();i++){ //stone for(int j = halfsum;j>=stones[i];j--) //背包 dp[j] = max(dp[j],dp[j-stones[i]]+stones[i]); } if(dp[halfsum]*2 ==sum) return 0; else return sum-2*dp[halfsum]; } };
给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。
返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
示例:
输入:nums: [1, 1, 1, 1, 1], S: 3
输出:5
⭐️ 这里需要分成两半数据,一半是正数,剩下的一半是负数。假设加法的总和为x,那么减法对应的总和就是sum - x。所以我们要求的是 x - (sum - x) = target x = (target + sum) / 2
⭐️ 不论是回溯法暴力求解还是使用动态规划背包问题的思想来做,目标值都是这个求到的x,放和为多少的正数放进path。
动态规划:
dp[j] 表示:填满j(包括j)这么大容积的包,有dp[j]种方法
只要搞到nums[i],凑成dp[j]就有dp[j - nums[i]] 种方法。
例如:dp[j],j 为5,
已经有一个1(nums[i]) 的话,有 dp[4]种方法 凑成 容量为5的背包。
已经有一个2(nums[i]) 的话,有 dp[3]种方法 凑成 容量为5的背包。
已经有一个3(nums[i]) 的话,有 dp[2]中方法 凑成 容量为5的背包
已经有一个4(nums[i]) 的话,有 dp[1]中方法 凑成 容量为5的背包
已经有一个5 (nums[i])的话,有 dp[0]中方法 凑成 容量为5的背包
那么凑整dp[5]有多少方法呢,也就是把 所有的 dp[j - nums[i]] 累加起来。
⭐️⭐️求组合类问题的公式
dp[j] += dp[j - nums[i]]
class Solution { public: //1. 回溯法 vector<int> path; vector<vector<int>> result; void backtracking(vector<int>& nums, int cursum, int targetSum, int startIndex){ if(cursum == targetSum){ result.push_back(path); //不能写return 这个需要递归到最后的深度 } if(cursum>targetSum) return; for(int i =startIndex;i<nums.size();i++) { cursum+=nums[i]; path.push_back(nums[i]); backtracking(nums,cursum,targetSum,i+1); path.pop_back(); cursum-=nums[i]; } } int findTargetSumWays(vector<int>& nums, int target) { int sum = 0; for(int i=0;i<nums.size();i++) { sum+=nums[i]; } if((target+sum) % 2 != 0) return 0; //如果不能整除则不可能实现。 if(abs(target)>sum) return 0; int targetSum = (target+sum)/2; // int startIndex = 0; // int cursum=0; // backtracking(nums,cursum,targetSum,startIndex); // return result.size(); //2. dp动态规划方法 vector<int> dp(targetSum+1,0); dp[0]=1; for(int i=0;i<nums.size();i++) for(int j = targetSum;j>=nums[i];j--) { dp[j] += dp[j-nums[i]]; } return dp[targetSum]; } };
dp变化图
class Solution { public: int findMaxForm(vector<string>& strs, int m, int n) { vector<vector<int>> dp(m+1,vector<int>(n+1,0)); for(string str : strs){ //遍历物品 int zeroNum = 0; int oneNum = 0; for(char c : str){ if(c=='0') zeroNum++; else oneNum++; } for(int i = m;i>=zeroNum;i--) for(int j = n;j>=oneNum;j--) dp[i][j] = max(dp[i][j],dp[i-zeroNum][j-oneNum]+1); } // for(int i=0;i<=m;i++){ // for(int j=0;j<=n;j++) // cout<<dp[i][j]<<' '; // cout<<endl; // } return dp[m][n]; } };
这一题可以用来区分多个背包问题 待看!!
卡码网52题
#include <iostream> #include <vector> #include<algorithm> using namespace std; using namespace std; int maxValue(vector<int> weight, vector<int> value, int bagsize){ // int nums = weight.size(); vector<int> dp(bagsize+1,0); for(int i =0;i<weight.size();i++) for(int j=weight[i];j<=bagsize;j++) dp[j]=max(dp[j],dp[j-weight[i]]+value[i]); return dp[bagsize]; } int main(){ int N,V; cin>>N>>V; vector<int> weight(N,0); vector<int> value(N,0); for(int i=0;i<N;i++){ int w; int v; cin >> w >>v; weight[i]=w; value[i]=v; } int result = maxValue(weight,value,V); cout<<result<<endl; }
for(int j=weight[i];j<=bagsize;j++)
这里条件不要搞错了。class Solution { public: //dp[j] 总金额j可有dp[j]中方式凑出。coins可以重复使用,完全背包问题 //求装满背包有几种方法,公式都是:dp[j] += dp[j - nums[i]]; int change(int amount, vector<int>& coins) { vector<int> dp(amount+1,0); dp[0]=1; //背包容量为0的时候只有一种方法。 for(int i = 0;i< coins.size();i++) for(int j=coins[i];j<=amount;j++) { dp[j] += dp[j - coins[i]]; } for(int i =0;i<amount+1;i++) cout<< dp[i]<<" "; return dp[amount]; } };
class Solution {
public:
long combinationSum4(vector<int>& nums, int target) {
vector<int> dp(target+1,0);
dp[0]=1;
for(int j = 0;j<=target;j++)
for(int i=0;i<nums.size();i++)
{
if(j >= nums[i] && dp[j] < INT_MAX - dp[j - nums[i]])
dp[j]+=dp[j-nums[i]];
}
return dp[target];
}
};
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬至多m (1 <= m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
#include<iostream> #include<vector> using namespace std; int main(){ int n,m; cin >> n >> m; vector<int> dp(n+1,0); dp[0]=1; // dp[1]=1; for(int j=0;j<=n;j++) for(int i=1;i<=m;i++){ if(j>=i) dp[j]+=dp[j-i]; } cout<<dp[n]<<endl; return 0; }
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
而本题是要求最少硬币数量,硬币是组合数还是排列数都无所谓!所以两个for循环先后顺序怎样都可以!
class Solution { public: int coinChange(vector<int>& coins, int amount) { //最少的硬币个数,贪心,对coins进行降序排列。 // sort(coins,false); //完全背包,先遍历背包,再遍历物品。 vector<int> dp(amount+1,INT_MAX); dp[0]=0; for(int j=0;j<=amount;j++) for(int i=0;i<coins.size();i++) { if(j>=coins[i] && dp[j - coins[i]] != INT_MAX) dp[j] = min(dp[j],dp[j-coins[i]]+1); } if(dp[amount]==INT_MAX) return -1; else return dp[amount]; } };
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n+1,INT_MAX);
dp[0]=0;
dp[1]=1;
for(int j=0;j<=n;j++)
for(int i=1;i<=sqrt(n);i++){
if(j>=i*i && dp[j-i*i]!=INT_MAX)
dp[j] = min(dp[j],dp[j-i*i]+1);
}
return dp[n];
}
};
AC~
给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
拆分时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。
class Solution { public: bool wordBreak(string s, vector<string>& wordDict) { vector<bool> dp(s.size()+1,false); dp[0] = true; for(int j = 0;j<=s.size();j++) for(int i = 0;i<j;i++) { string word = s.substr(i, j - i); //substr(起始位置,截取的个数) for(int z = 0; z< wordDict.size();z++) if(word == wordDict[z] && dp[i]==true) dp[j]=true; }成分 return dp[s.size()]; } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。