做网站工作内容cps广告是什么意思
做网站工作内容,cps广告是什么意思,找网页设计公司,wordpress自动建议搜索引擎不抓取声明#xff1a;若未特殊标出#xff0c;则默认是leedcode原题。
1、1137.第N个泰波那契数列#xff1a; ①状态表示#xff1a;dp[i]表示#xff1a;第i个泰波那契数的值。 ②状态转移方程#xff1a;以i位置的状态#xff0c;最近的一步#xff0c;来划分问题#…声明若未特殊标出则默认是leedcode原题。
1、1137.第N个泰波那契数列 ①状态表示dp[i]表示第i个泰波那契数的值。 ②状态转移方程以i位置的状态最近的一步来划分问题dp[i] dp[i-1] dp[i-2] dp[i-3] ③初始化dp[0] 0 dp[1] dp[2] 1 ④填表顺序从左往右。 ⑤返回值dp[n] class Solution
{
public:int tribonacci(int n) {// 0、处理边界情况if(n 0) return 0;if(n 1 || n 2) return 1;// 1、创建dp表vectorint dp(n1);// 2、初始化dp[0] 0, dp[1] dp[2] 1;// 3、填表for(int i 3; i n; i){dp[i] dp[i-1] dp[i-2] dp[i-3];}// 4、返回值return dp[n];}
}; 利用滚动数组优化 class Solution
{
public:int tribonacci(int n) {if(n 0) return 0;if(n 1 || n 2) return 1;int a 0, b 1, c 1, d;for(int i 3; i n; i){d a b c;// 滚动操作a b; b c; c d;}return d;}
}; 2、面试题 08.01.三步问题 ①状态表示dp[i]表示到达i位置时一共有多少种方法。 ②状态转移方程以i位置的状态最近的一步来划分问题dp[i] dp[i-1] dp[i-2] dp[i-3] ③初始化dp[1] 1 dp[2] 2 dp[3] 4 ④填表顺序从左往右。 ⑤返回值dp[n]
class Solution
{
public:int waysToStep(int n) {// 0、处理边界情况if(n 0) return 0;if(n 1) return 1;if(n 2) return 2;if(n 3) return 4;const int MOD 1e9 7;// 1、创建dp表vectorint dp(n1);// 2、初始化dp[0] 0, dp[1] 1, dp[2] 2, dp[3] 4;// 3、填表for(int i 4; i n; i){dp[i] ((dp[i-1] dp[i-2]) % MOD dp[i-3]) % MOD;}// 4、返回值return dp[n];}
}
3、746.使用最小花费爬楼梯
解法一 ①状态表示dp[i]表示到达i位置时最小花费。 ②状态转移方程用之前/之后的状态推导出dp[i]的值。根据最近的一步来划分问题 先到达i-1位置然后支付cost[i-1]走一步dp[i] dp[i-1] cost[i-1] 先到达i-2位置然后支付cost[i-2]走两步dp[i] dp[i-2] cost[i-2] dp[i] min(dp[i-1] cost[i-1], dp[i-2] cost[i-2]); ③初始化保证填表时不越界dp[0] dp[1] 0 ④填表顺序从左往右。 ⑤返回值dp[n]
class Solution
{
public:int minCostClimbingStairs(vectorint cost) {// 1、创建dp表int n cost.size();vectorint dp(n1);// 2、初始化(vector默认初始值为0)// dp[0] dp[1] 0;// 3、填表for(int i 2; i n; i){dp[i] min(dp[i-1] cost[i-1], dp[i-2] cost[i-2]);}// 4、返回值return dp[n];}
};
解法二 ①状态表示从i位置出发到达楼顶此时的最小花费。 ②状态转移方程用之前/之后的状态推导出dp[i]的值。根据最近的一步来划分问题 支付cost[i]走一步到达i1位置出发到终点dp[i] dp[i1] cost[i] 支付cost[i]走两步到达i2位置出发到终点dp[i] dp[i2] cost[i] dp[i] min(dp[i1] cost[i], dp[i2] cost[i]); ③初始化保证填表时不越界dp[n-1] cost[n-1] dp[n-2] cost[n-2] ④填表顺序从右往左。 ⑤返回值min(dp[0]dp[1])
class Solution
{
public:int minCostClimbingStairs(vectorint cost) {// 1、创建dp表int n cost.size();vectorint dp(n);// 2、初始化dp[n-1] cost[n-1], dp[n-2] cost[n-2];// 3、填表for(int i n - 3; i 0; i--)dp[i] cost[i] min(dp[i1], dp[i2]);// 4、返回值return min(dp[0], dp[1]);}
};
4、91.解码方法 ①状态表示dp[i]表示到达i位置时解码方法的总数。 ②状态转移方程根据最近的一步来划分问题 s[i]单独解码 成功1a9)dp[i-1] 失败0 s[i-1]与s[i]解码成功10b*10a26)dp[i-2] 失败0 dp[i] dp[i-1] dp[i-2] ③初始化dp[0] 0/1 dp[1] 0/1/2 ④填表顺序从左往右。 ⑤返回值dp[n-1]
class Solution
{
public:int numDecodings(string s) {// 1、创建dp表int n s.size();vectorint dp(n);// 2、初始化dp[0] s[0] ! 0;if(n 1 || dp[0] 0) return dp[0]; // 处理边界情况if(s[0] ! 0 s[1] ! 0) dp[1] 1;int t (s[0] - 0) * 10 s[1] - 0;if(t 10 t 26) dp[1] 1;// 3、填表for(int i 2; i n; i){if(s[i] ! 0) dp[i] dp[i-1];int q (s[i-1] - 0) * 10 s[i] - 0;if(q 10 q 26) dp[i] dp[i-2];}// 4、返回值return dp[n-1];}
};
优化原理处理边界问题以及初始化问题的技巧虚拟节点 注意事项 ①虚拟节点里面的值要保证后面的填表是正确的。 ②下标的映射关系。
class Solution
{
public:int numDecodings(string s) {// 优化// 1、创建dp表int n s.size();vectorint dp(n 1);// 2、初始化dp[0] 1;dp[1] s[1 - 1] ! 0;// 3、填表for(int i 2; i n; i){if(s[i - 1] ! 0) dp[i] dp[i - 1];int t (s[i - 2] - 0) * 10 s[i - 1] - 0;if(t 10 t 26) dp[i] dp[i - 2];}// 4、返回值return dp[n];}
};
5、62.不同路径 ①状态表示dp[i][j]表示到达[i,j]位置时一共有多少种方式。 ②状态转移方程根据最近的一步来划分问题 从[i-1,j]→[i,j]→dp[i-1][j] 从[i,j-1]→[i,j]→dp[i][j-1] dp[i][j] dp[i-1][j] dp[i][j-1] ③初始化增添一行和一列的虚拟节点。 ④填表顺序从上往下填写每一行每一行从左往右。 ⑤返回值dp[m][n]
class Solution
{
public:int uniquePaths(int m, int n) {// 1、创建dp表vectorvectorint dp(m 1, vectorint(n 1));// 2、初始化dp[0][1] 1;// 3、填表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];}}// 4、返回值return dp[m][n];}
};
6、63.不同路径II(有障碍物
class Solution
{
public:int uniquePathsWithObstacles(vectorvectorint ob) {// 1、创建dp表int m ob.size(), n ob[0].size();vectorvectorint dp(m 1, vectorint(n 1));// 2、初始化dp[0][1] 1;// 3、填表for(int i 1; i m; i){for(int j 1; j n; j){if(ob[i - 1][j - 1] 0) dp[i][j] dp[i-1][j] dp[i][j-1];}}// 4、返回值return dp[m][n];}
};
8、931.下降路径最小和 ①状态表示dp[i][j]表示到达[i,j]位置时最小的下降路径。 ②状态转移方程根据最近的一步来划分问题 从[i-1,j-1]→[i,j]→xdp[i-1][j-1]m[i][j] 从[i-1, j ]→[i,j]→ydp[i-1][ j ]m[i][j] 从[i-1,j1]→[i,j]→zdp[i-1][j1]m[i][j] dp[i][j] min(x,y,z)m[i][j] ③初始化增添一行和两列虚拟节点所有位置填正无穷第一行改为0。 ④填表顺序从上往下填写每一行。 ⑤返回值最后一行最小值。
class Solution
{
public:int minFallingPathSum(vectorvectorint matrix) {int n matrix.size();// 1、创建dp表vectorvectorint dp(n 1, vectorint(n 2, INT_MAX));// 2、初始化第一行for(int j 0; j n 1; j) dp[0][j] 0;// 3、填表for(int i 1; i n; i)for(int j 1; j n; j)dp[i][j] min(dp[i-1][j-1], min(dp[i-1][j], dp[i-1][j1])) matrix[i - 1][j - 1];int ret INT_MAX;// 4、返回值for(int j 1; j n; j)ret min(ret, dp[n][j]);return ret;}
};
10、174.地下城游戏有后效性 ①状态表示 错误状态表示dp[i][j]表示从起点出发到达[i,j]位置时所需最低初始健康点数。以某位置为结尾 正确状态表示dp[i][j]表示从[i,j]位置出发到达终点时所需最低初始健康点数。以某位置为起点 ②状态转移方程根据最近的一步来划分问题 向右走dp[i][j]dp[i][j1]-d[i][j] 向下走dp[i][j]dp[i1][j]-d[i][j] dp[i][j] min(dp[i][j1]dp[i1][j])-d[i][j]由于最低健康点数为1故dp[i][j]max(1,dp[i][j])。 ③初始化最右和最下面分别增添一列/行虚拟节点保证最低健康血量为1其余填正无穷大即可。 ④填表顺序从下往上填写每一行每一行从右往左。 ⑤返回值dp[0][0]
class Solution
{
public:int calculateMinimumHP(vectorvectorint dungeon) {int m dungeon.size(), n dungeon[0].size();// 1、创建dp表vectorvectorint dp(m 1, vectorint(n 1, INT_MAX));// 2、初始化dp[m-1][n] dp[m][n-1] 1;// 3、填表for(int i m - 1; i 0; i--)for(int j n - 1; j 0; j--)dp[i][j] max(1, min(dp[i][j 1], dp[i 1][j]) - dungeon[i][j]);// 4、返回值return dp[0][0];}
};
11、打家劫舍I按摩师 ①状态表示选择到i位置的时候此时的最长预约时长。 f[i]表示选择到i位置的时候nums[i]必选此时的最长预约时长。 g[i]表示选择到i位置的时候nums[i]不选此时的最长预约时长。 ②状态转移方程 i处选 f[i]g[i-1]nums[i] i处不选i-1处选 g[i]f[i-1] i-1处不选g[i]g[i-1] g[i]max(f[i-1],g[i-1]) ③初始化此处没有必要加虚拟节点f[0]nums[0]g[0]0。 ④填表顺序从左往右两个表一起填。 ⑤返回值max(f[n-1],g[n-1])
class Solution
{
public:int massage(vectorint nums) {// 0、处理边界条件int n nums.size();if(n 0) return 0;// 1、创建dp表vectorint f(n), g(n);// 2、初始化f[0] nums[0];// 3、填表for(int i 1; i n; i){f[i] g[i - 1] nums[i];g[i] max(f[i - 1],g[i - 1]);}// 4、返回值return max(f[n - 1],g[n - 1]);}
};
12、213.打家劫舍II ①状态表示通过分类讨论将环形的问题转化成两个线性的“打家劫舍I”。 f[i]表示偷到i位置时偷nums[i]此时的最大金额。 g[i]表示偷到i位置时不偷nums[i]此时的最大金额。 ②状态转移方程 i处偷 f[i]g[i-1]nums[i] i处不偷i-1处偷 g[i]f[i-1] i-1处不偷g[i]g[i-1] g[i]max(f[i-1],g[i-1]) ③初始化此处没有必要加虚拟节点f[0]nums[0]g[0]0。 ④填表顺序从左往右两个表一起填。 ⑤返回值max(f[n-1],g[n-1])
class Solution
{
public:int rob(vectorint nums){int n nums.size();return max(nums[0] rob1(nums, 2, n - 2), rob1(nums, 1, n - 1));}int rob1(vectorint nums, int left, int right) {// 0、处理边界条件if(left right) return 0;int n nums.size();// 1、创建dp表vectorint f(n), g(n);// 2、初始化f[left] nums[left];// 3、填表for(int i left 1; i right; i){f[i] g[i - 1] nums[i];g[i] max(f[i - 1],g[i - 1]);}// 4、返回值return max(f[right], g[right]);}
};
13、740.删除并获得点数 ①状态表示预处理将数组中的数统计到arr中做一次“打家劫舍I”问题即可。 ②状态转移方程 i处选 f[i]g[i-1]arr[i] i处不选i-1处选 g[i]f[i-1] i-1处不选g[i]g[i-1] g[i]max(f[i-1],g[i-1]) ③初始化此处没有必要加虚拟节点f[0]arr[0]g[0]0。 ④填表顺序从左往右两个表一起填。 ⑤返回值max(f[n-1],g[n-1])
class Solution
{
public:int deleteAndEarn(vectorint nums) {const int N 10001;// 0、预处理vectorint arr(N);for(auto x : nums) arr[x] x;// 1、创建dp表vectorint f(N), g(N);// 2、初始化f[0] arr[0];// 3、填表for(int i 1; i N; i){f[i] g[i - 1] arr[i];g[i] max(f[i - 1],g[i - 1]);}// 4、返回值return max(f[N - 1],g[N - 1]);}
};
14、LCR 091.粉刷房子 ①状态表示 dp[i][0]表示粉刷到i位置时粉刷上红色此时的最小花费。 dp[i][1]表示粉刷到i位置时粉刷上蓝色此时的最小花费。 dp[i][2]表示粉刷到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][0],dp[i-1][1])costs[i][2] ③初始化加一列虚拟节点并初始化为0。 ④填表顺序从左往右三个表一起填。 ⑤返回值min(dp[n][0],dp[n][1],dp[n][2])
class Solution
{
public:int minCost(vectorvectorint costs) {// 1、创建dp表int n costs.size();vectorvectorint dp(n 1, vectorint(3));// 2、初始化// 3、填表for(int i 1; i n; i){dp[i][0] min(dp[i - 1][1], dp[i - 1][2]) costs[i - 1][0];dp[i][1] min(dp[i - 1][0], dp[i - 1][2]) costs[i - 1][1];dp[i][2] min(dp[i - 1][0], dp[i - 1][1]) costs[i - 1][2];}// 4、返回值return min(dp[n][0], min(dp[n][1], dp[n][2]));}
};
15、309.买卖股票的最佳时期I含冷冻期 ①状态表示 dp[i][0]表示第i天结束后处于“买入”状态此时的最大利润。 dp[i][1]表示第i天结束后处于“可交易”状态此时的最大利润。 dp[i][2]表示第i天结束后处于“冷冻期”状态此时的最大利润。 ②状态转移方程状态机 dp[i][0]max(dp[i-1][0],dp[i-1][0]-prices[i-1]) dp[i][1]max(dp[i-1][1],dp[i-1][2]) dp[i][2]dp[i-1][0]prices[i] ③初始化dp[0][0]-p[0] dp[0][1]0 dp[0][2]0 ④填表顺序从左往右三个表一起填。 ⑤返回值max(dp[n-1][1],dp[n-1][2])
class Solution
{
public:int maxProfit(vectorint prices) {// 1、创建dp表int n prices.size();vectorvectorint dp(n, vectorint(3));// 2、初始化dp[0][0]-prices[0];// 3、填表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][1], dp[i - 1][2]);dp[i][2]dp[i - 1][0] prices[i];}// 4、返回值return max(dp[n - 1][1], dp[n - 1][2]);}
};
16、714.买卖股票的最佳时期II含手续费 ①状态表示 f[i]表示第i天结束后处于“买入”状态此时的最大利润。 g[i]表示第i天结束后处于“卖出”状态此时的最大利润。 ②状态转移方程状态机 f[i]max(f[i-1],g[i-1]-prices[i]) g[i]max(g[i-1],f[i-1]prices[i]-fee) ③初始化f[0]-prices[0] g[0]0 ④填表顺序从左往右两个表一起填。 ⑤返回值g[n-1]
class Solution
{
public:int maxProfit(vectorint prices, int fee) {// 1、创建dp表int n prices.size();vectorint f(n), g(n);// 2、初始化f[0]-prices[0];// 3、填表for(int i 1; i n; i){f[i] max(f[i - 1], g[i - 1] - prices[i]);g[i] max(g[i - 1], f[i - 1] prices[i] - fee);}// 4、返回值return g[n - 1];}
};
17、714.买卖股票的最佳时期III ①状态表示 f[i][j]表示第i天结束后完成了j次交易此时处于“买入”状态此时的最大利润。 g[i][j]表示第i天结束后完成了j次交易处于“卖出”状态此时的最大利润。 ②状态转移方程状态机 f[i][j]max(f[i-1][j],g[i-1][j]-prices[i]) g[i]g[i-1][j] if(j-10) g[i][j]max(g[i][j],f[i-1][j-1]prices[i]) ③初始化f[0][0]-prices[0] g[0][0]0 f[0][1]f[0][2]g[0][1]g[0][2]-0x3f3f3f3f ④填表顺序从上往下填写每一行每一行从左往右两个表一起填。 ⑤返回值g表的最后一行里面的最大值。
class Solution
{
public:const int INF 0x3f3f3f3f;int maxProfit(vectorint prices) {// 1、创建dp表int n prices.size();vectorvectorint f(n, vectorint(3, -INF));auto g f;// 2、初始化f[0][0] -prices[0], g[0][0] 0;// 3、填表for(int i 1; i n; i){for(int j 0; j 3; j){f[i][j] max(f[i - 1][j], g[i - 1][j] - prices[i]);g[i][j] g[i - 1][j];if(j - 1 0) g[i][j] max(g[i][j], f[i - 1][j - 1] prices[i]);}}// 4、返回值int ret 0;for(int j 0; j 3; j)ret max(ret, g[n - 1][j]);return ret;}
};
19、53.最大子数组和 ①状态表示dp[i]以i位置元素为结尾的所有子数组的最大和。 ②状态转移方程 长度为一dp[i]nums[i] 长度大于一dp[i]dp[i-1]nums[i] dp[i]max(nums[i],dp[i-1]nums[i]) ③初始化虚拟节点dp[0]0 ④填表顺序从左往右。 ⑤返回值整个dp表里的最大值
class Solution
{
public:int maxSubArray(vectorint nums) {// 0、处理边界条件int n nums.size();if(n 0) return 0;// 1、创建dp表vectorint dp(n 1);int ret INT_MIN; 4、返回值// 2、初始化// 3、填表for(int i 1; i n; i){dp[i] max(nums[i - 1], dp[i - 1] nums[i-1]);ret max(ret, dp[i]);}return ret;}
};
20、53.最大子数组和 ①状态表示 f[i]表示以i位置元素为结尾的所有子数组的最大和。 g[i]表示以i位置元素为结尾的所有子数组的最小和。 ②状态转移方程 长度为一f[i]nums[i] 长度大于一f[i]dp[i-1]nums[i] f[i]max(nums[i],f[i-1]nums[i]) 长度为一g[i]nums[i] 长度大于一g[i]g[i-1]nums[i] g[i]min(nums[i],g[i-1]nums[i]) ③初始化虚拟节点dp[0]0 ④填表顺序从左往右两个表一起填。 ⑤返回值sumgmin?fmax:max(fmax,sum-gmin)
class Solution
{
public:int maxSubarraySumCircular(vectorint nums) {// 1、创建dp表int n nums.size();vectorint f(n 1), g(n 1);int fmax INT_MIN, gmin INT_MAX, sum 0; // 2、初始化// 3、填表for(int i 1; i n; i){int x nums[i - 1];f[i] max(x, f[i - 1] x);fmax max(fmax, f[i]);g[i] min(x, g[i - 1] x);gmin min(gmin, g[i]);sum x;}// 4、返回值return sum gmin ? fmax : max(fmax, sum - gmin);}
};
21、152.乘积最大子数组 ①状态表示 f[i]表示以i位置元素为结尾的所有子数组的最大积。 g[i]表示以i位置元素为结尾的所有子数组的最小积。 ②状态转移方程 长度为一f[i]nums[i] 长度大于一if(nums[i]0) f[i]f[i-1]*nums[i] if(nums[i]0) f[i]g[i-1]*nums[i] f[i]max(nums[i],f[i-1]*nums[i],g[i-1]*nums[i]) 长度为一f[i]nums[i] 长度大于一if(nums[i]0) g[i]g[i-1]*nums[i] if(nums[i]0) g[i]f[i-1]*nums[i] g[i]min(nums[i],g[i-1]*nums[i],f[i-1]*nums[i]) ③初始化虚拟节点f[0]g[0]1 ④填表顺序从左往右两个表一起填。 ⑤返回值f表中的最大值。
class Solution
{
public:int maxProduct(vectorint nums) {// 1、创建dp表int n nums.size();vectorint f(n 1), g(n 1);int ret INT_MIN; // 2、初始化f[0] g[0] 1;// 3、填表for(int i 1; i n; i){int x nums[i - 1];f[i] max(x, max(f[i - 1] * x, g[i - 1] * x));g[i] min(x, min(g[i - 1] * x, f[i - 1] * x));ret max(ret, f[i]);}// 4、返回值return ret;}
};
22、1567. 乘积为正数的最长子数组长度 ①状态表示 f[i]表示以i位置元素为结尾的所有子数组中乘积为正数的最长长度 。 g[i]表示以i位置元素为结尾的所有子数组中乘积为负数的最长长度 。 ②状态转移方程 长度为一 if(nums[i]0) f[i]1 if(nums[i]0) f[i]0 长度大于一if(nums[i]0) f[i]f[i-1]1 if(nums[i]0) f[i]g[i-1]0?0:g[i-1]1 故if(nums[i]0) f[i]f[i-1]1 if(nums[i]0) f[i]g[i-1]0?0:g[i-1]1
长度为一 if(nums[i]0) g[i]0 if(nums[i]0) g[i]1 长度大于一if(nums[i]0) g[i]g[i-1]0?0:g[i-1]1 if(nums[i]0) g[i]f[i-1]1 故if(nums[i]0) g[i]g[i-1]0?0:g[i-1]1 if(nums[i]0) g[i]f[i-1]1 ③初始化虚拟节点f[0]g[0]0 ④填表顺序从左往右两个表一起填。 ⑤返回值f表中的最大值。
class Solution
{
public:int getMaxLen(vectorint nums) {// 1、创建dp表int n nums.size();vectorint f(n 1), g(n 1);int ret INT_MIN; // 2、初始化// 3、填表for(int i 1; i n; i){if(nums[i - 1] 0){f[i] f[i - 1] 1;g[i] g[i - 1] 0 ? 0 : g[i - 1] 1;} else if(nums[i - 1]0){f[i] g[i - 1] 0 ? 0 : g[i - 1] 1;g[i] f[i - 1] 1;}ret max(ret, f[i]);}// 4、返回值return ret; }
};
23、413.等差数列划分 ①状态表示 dp[i]表示以i位置元素为结尾的所有子数组中有多少个等差数列。 ②状态转移方程 if(c-bb-a) dp[i]dp[i-1]1 if(c-b!b-a) dp[i]0 dp[i]c-bb-a?dp[i-1]1:0 ③初始化dp[0]dp[1]0 ④填表顺序从左往右。 ⑤返回值dp表内所有元素的和。
class Solution
{
public:int numberOfArithmeticSlices(vectorint nums) {// 1、创建dp表int n nums.size();vectorint dp(n);int ret 0;// 2、初始化// 3、填表for(int i 2; i n; i){dp[i] nums[i] - nums[i-1] nums[i - 1] - nums[i - 2] ? dp[i - 1] 1 : 0;ret dp[i];}// 4、返回值return ret; }
};
24、413.最长湍流子数组 ①状态表示 错误状态表示以i位置元素为结尾的所有子数组中最长湍流子数组的长度。 正确状态表示 f[i]表示:以i位置元素为结尾的所有子数组中最后呈现“上升”状态的最长湍流子数组的长度。 g[i]表示:以i位置元素为结尾的所有子数组中最后呈现“下降”状态的最长湍流子数组的长度。 ②状态转移方程 if(ab) f[i]1 if(ab) f[i]g[i-1]1√ f[i]ab?1:g[i-1]1 if(ab) g[i]f[i-1]1√ if(ab) g[i]1 g[i]ab?g[i-1]1:1 ③初始化f表和g表初始化为1 ④填表顺序从左往右两个表一起填。 ⑤返回值f表与g表内最大值。
class Solution
{
public:int maxTurbulenceSize(vectorint nums) {// 1、创建dp表 // 2、初始化int n nums.size();vectorint f(n, 1), g(n, 1);int ret 1;// 3、填表for(int i 1; i n; i){if(nums[i - 1] nums[i]) f[i] g[i - 1] 1;else if(nums[i - 1] nums[i]) g[i] f[i - 1] 1;ret max(ret, max(f[i], g[i]));}// 4、返回值return ret; }
};
25、139. 单词拆分 ①状态表示 dp[i]表示:[0,i]区间内的字符串能否被字典中的单词拼接而成。 ②状态转移方程根据最后一个位置的情况来划分问题。设j为最后一个单词起始位置的下标0ji。 if(dp[j-1]trues[j~i]在字典中dp[i]true else dp[i]false ③初始化虚拟节点确保后续填表正确dp[0]true下标的映射关系s_s ④填表顺序从左往右。 ⑤返回值dp[n]。
class Solution
{
public:bool wordBreak(string s, vectorstring wordDict) {unordered_setstring hash;for(auto s : wordDict) hash.insert(s);int n s.size();vectorbool dp(n 1);dp[0] true; // 保证后续填表是正确的s s; // 使原始字符串的下标统一1for(int i 1; i n; i) // 填dp[i]{for(int j i; j 1; j--) // 最后一个单词的起始位置{if(dp[j - 1] hash.count(s.substr(j, i - j 1))){dp[i] true;break;}}}return dp[n];}
};
26、467. 环绕字符串中唯一的子字符串 ①状态表示 dp[i]表示:以i位置的元素为结尾的所有子串里面有多少个在base中出现过。 ②状态转移方程 长度为一dp[i]1 长度大于一if(s[i-1]1s[i]||s[i-1]zs[i]a) dp[i]dp[i-1] dp[i]1dp[i-1] ③初始化dp表里的值都初始化为1。 ④填表顺序从左往右。 ⑤返回值返回dp表中所有元素的和。
去重相同字符结尾的dp值取最大的即可 1、创建一个大小为26的数组。 2、里面的值保存相应字符结尾的最大的dp值即可。 3、返回数组里的和。
class Solution
{
public:int findSubstringInWraproundString(string s) {int n s.size();vectorint dp(n, 1);for(int i 1; i n; i){if(s[i - 1]1 s[i] || s[i - 1] z s[i] a)dp[i] dp[i - 1];}int hash[26] { 0 };for(int i 0; i n; i)hash[s[i] - a] max(hash[s[i] - a], dp[i]);int sum 0;for(auto x : hash) sum x;return sum;}
};
27、300.最长递增子序列 ①状态表示 dp[i]表示:以i位置的元素为结尾的所有子序列里面最长递增子序列的长度。 ②状态转移方程 长度为一dp[i]1 长度大于一ifnums[j]nums[i]) dp[i]max(dp[j]1) ③初始化dp表里的值都初始化为1。 ④填表顺序从左往右。 ⑤返回值返回dp表中的最大值。
class Solution
{
public:int lengthOfLIS(vectorint nums) {int n nums.size();vectorint dp(n, 1);int ret 1;for(int i 1; i n; i){for(int j 0; j i; j)if(nums[j] nums[i]) dp[i] max(dp[i], dp[j] 1);ret max(ret, dp[i]);}return ret;}
};
28、376. 摆动序列 ①状态表示 dp[i]表示:以i位置的元素为结尾的所有子序列里面最长摆动序列的长度。× f[i]表示:以i位置的元素为结尾的所有子序列里面最后一个位置呈现“上升”趋势的最长摆动序列的长度。 g[i]表示:以i位置的元素为结尾的所有子序列里面最后一个位置呈现“下降”趋势的最长摆动序列的长度。 ②状态转移方程 上升长度为一f[i]1 长度大于一ifnums[j]nums[i]) f[i]max(g[j]1) 下降长度为一g[i]1 长度大于一ifnums[j]nums[i]) g[i]max(f[j]1) ③初始化dp表里的值都初始化为1。 ④填表顺序从左往右。 ⑤返回值f表和g表中的最大值。
class Solution
{
public:int wiggleMaxLength(vectorint nums) {int n nums.size();vectorint f(n, 1), g(n, 1);int ret 1;for(int i 1; i n; i){for(int j 0; j i; j){if(nums[j] nums[i]) f[i] max(f[i], g[j] 1);else if(nums[j] nums[i]) g[i] max(g[i], f[j] 1);}ret max(ret, max(f[i], g[i]));}return ret;}
};
29、673. 最长递增子序列的个数 ①状态表示 dp[i]表示:以i位置的元素为结尾的所有子序列里面最长递增子序列的个数。× len[i]表示:以i位置的元素为结尾的所有子序列里面最长递增子序列的长度。 count[i]表示:以i位置的元素为结尾的所有子序列里面最长递增子序列的个数。 ②状态转移方程 if(len[j]1len[i]) count[i]count[j] if(len[j]1len[i]) 无视 if(len[j]1len[i]) len[i]len[j]1; count[i]count[j] ③初始化len[i]count[i]1(两个表都初始化为1 ④填表顺序从左往右。 ⑤返回值通过小贪心的策略从左往右扫描时找最大值的同时也更新最大值的个数。
class Solution
{
public:int findNumberOfLIS(vectorint nums) {int n nums.size();vectorint len(n, 1), count(n, 1);int retlen 1, retcount 1;for(int i 1; i n; i){for(int j 0; j i; j){if(nums[j] nums[i]){if(len[j] 1 len[i]) count[i] count[j];else if(len[j] 1 len[i]) len[i] len[j] 1, count[i] count[j];}}if(retlen len[i]) retcount count[i];else if(retlen len[i]) retlen len[i], retcount count[i];}return retcount;}
};
30、673. 最长递增子序列的个数 ①状态表示先预处理按照第一个元素排序即可 dp[i]表示:以i位置的元素为结尾的所有数对链中最长数对链的长度。 ②状态转移方程 长度为1dp[i]1 长度大于1if(p[j][1]p[i][0]) dp[i]max(dp[j]1) ③初始化表中元素都初始化为1 ④填表顺序从左往右。 ⑤返回值dp表中的最大值。
class Solution
{
public:int findLongestChain(vectorvectorint pairs) {sort(pairs.begin(), pairs.end());int n pairs.size();vectorint dp(n, 1);int ret 1;for(int i 1; i n; i){for(int j 0; j i; j){if(pairs[j][1]pairs[i][0]) dp[i] max(dp[i], dp[j] 1);}ret max(ret, dp[i]);}return ret;}
};
31、1218. 最长定差子序列 ①状态表示 dp[i]表示:以i位置的元素为结尾的所有子序列里面最长等差子序列的长度。 ②状态转移方程 b不存在1 b存在最后一个dp[j]1 优化将元素dp[j]的值绑定放在哈希表中。直接在哈希表中做动态规划。 ③初始化hash[arr[0]]1 ④填表顺序从左往右。 ⑤返回值dp表中的最大值。
class Solution
{
public:int longestSubsequence(vectorint arr, int difference) {unordered_mapint, int hash;hash[arr[0]] 1;int ret 1;for(int i 1; i arr.size(); i){hash[arr[i]] hash[arr[i] - difference] 1;ret max(ret, hash[arr[i]]);}return ret;}
};
32、1218. 最长定差子序列①状态表示 dp[i]表示:以i位置的元素为结尾的所有子序列中最长斐波那契子序列的长度。× dp[i][j]表示:以i位置以及j位置为结尾的所有子序列里面最长斐波那契子序列的长度。 ②状态转移方程nums[i]b;nums[j]c;nums[k]a; a存在且abdp[i][j]dp[k][j]1 a存在且bac / a不存在dp[i][j]2 优化将数组中所有元素与它们的下标绑定存在哈希表中。直接在哈希表中做动态规划。 ③初始化表里面所有的值都初始化为2。 ④填表顺序从上往下。 ⑤返回值dp表中的最大值。ret3?0:ret
class Solution
{
public:int lenLongestFibSubseq(vectorint arr) {int n arr.size();// 优化unordered_mapint, int hash;for(int i 0; i n; i) hash[arr[i]] i;int ret 2;vectorvectorint dp(n, vector(n, 2));for(int j 2; j n; j) // 固定最后一个位置{for(int i 1; i j; i){int a arr[j] - arr[i];if(a arr[i] hash.count(a)) dp[i][j] dp[hash[a]][i] 1;ret max(ret, dp[i][j]);}}return ret 3 ? 0 : ret;}
};
33、1027. 最长等差数列 ①状态表示 dp[i]表示:以i位置的元素为结尾的所有子序列中最长等差序列的长度。× dp[i][j]表示:以i位置以及j位置为结尾的所有子序列里面最长等差序列的长度。 ②状态转移方程nums[i]b;nums[j]c;nums[k]a; a存在且abdp[i][j]dp[k][j]1 a存在且bac / a不存在dp[i][j]2 优化 法一将数组中所有元素与它们的下标绑定元素下标数组存在哈希表中。直接在哈希表中做动态规划。(可行但超时 法二一边dp一边保存离它最近的下标。元素下标 ③初始化dp表中所有的值都初始化为2。 ④填表顺序: 法一先固定最后一个数再枚举倒数第二个数无法保存下标 法二先固定倒数第二个数再枚举最后一个数。 选第二种填表方式当i位置填完之后将i位置的值放入哈希表中即可。 ⑤返回值dp表中的最大值。
class Solution
{
public:int longestArithSeqLength(vectorint nums) {// 优化unordered_mapint,int hash;hash[nums[0]] 0;int n nums.size();vectorvectorint dp(n, vectorint(n, 2)); // 创建dp表 初始化int ret 2;for(int i 1; i n; i) // 固定倒数第二个数{for(int j i 1; j n; j) // 枚举倒数第一个数{int a 2 * nums[i] - nums[j];if(hash.count(a))dp[i][j] dp[hash[a]][i] 1;ret max(ret, dp[i][j]);}hash[nums[i]] i;}return ret;}
};
33、446.等差数列划分 II - 子序列 ①状态表示 dp[i]表示:以i位置的元素为结尾的所有子序列中等差子序列的个数。×只知道子序列的个数但不能确定一个具体的子序列 dp[i][j]表示:以i位置以及j位置为结尾的所有子序列中等差子序列的个数。 ②状态转移方程nums[i]b;nums[j]c;nums[kx]a; a存在且kxidp[i][j]dp[kx][i]1 dp[i][j]dp[kx][i]1 优化将元素下标数组绑定在一起存在哈希表中。 ③初始化dp表中所有的值都初始化为0。 ④填表顺序:先固定最后一个数再枚举倒数第二个数 ⑤返回值dp表中的所有元素的和。
class Solution
{
public:int numberOfArithmeticSlices(vectorint nums) {int n nums.size();// 优化unordered_maplong long, vectorint hash;for(int i 0; i n; i) hash[nums[i]].push_back(i);vectorvectorint dp(n, vectorint(n)); // 创建dp表 初始化int sum 0;for(int j 2; j n; j) // 固定倒数第二个数{for(int i 1; i j; i) // 枚举倒数第一个数{long long a (long long)2 * nums[i] - nums[j];if(hash.count(a)){for(auto k : hash[a]){if(k i) dp[i][j] dp[k][i] 1;}}sum dp[i][j];}}return sum;}
};
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/90263.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!