按摩师
按摩师
1.状态表示
dp【i】表示:到i位置时,此时最长时长
继续细化:在i位置选预约,或不选预约
f【i】:到i位置时,nums【i】必选的,最长时长
g【i】:到i位置时,nums【i】不选的,最长时长
2状态转移方程
f【i】=g【i-1】+nums【i】
g【i】=max(f【i-1】,g【i-1】)
3初始化
f【0】=nums【0】
g【0】=0
4.填表顺序
左往右
5.返回值
max(f【n-1】,g【n-1】)
class Solution {
public:int massage(vector<int>& nums) {int n=nums.size();if(n==0)return 0;vector<int>f(n);vector<int>g(n);f[0]=nums[0];for(int i=1;i<n;i++){f[i]=g[i-1]+nums[i];g[i]=max(f[i-1],g[i-1]);}return max(f[n-1],g[n-1]);}
};
打家劫舍
198. 打家劫舍
1.dp表示:
f【i】:表示到i位置时,必偷i位置房屋,获得的最大金额
g【i】:表示到i位置时,不偷i位置房屋,获得的最大金额
f【i】=g【i-1】+nums【i】
g【i】=max(f【i-1】,g【i-1】)
f【0】=nums【0】
返回值
max(f【n-1】,g【n-1】)
class Solution {
public:int rob(vector<int>& nums) {int n =nums.size();vector<int>f(n);vector<int>g(n);f[0]=nums[0];for(int i=1;i<n;i++){f[i]=g[i-1]+nums[i];g[i]=max(f[i-1],g[i-1]);}return max(f[n-1],g[n-1]);}
};
打家劫舍 II
213. 打家劫舍 II
环形问题转化
分情况偷0下标的和不偷0下标的
当偷【0】时,转化为打家劫舍一:从【2,n-2】的打家劫舍
不偷【0】,转化为从【1,n-1】的打家劫舍
class Solution {
public:int rob(vector<int>& nums) {int n=nums.size();if(n==1)return nums[0];else if(n==2)return max(nums[0],nums[1]);else if(n==3)return max(max(nums[0],nums[1]),nums[2]);int a=nums[0]+_rob(nums,2,n-2);int b=_rob(nums,1,n-1);return max(a,b);}int _rob(vector<int>&nums,int left,int right){int n=nums.size();vector<int>f(n);vector<int>g(n);f[left]=nums[left];for(int i=left+1;i<=right;i++){f[i]=g[i-1]+nums[i];g[i]=max(g[i-1],f[i-1]);}return max(f[right],g[right]);}
};
删除并获得点数
740. 删除并获得点数
转换为打家劫舍问题
用一个arr数组:arr【i】表示i出现的总和
class Solution {
public:const int N=10001;int deleteAndEarn(vector<int>& nums) {int n=nums.size();vector<int>arr(N);for(int v:nums){arr[v]+=v;}vector<int>f(N);vector<int>g(N);for(int i=1;i<N;i++){f[i]=g[i-1]+arr[i];g[i]=max(g[i-1],f[i-1]);}return max(f[N-1],g[N-1]);}
};
粉刷房子
LCR 091. 粉刷房子
dp【i】位置分三种状态,
分别时刷红,蓝,绿
用dp【i】【0,1,2】分别表示到第i位置时,刷红蓝绿的成本
class Solution {
public:int minCost(vector<vector<int>>& costs) {int n=costs.size();vector<vector<int>>dp(n,vector<int>(3));dp[0][0]=costs[0][0];dp[0][1]=costs[0][1];dp[0][2]=costs[0][2];for(int i=1;i<n;i++){dp[i][0]=min(dp[i-1][1],dp[i-1][2])+costs[i][0];dp[i][1]=min(dp[i-1][0],dp[i-1][2])+costs[i][1];dp[i][2]=min(dp[i-1][1],dp[i-1][0])+costs[i][2];}return min(dp[n-1][2],min(dp[n-1][0],dp[n-1][1]));}
};
309. 买卖股票的最佳时机含冷冻期
买卖股票的最佳时机含冷冻期
309. 买卖股票的最佳时机含冷冻期
状态转移:
状态机:可买(可交易)dp【0】,可卖(买入)dp【1】,冷冻期dp【2】
dp【i】【0】=max(dp【i-1】【0】,dp【i-1】【2】)
dp【i】【1】=max(dp【i-1】【0】-costs【i】,dp【i-1】【1】)
dp【i】【2】=dp【i-1】【1】+costs【i】
初始化
dp【0】【0】=0
dp【0】【1】=-cost【0】
dp【0】【2】=0
class Solution {
public:int maxProfit(vector<int>& prices) {int n=prices.size();vector<vector<int>>dp(n,vector<int>(3));dp[0][1]=-prices[0];for(int i=1;i<n;i++){dp[i][0]=max(dp[i-1][0],dp[i-1][2]);dp[i][1]=max(dp[i-1][0]-prices[i],dp[i-1][1]);dp[i][2]=dp[i-1][1]+prices[i];}return max(dp[n-1][0],dp[n-1][2]);}
};
买卖股票的最佳时机含手续费
714. 买卖股票的最佳时机含手续费
dp【i】【0】可买
dp【i】【1】可卖
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】)
dp【0】【0】=0
dp【0】【1】=-prices【0】
class Solution {
public:int maxProfit(vector<int>& prices, int fee) {int n=prices.size();vector<vector<int>>dp(n,vector<int>(3));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];}
};
123. 买卖股票的最佳时机 III
188. 买卖股票的最佳时机 IV
122. 买卖股票的最佳时机 II
122. 买卖股票的最佳时机 II
dp【i】【0】可买
dp【i】【1】可卖
dp【i】【0】=max(dp【i-1】【0】,dp【i-1】【1】+prices【i】)
dp【i】【1】=max(dp【i-1】【1】,dp【i-1】【0】-prices【i】)
dp【0】【0】=0
dp【0】【1】=-prices【0】
class Solution {
public:int maxProfit(vector<int>& prices) {int n=prices.size();vector<vector<int>>dp(n,vector<int>(2));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]);dp[i][1]=max(dp[i-1][0]-prices[i],dp[i-1][1]);}return dp[n-1][0];}
};
121. 买卖股票的最佳时机
53. 最大子数组和
53. 最大子数组和
dp【i】:以i位置为结尾的所有子数组最大和
fen为长度为1和不为1的
dp【i】=max(dp【i-1】+nums【i】,nums【i】)
class Solution {
public:int maxSubArray(vector<int>& nums) {int n=nums.size();vector<int>dp(n);dp[0]=nums[0];for(int i=1;i<n;i++){dp[i]=max(dp[i-1]+nums[i],nums[i]);}int ret=INT_MIN;for(int i=0;i<n;i++){ret=max(ret,dp[i]);}return ret;}
};
918. 环形子数组的最大和
918. 环形子数组的最大和
借鉴环形打家劫舍
转化为非环形
f【i】:以i位置为结尾的所有子数组最大和
g【i】:以i位置为结尾的所有子数组最小和
返回 f【i】和sum-g【i】中最大的
注意:当全为负数时 f【i】为负
sum-g【i】为0,会返回0 这是错误的结果
class Solution {
public:int maxSubarraySumCircular(vector<int>& nums) {int n=nums.size();vector<int>f(n);vector<int>g(n);f[0]=nums[0];g[0]=nums[0];int sum=0;for(int i=1;i<n;i++){f[i]=max(f[i-1]+nums[i],nums[i]);g[i]=min(g[i-1]+nums[i],nums[i]);}for(auto v:nums){sum+=v;}int Max=f[0];for(int i=1;i<n;i++){if(i==n-1&&sum-g[i]==0){if(Max<f[i])Max=f[i];break;}if(Max<f[i])Max=f[i];if(Max<(sum-g[i]))Max=sum-g[i];}return Max;}
};
乘积最大子数组
乘积最大子数组
f【i】以i为结尾的乘积最大的子数组
g【i】以i为结尾的乘积最小的子数组
f【i】=
1.nums【i】
2.
乘积要分类 nums【i】》0,要与f【i-1】相乘
nums【i】《0,要与g【i-1】相乘
f【i】=max(nums【i】,f【i-1】*nums【i】,g【i-1】*nums【i】)
g【i】=min(nums【i】,f【i-1】*nums【i】,g【i-1】*nums【i】)
class Solution {
public:int maxProduct(vector<int>& nums) {int n=nums.size();vector<vector<int>>dp(n,vector<int>(2));dp[0][0]=nums[0];dp[0][1]=nums[0];int Max=INT_MIN;for(int i=1;i<n;i++){dp[i][0]=max(dp[i-1][0]*nums[i],max(nums[i],dp[i-1][1]*nums[i]));dp[i][1]=min(dp[i-1][1]*nums[i],min(nums[i],dp[i-1][0]*nums[i]));}for(int i=0;i<n;i++){Max=Max>dp[i][0]?Max:dp[i][0];}return Max;}
};
乘积为正数的最长子数组长度
乘积为正数的最长子数组长度
f【i】以i为结尾乘积为正数的最长子数组长度
g【i】以i为结尾乘积为负数数的最长子数组长度
分类
1.nums【i】==0 f【i】==0
2.nums【i】<0
f【i】=g【i-1】+1
要单独判断f【i-1】=0
g【i】=f【i-1】+1
2.nums【i】>0
要单独判断g【i-1】=0
f【i】=f【i-1】+1
g【i】=g【i-1】+1
class Solution {
public:int getMaxLen(vector<int>& nums) {int n=nums.size();vector<vector<int>>dp(n+1,vector<int>(2));dp[0][0]=0;dp[0][1]=-1;int Max=0;for(int i=1;i<=n;i++)if(nums[i-1]==0)dp[i][0]=dp[i][1]=0;else if(nums[i-1]<0){if(dp[i-1][1]==0)dp[i][0]=0;elsedp[i][0]=dp[i-1][1]+1;dp[i][1]=dp[i-1][0]+1;}else{dp[i][0]=dp[i-1][0]+1;if(dp[i-1][1]==0)dp[i][1]=0;elsedp[i][1]= dp[i-1][1]+1;}for(int i=1;i<=n;i++)Max=Max>dp[i][0]?Max:dp[i][0];return Max;}
};
等差数列划分
等差数列划分
dp【i】以i位置为结尾的能构成等差数列的个数
dp【i】
1.nums【i】+nums【i-2】=nums【i-1】*2
dp【i】=1+dp【i-1】
2
dp【i】=0
class Solution {
public:int numberOfArithmeticSlices(vector<int>& nums) {int n=nums.size();vector<int>dp(n);if(n==1||n==2)return 0;dp[0]=dp[1]=0;for(int i=2;i<n;i++){if(nums[i]+nums[i-2]==2*nums[i-1])dp[i]=1+dp[i-1];elsedp[i]=0;}int sum=0;for(int i=0;i<n;i++){sum+=dp[i];}return sum;}
};
最长湍流子数组
最长湍流子数组
f【i】表示以i为结尾的最长湍流子数组 且i位置为小
g【i】表示以i为结尾的最长湍流子数组 且i位置为大
f【i】=g【i】=1
if(nums【i-1】> nums【i】)
f【i】=1+g【i-1】
else if (nums【i-1】<nums【i】)
g【i】=1+f【i-1】
else
f【i】=g【i】=1
class Solution {
public:int maxTurbulenceSize(vector<int>& arr) {int n=arr.size();vector<int>f(n);vector<int>g(n);f[0]=g[0]=1;int Max=INT_MIN;for(int i=1;i<n;i++){if(arr[i-1]>arr[i]){f[i]=g[i-1]+1;g[i]=1;}else if(arr[i-1]<arr[i]){g[i]=f[i-1]+1;f[i]=1;}else{f[i]=g[i]=1;}}for(int i=0;i<n;i++){Max=Max>f[i]?Max:f[i];Max=Max>g[i]?Max:g[i];}return Max;}
};