代码随想录-动态规划
#include <iostream> #include <vector> #include <numeric> #include <string> #include <unordered_set> using namespace std; struct TreeNode{ int val = 0; TreeNode* left = nullptr; TreeNode* right = nullptr; TreeNode(int val_):val(val_) {} }; int fib(int n) { if( n < 2)return n; vector<int>dp(n + 1); dp[0] = 0; dp[1] = 1; for(int i = 2; i <= n; ++i) { dp[i] = dp[i-1] + dp[i-2]; } return dp[n]; } int climbStairs(int n) { if(n <= 2)return n; vector<int>dp(n+1); dp[1] = 1; dp[2] = 2; for(int i = 3; i <= n; ++i) { dp[i] = dp[i-1] + dp[i-2]; } return dp[n]; } int climbStairs_m(int n,int m) { vector<int>dp(n+1,0); dp[0] = 1; for(int i = 1; i <= n; ++i) { for(int j = 1;j <= m; ++j) { if(i - j >= 0)dp[i]+=dp[i-j]; } } return dp[n]; } int minCostClimbStairs(const vector<int>& cost) { vector<int>dp(cost.size()); dp[0] = cost[0]; dp[1] = cost[1]; for(int i = 2; i < cost.size(); ++i) { dp[i] = min(dp[i-1],dp[i-2]) + cost[i]; } return min(dp[cost.size() - 1],dp[cost.size() - 2]); } int uniquePath(int m, int n) { vector<vector<int>>dp(m,vector<int>(n,0)); for(int i = 0; i < m; ++i) { dp[i][0] = 1; } for(int i = 0; i < n; ++i) { dp[0][i] = 1; } for(int i = 1;i < m; ++i) { for(int j = 1; j < n; ++j) { dp[i][j] = dp[i-1][j] + dp[i][j-1]; } } return dp[m-1][n-1]; } int uniquePathWithObstackles(const vector<vector<int>>& obstackles) { int m = obstackles.size(), n = obstackles[0].size(); vector<vector<int>>dp(m,vector<int>(n,0)); for(int i = 0; i < m && obstackles[i][0] == 0 ; ++i)dp[i][0] = 1; for(int i = 0; i < n && obstackles[0][i] == 0 ; ++i)dp[0][i] = 1; for(int i = 1; i < m; ++i) { for(int j = 1; j < n; ++j) { if(obstackles[i][j] == 1) continue; dp[i][j] = dp[i-1][j] + dp[i][j-1]; } } return dp[m-1][n-1]; } int intergerBreak(int n) { vector<int>dp(n+1,0); dp[2] = 1; for(int i = 3; i <= n; ++i) { for(int j = 1; j < i-1; ++j) { dp[i] = max(dp[i],max(j * (i -j),j * dp[i-j])); } } return dp[n]; } int numTrees(int n) { vector<int>dp(n + 1); dp[0] = 1; for(int i = 0; i <= n; ++i) { for(int j = 1;j <= i; ++j) { dp[i] += dp[j - 1] * dp[i-j]; } } return dp[n]; } bool canPartition(const vector<int>& nums) { int sum = accumulate(nums.begin(),nums.end(),0); if(sum % 2 == 1)return false; int target = sum / 2; vector<int>dp(10001,0); for(int i = 0; i < nums.size(); ++i) { for(int j = target; j >= nums[i]; --j) { dp[j] = max(dp[j],dp[j-nums[i]]+nums[i]); } } return dp[target]==target; } int zeroOneBag(const vector<int>& weight, const vector<int>& value,int bagWeight) { vector<vector<int>>dp(weight.size() + 1, vector<int>(bagWeight+1,0)); // for(int i = 0; i < weight.size(); ++i) // { // dp[i][0] = 0; // } for(int j = bagWeight; j >= weight[0]; --j) { dp[0][j] = dp[0][j-weight[0]]+value[0]; } for(int i = 1; i < weight.size(); ++i) { for(int j = 0; j <= bagWeight; ++j) { if(j < weight[i])dp[i][j] = dp[i-1][j]; else { dp[i][j] = max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]); } } } return dp[weight.size()-1][bagWeight]; } int zeroOneBag_1D(const vector<int>& weight, const vector<int>& value,int bagWeight) { vector<int>dp(bagWeight + 1,0); for(int i = 0; i < weight.size(); ++i) { for(int j = bagWeight; j >= weight[i];--j) { dp[j] = max(dp[j],dp[j-weight[i]]+value[i]); } } return dp[bagWeight]; } int lastStoneWeight(const vector<int>& stones) { int sum = accumulate(stones.begin(),stones.end(),0) / 2; vector<int>dp(15001,0); int target = sum / 2; for(int i = 0; i < stones.size(); ++i) { for(int j = target; j >= stones[i];--j) { dp[j] = max(dp[j],dp[j-stones[i]]+stones[i]); } } cout << dp[target] << endl; return sum - dp[target] - dp[target]; } int findTargetSumWays(const vector<int>nums,int s) { //left + right = sum , left - right = target ->left = (target + sum) / 2 int sum = accumulate(nums.begin(),nums.end(),0); if(s > sum || (s + sum) / 2 == 1)return 0; int bagSize = (s + sum) / 2; vector<int>dp(bagSize + 1,0); dp[0] = 1; for(int i = 0; i < nums.size(); ++i) { for(int j = bagSize;j>=nums[i];--j) { dp[j]+=dp[j-nums[i]]; } } return dp[bagSize]; } int findMaxForm(const vector<string>& strs, int m , int n) { vector<vector<int>>dp(m+1,vector<int>(n + 1,0)); for(string str:strs) { int oneNum = 0, zeroNum = 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],1 + dp[i-zeroNum][j-oneNum]); } } } return dp[m][n]; } int change(const vector<int>& coins,int amount) { vector<int>dp(amount+1,0); dp[0] = 1; for(int i = 0; i < coins.size(); ++i) { for(int j = coins[i]; j <= amount; ++j) { dp[j]+=dp[j-coins[i]]; } } return dp[amount]; } int combinationSum4(const vector<int>& nums, int target) { vector<int>dp(target + 1, 0); dp[0] = 1; for(int i = 0; i <= target; ++i) { for(int j = 0; j < nums.size(); ++j) { if(i >= nums[j] && dp[i] + dp[i - nums[j]] <INT_MAX) { dp[i]+=dp[i-nums[j]]; } } } return dp[target]; } int coinChange(const vector<int>&nums,int amount) { vector<int>dp(amount + 1,INT_MAX); dp[0] = 0; for(int i = 0; i < nums.size(); ++i) { for(int j = nums[i];j <= amount; ++j) { if(dp[j - nums[i]]!= INT_MAX) { dp[j] = min(dp[j],dp[j-nums[i]] + 1); } } } if(dp[amount] == INT_MAX)return -1; return dp[amount]; } int numSquares(int n) { vector<int>dp(n+1,INT_MAX); dp[0] = 0; for(int i = 0; i <= n; ++i) { for(int j = 1; j * j <= i; ++j) { dp[i] = min(dp[i],dp[i - j * j]+1); } } return dp[n]; } bool wordBreak(string s, const vector<string>& wordDict) { vector<bool>dp(s.size() + 1, false); unordered_set<string>set(wordDict.begin(),wordDict.end()); dp[0] = true; for(int i = 1; i <= s.size(); ++i) { for(int j = 0; j < i; ++j) { string word = s.substr(j,i - j); if(set.find(word)!= set.end()&&dp[j]) { dp[i] = true; } } } return dp[s.size()]; } int multiBag(vector<int>&weight,vector<int>&value,int bagWeight,vector<int>& nums) { for(int i = 0;i < nums.size(); ++i) { while(nums[i] > 1) { weight.push_back(weight[i]); value.push_back(value[i]); --nums[i]; } } vector<int>dp(bagWeight + 1, 0); for(int i = 0; i < value.size(); ++i) { for(int j = bagWeight; j >= weight[i];--j) { dp[j] = max(dp[j],dp[j-weight[i]]+value[i]); } } return dp[bagWeight]; } int rob(const vector<int>& nums) { int n = nums.size(); if(n == 0)return 0; if(n == 1) return nums[0]; vector<int>dp(n,INT_MIN); dp[0] = nums[0]; dp[1] = max(nums[0],nums[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]; } int rob_h(const vector<int>& nums,int start,int end) { if(start == end)return nums[start]; vector<int>dp(nums.size()); dp[start]=nums[start]; dp[start+1]=max(nums[start],nums[start+1]); for(int i = start + 2; i <= end; ++i) { dp[i] = max(dp[i-2]+nums[i],dp[i-1]); } return dp[end]; } int robII(const vector<int>& nums) { int n = nums.size(); if(n == 0)return 0; if(n == 1)return nums[0]; return max(rob_h(nums,0,nums.size() - 2),rob_h(nums,1,nums.size() - 1)); } vector<int>robTree(TreeNode* root) { if(nullptr == root)return {0,0}; vector<int>left = robTree(root->left); vector<int>right = robTree(root->right); int Rob = root->val + left[0] + right[0]; int NoRob = max(left[0],right[1]) +max(left[1],right[0]); return {NoRob,Rob}; } int robIII(TreeNode* root) { auto res = robTree(root); return *max_element(res.begin(),res.end()); } int maxProfit(const vector<int>& prices) { int n = prices.size(); if(n == 0) return 0; vector<vector<int>>dp(n,vector<int>(2,0)); dp[0][0] = 0; dp[0][1] = -prices[0]; for(int i = 1; i < prices.size(); ++i) { dp[i][0] = max(dp[i-1][1]+prices[i],dp[i-1][0]); dp[i][1] = max(dp[i-1][1],-prices[i]);//只能买卖一次,所以不能是dp[i-1][0]-prices[i] } return dp[prices.size() - 1][0] ; } int maxProfitII(const vector<int>& prices) { int n = prices.size(); if(n == 0) return 0; vector<vector<int>>dp(n,vector<int>(2,0)); dp[0][0] = 0; dp[0][1] = -prices[0]; for(int i = 1; i < prices.size(); ++i) { dp[i][0] = max(dp[i-1][1]+prices[i],dp[i-1][0]); dp[i][1] = max(dp[i-1][1],dp[i-1][0]-prices[i]);//可以买卖多次,所以这里是dp[i-1][0]-prices[i] } return dp[prices.size() - 1][0] ; } int maxProfitIII(const vector<int>& prices) { //0:没有操作 1:第一次买入 2:第一次卖出 3:第二次买入 4:第二次卖出 int n = prices.size(); if(n == 0)return 0; vector<vector<int>>dp(n,vector<int>(5,0)); dp[0][1] = -prices[0]; dp[0][3] = -prices[0]; for(int i = 1; i < n; ++i) { dp[i][0] = dp[i-1][0]; dp[i][1] = max(dp[i-1][1],dp[i-1][0]-prices[i]); dp[i][2] = max(dp[i-1][2],dp[i-1][1]+prices[i]); dp[i][3] = max(dp[i-1][3],dp[i-1][2]-prices[i]); dp[i][4] = max(dp[i-1][4],dp[i-1][3]+prices[i]); } return dp[prices.size()-1][4]; } int maxProfit(const vector<int>& nums, int k) { int n = nums.size(); if(0 == n)return 0; vector<vector<int>>dp(n,vector<int>(2 * k + 1,0)); for(int j = 1; j < 2*k; j += 2) { dp[0][j] = -nums[0]; } for(int i = 1; i < nums.size(); ++i) { for(int j = 0; j < 2 * k - 1; j += 2) { dp[i][j + 1] = max(dp[i-1][j + 1],dp[i-1][j] - nums[i]); dp[i][j + 2] = max(dp[i-1][j + 2],dp[i-1][j+1]+nums[i]); } } return dp[nums.size() - 1][2 * k]; } int maxProfit_cold(const vector<int>& nums) { //状态一:买入股票状态(是今天买入,或者之前买入一直没卖) //状态二: 保持卖出股票状态(两天前就卖出了,度过冷冻期,没操作) //状态三:今天卖出股票 //状态四:今天为冷冻期 int n = nums.size(); if(0 == n)return 0; vector<vector<int>>dp(n,vector<int>(4,0)); dp[0][0] = -nums[0]; for(int i = 1; i < n; ++i) { dp[i][0] = max(dp[i-1][0],max(dp[i-1][3],dp[i-1][1]) - nums[i]) ; dp[i][1] = max(dp[i-1][1],dp[i-1][3]); dp[i][2] = dp[i-1][0] + nums[i]; dp[i][3] = dp[i-1][2]; } return max(dp[n-1][3],max(dp[n-1][1],dp[n-1][2])); } int maxProfit_fee(const vector<int>& prices, int fee) { int n = prices.size(); vector<vector<int>>dp(n,vector<int>(2,0)); dp[0][1] = -prices[0]; for(int i = 1; i < n; ++i) { dp[i][0] = max(dp[i-1][0],dp[i-1][1]+prices[i]-fee); dp[i][1] = max(dp[i-1][1],dp[i-1][0]-prices[i]); } return dp[n-1][0]; } int lengthOfList(const vector<int>& nums) { int n = nums.size(); if(n <= 1)return n; vector<int>dp(n,1); for(int i = 1; i < n; ++i) { for(int j = 0; j < i; ++j) { if(nums[i] > nums[j])dp[i] = max(dp[i], 1 + dp[j]); } } return *max_element(dp.begin(),dp.end()); } int lengthOfLCIS(const vector<int>& nums) { int n = nums.size(); if(0 == n)return 0; vector<int>dp(n,1); for(int i = 0; i < n - 1; ++i) { if(nums[i] < nums[i + 1]) { dp[i + 1] = 1 + dp[i]; } } return *max_element(dp.begin(),dp.end()); } int findLength(const vector<int>&A, const vector<int>&B) { int m = A.size(),n = B.size(); vector<vector<int>>dp(m + 1,vector<int>(n + 1,0)); int res = 0; for(int i = 1; i <= m; ++i) { for(int j = 1; j <= n; ++j) { if(A[i-1] == B[j-1]) { dp[i][j] = 1 + dp[i-1][j-1]; } if(dp[i][j] > res)res = dp[i][j]; } } return res; } int lcs(string s1,string s2) { int m = s1.size(), n = s2.size(); vector<vector<int>>dp(m+1,vector<int>(n+1,0)); for(int i = 1; i <= m ; ++i) { for(int j = 1; j <= n; ++j) { if(s1[i-1] == s2[j-1]) { dp[i][j] = 1 + dp[i-1][j-1]; } else { dp[i][j] = max(dp[i-1][j],dp[i][j-1]); } } } return dp[m][n]; } int maxUncrossLines(const vector<int>& nums1, const vector<int>& nums2) { int m = nums1.size(), n = nums2.size(); vector<vector<int>>dp(m+1,vector<int>(n+1,0)); for(int i = 1; i <= m; ++i) { for(int j = 1; j <= n; ++j) { if(nums1[i-1] == nums2[j-1]) { dp[i][j] = 1 + dp[i-1][j-1]; } else { dp[i][j] = max(dp[i-1][j],dp[i][j-1]); } } } return dp[m][n]; } int maxSubArray(const vector<int>& nums) { int n = nums.size(); if(0 == n) return 0; vector<int>dp(n,0); dp[0] = nums[0]; for(int i = 1; i < n; ++i) { dp[i] = max(nums[i] + dp[i-1],nums[i]); } return *max_element(dp.begin(),dp.end()); } bool isSubsequence(string s, string t) { int m = s.size(), n = t.size(); vector<vector<int>>dp(m + 1, vector<int>(n + 1,0)); for(int i = 1; i <= m; ++i) { for(int j = 1; j <= n; ++j) { if(s[i-1] == t[j-1]) { dp[i][j] = 1 + dp[i-1][j-1]; } else dp[i][j] = dp[i][j-1]; } } if(dp[m][n] == s.size())return true; else return false; } int numsDistinct(string s, string t) { int m = s.size(), n = t.size(); vector<vector<int>>dp(m+1,vector<int>(n+1,0)); for(int i = 0; i < m; ++i)dp[i][0] = 1; for(int j = 1; j < n; ++j)dp[0][j] = 0; for(int i = 1; i <= m; ++i) { for(int j = 1; j <= n; ++j) { if(s[i]==t[j]) { dp[i][j] = dp[i-1][j-1] + dp[i-1][j]; } else { dp[i][j] = dp[i-1][j]; } } } return dp[m][n]; } int minDistance(string s, string t) { int m = s.size(), n = t.size(); vector<vector<int>>dp(m + 1, vector<int>(n + 1, 0)); for(int i = 0; i < m; ++i)dp[i][0] = i; for(int j = 0; j < n; ++j)dp[0][j] = j; for(int i = 1; i <= m; ++i) { for(int j = 1; j <= n; ++j) { if(s[i-1] == t[j-1]) { dp[i][j] = dp[i-1][j-1]; } else { dp[i][j] = min({dp[i-1][j] + 1, dp[i][j-1]+1,dp[i-1][j-1] + 2}); } } } return dp[m][n]; } int minEditDistance(string s, string t) { int m = s.size(), n = t.size(); vector<vector<int>>dp(m+1,vector<int>(n+1,0)); for(int i = 0; i < m; ++i)dp[i][0] = i; for(int j = 0; j < n; ++j)dp[0][j] = j; for(int i = 1; i <= m; ++i) { for(int j = 1; j <= n; ++j) { if(s[i-1] == t[j-1]) { dp[i][j] = dp[i-1][j-1]; } else{ dp[i][j] = min({dp[i-1][j-1],dp[i][j-1],dp[i-1][j]}) + 1; } } } return dp[m][n]; } int countSubStrings(string s) { int n = s.size(),res = 0; vector<vector<bool>>dp(n,vector<bool>(n,false)); for(int i = n - 1; i >= 0; --i) { for(int j = i; j <= s.size(); ++j) { if(s[i] == s[j]) { if(j - i <= 1) { ++res; dp[i][j] = true; } else if(dp[i+1][j-1]) { ++res; dp[i][j] = true; } } } } return res; } int longestHuiwenSubSqueence(string s) { int n = s.size(); vector<vector<int>>dp(n,vector<int>(n,0)); for(int i = 0; i < n; ++i)dp[i][i] = 1; for(int i = s.size() - 1; i >= 0; --i) { for(int j = i + 1; j < n; ++j) { if(s[i] == s[j]) { dp[i][j] = dp[i+1][j-1]+2; } else { dp[i][j] = max(dp[i+1][j],dp[i][j-1]); } } } return dp[0][n-1]; } int main() { //LeetCode509 斐波那契序列 cout << fib(4) << endl; //LeetCode70 爬楼梯 cout << climbStairs(3) << endl; cout << climbStairs_m(3,2) << endl;//变体为完全背包问题 //LeetCode746 使用最小花费爬楼梯 vector<int>cost{1,100,1,1,1,100,1,1,100,1}; cout << minCostClimbStairs(cost) << endl; //LeetCode62 不同路径 int m = 3, n = 7; cout << uniquePath(m,n) << endl; //LeetCode63 不同路径II vector<vector<int>>path{{0,0,0},{0,1,0},{0,0,0}}; cout << uniquePathWithObstackles(path) << endl; //LeetCode343 整数拆分 cout << intergerBreak(10) << endl; //LeetCode96不同的二叉搜索树 cout << numTrees(3) << endl; //背包问题 //0-1背包 vector<int>weight{1,3,4}; vector<int>value{15,20,30}; int bagweight = 4; cout << zeroOneBag(weight,value,bagweight) << endl; cout << zeroOneBag_1D(weight,value,bagweight) << endl; //LeetCode416 分割等和子集 vector<int>nums{1,5,11,5}; cout << canPartition(nums) << endl; //LeetCode1049 最后一块石头的重量II vector<int>stones{2,7,4,1,8,1}; cout << lastStoneWeight(stones) << endl; //LeetCode494 目标和 nums = {1,1,1,1,1}; int s = 3; cout << findTargetSumWays(nums,s) << endl; //LeetCode474 一和零 vector<string>strs{"10","0001","111001","1","0"}; m = 5, n = 3; cout << findMaxForm(strs,m,n) << endl; //LeetCode518 零钱兑换II vector<int>coins{1,2,5}; int amount = 5; cout << change(coins,amount) << endl; //LeetCode377 组合总和IV nums = {1,2,3}; int target = 4; cout << combinationSum4(nums,target) << endl; //LeetCode322 零钱兑换 coins = {1,2,5}; amount = 11; cout << coinChange(coins,amount) << endl; //LeetCode279 完全平方数 cout << numSquares(12) << endl; //LeetCode139 单词拆分 string str = "leetcode"; vector<string>wordDict{"leet","code"}; cout << wordBreak(str,wordDict) << endl; //多重背包 weight = {1,3,4}; value = {15,20,30}; nums = {2,3,2}; cout << multiBag(weight,value,10,nums) << endl; //打家劫舍 //LeetCode198 打家劫舍 nums = {2,7,9,3,1}; cout << rob(nums) << endl; //LeetCode213 打家劫舍II nums = {2,3,2}; cout << robII(nums) << endl; //LeetCode337 打家劫舍III TreeNode t1(3); TreeNode t2(2); TreeNode t3(3); TreeNode t4(3); TreeNode t5(1); t1.left = &t2; t1.right = &t3; t2.right = &t4; t3.right = &t5; cout << robIII(&t1) << endl; //买卖股票的最佳时机 //LeetCode121 nums = {7,1,5,3,6,4}; cout << maxProfit(nums) << endl; //LeetCode122 cout << maxProfitII(nums) << endl; //LeetCode123 nums = {3,3,5,0,0,3,1,4}; cout << maxProfitIII(nums) << endl; //LeetCode188 nums = {2,4,1}; int k = 2; cout << maxProfit(nums,k) << endl; //LeetCode309 冷冻期 nums = {1,2,3,0,2}; cout << maxProfit_cold(nums) << endl; //LeetCode714 含手续费 vector<int>prices{1,3,2,8,4,9}; int fee = 2; cout << maxProfit_fee(prices,fee) << endl; //LeetCode300 递增最长子序列 nums = {0,1,0,3,2,3}; cout << lengthOfList(nums) << endl; //LeetCode674 最长连续递增序列 nums = {1,3,5,4,7}; cout << lengthOfLCIS(nums) << endl; //LeetCode718 vector<int>A{1,2,3,2,1}; vector<int>B{3,2,1,4,7}; cout << findLength(A,B) << endl; //LeetCode1143最长公共子序列 string s1 = "abcde", s2 = "ace"; cout << lcs(s1,s2) << endl; //LeetCode1035 不相交的线 vector<int>nums1{1,4,2}; vector<int>nums2{1,2,4}; cout << maxUncrossLines(nums1, nums2) << endl; //LeetCode53 最大子序和 nums = {-2,1,-3,4,-1,2,1,-5,4}; cout << maxSubArray(nums) << endl; //LeetCode392 判断子序列 string s0 = "abc"; string t0 = "ahbgdc"; cout << isSubsequence(s0,t0) << endl; //LeetCode115 不同的子序例 s0 = "rabbbit"; s1 = "rabbit"; cout << numsDistinct(s0,s1) << endl; //LeetCode583 两个字符串的删除操作 s0 = "sea"; s1= "eat"; cout << minDistance(s0,s1) << endl; //LeetCode72 编辑距离 s0 = "intention"; s1 = "execution"; cout << minEditDistance(s0,s1) << endl; //LeetCode647 回文子串个数 s0 = "abc"; cout << countSubStrings(s0) << endl; //LeetCode516 最长回文子序列 s0 = "bbbab"; cout << longestHuiwenSubSqueence(s0) << endl; return 0; }