力扣热题之动态规划
又来了..
1.爬楼梯
class Solution {
public:int climbStairs(int n) {vector<int> dp(n+1,0);dp[1]=1;if(n==1) return 1;dp[2]=2;if(n==2) return 2;for(int i=3;i<n+1;i++){dp[i]=dp[i-1]+dp[i-2];}return dp[n];}
};
2.杨辉三角
谁敢想我初始化弄错了,一开始三个else if ,这样numRows=3的时候,就没有初始化,直接搞乱了
class Solution {
public:vector<vector<int>> generate(int numRows) {vector<vector<int>> res;res.push_back({1});if(numRows==1) return res;res.push_back({1,1});if(numRows==2) return res;for(int row=2;row<numRows;row++){vector<int> cur(row+1,1);for(int col=1;col<row;col++)cur[col]=res[row-1][col]+res[row-1][col-1];res.push_back(cur);}return res;}
};
3.打家劫舍
class Solution {
public:int rob(vector<int>& nums) {vector<int> dp(nums.size(),0);dp[0]=nums[0];if(nums.size()==1) return dp[0];dp[1]=max(nums[0],nums[1]); if(nums.size()==2) return dp[1];for(int i=2;i<nums.size();i++)dp[i]=max(dp[i-1],dp[i-2]+nums[i]);return dp[nums.size()-1];}
};
4.完全平方数
居然在for后面加了个;
class Solution {
public:int numSquares(int n) {vector<int> dp(n+1,INT_MAX);dp[0]=0;for(int i=1;i<=n;i++){for(int step=1;step<=sqrt(i);step++)dp[i]=min(dp[i],dp[i-step*step]+1);}return dp[n];}
};
5.零钱兑换
谁想出来的让零钱有2800000的
class Solution {
public:int coinChange(vector<int>& coins, int amount) {if(amount==0) return 0;vector<long long> dp(amount+1,INT_MAX);dp[0]=0;for(int i=1;i<=amount;i++){for(int j=0;j<coins.size();j++)if(i>=coins[j]) dp[i]=min(dp[i],dp[i-coins[j]]+1);}return dp[amount]==INT_MAX?-1:dp[amount];}
};
6.单词拆分
(1)用集合,find找更快 (2)s.substr(beginIdx,Length);
class Solution {
public:bool wordBreak(string s, vector<string>& wordDict) {vector<bool> dp(s.size()+1,false);unordered_set<string> m(wordDict.begin(),wordDict.end());//放进集合里更容易查找dp[0]=true;for(int i=1;i<=s.size();i++){for(int j=0;j<i;j++){if(dp[j]&&m.find(s.substr(j,i-j))!=m.end()){dp[i]=true;break;}}}return dp[s.size()];}
};
7.最长递增子序列
这些题都好基础。。没意思.注意不要返回dp.back(),而是要返回max_element;
class Solution {
public:int lengthOfLIS(vector<int>& nums) {vector<int> dp(nums.size(),1);if(nums.size()==1) return 1;for(int i=1;i<nums.size();i++){for(int j=0;j<i;j++){if(nums[i]>nums[j]) dp[i]=max(dp[i],dp[j]+1);}}return *max_element(dp.begin(),dp.end());}
};
8.乘积最大子数组
我嘞个三元比较求max、min,这样就不用讨论nums[i]的正负了,强悍如斯
class Solution {
public:int maxProduct(vector<int>& nums) {int n = nums.size();if (n == 0) return 0;vector<int> maxDp(n); // 存储以i结尾的最大乘积vector<int> minDp(n); // 存储以i结尾的最小乘积maxDp[0] = nums[0];minDp[0] = nums[0];int result = nums[0];for (int i = 1; i < n; i++) {// 三种可能:当前数本身、当前数乘以前面的最大值、当前数乘以前面的最小值maxDp[i] = max({nums[i], maxDp[i-1] * nums[i], minDp[i-1] * nums[i]});minDp[i] = min({nums[i], maxDp[i-1] * nums[i], minDp[i-1] * nums[i]});result = max(result, maxDp[i]);}return result;}
};
9.分割等和子集
有点意思,不会。
看了下大佬的思路,这个实际上是变形的01背包问题,只不过背包的总容量是sum/2,我决定手搓一下代码。第一次手写01背包。。
class Solution {
public:bool canPartition(vector<int>& nums) {int sum = accumulate(nums.begin(), nums.end(), 0);if(sum%2!=0) return false;int target=sum/2;int maxNum=*max_element(nums.begin(),nums.end());if(maxNum>target) return false;if(maxNum==target) return true;//剪枝int row=nums.size();vector<vector<bool>> dp(row,vector<bool>(target+1,false));//初始化for(int i=0;i<row;i++) dp[i][0]=true;for(int i=0;i<=target;i++){if(nums[0]==i) dp[0][i]=true;else dp[0][i]=false;}//状态转移for(int i=1;i<row;i++){for(int j=1;j<=target;j++){if(nums[i]<=j) dp[i][j]=dp[i-1][j]||dp[i-1][j-nums[i]];else dp[i][j]=dp[i-1][j];}}return dp[row-1][target];}
};
10.最长有效括号
动态规划最后一题!写完去干饭
(1)索引栈
没有用动态规划,栈里面放的都是左边括号的索引,用来计算,注意,如果弹出了左括号,结果栈空了,说明我们的右括号多了(因为最开始放了个-1进去),所以这个右括号就成了新的阻拦,嗯,然后在i-st.top() 比如 ()())() id=4的和内个-1匹配上了,我们就把4放进去,后续的是6-4,非常自然。
class Solution {
public:int longestValidParentheses(string s) {stack<int> st;st.push(-1); // 放入起始标记int maxValid = 0;for (int i = 0; i < s.size(); i++) {if (s[i] == '(') {st.push(i);} else {st.pop();if (st.empty()) {st.push(i); // 放入新的起始标记} else {maxValid = max(maxValid, i - st.top());}}}return maxValid;}
};