0%

双指针法

使用两个指针 i,j 分别指向串 s 和串 ts[i]==t[j],i++,j++ 否则 j++i=s.size() 时,说明是子序列,否则移动到 j=t.size() 结束。

代码实现:

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
bool isSubsequence(string s, string t) {
int n=s.size(),m=t.size(),i=0,j=0;
for(;i<n,j<m;j++){
if(s[i]==t[j]) i++;
}
if(i==n) return true;
return false;
}
};
阅读全文 »

动态规划

此处寻找的是连续的子序列,要求子序列的和能够最大。重点依旧是动态规划数组的定义。

  1. 动态规划数组的定义:定义动态规划数组 dp[n+1] ,其中 dp[i] 表示以 nums[i-1] 结尾的子序列的最大和。
  2. 动态规划数组的推导:对于 dp[i] ,推导公式为 dp[i]=max(nums[i-1],nums[i-1]+dp[i-1])
  3. 动态规划数组的初始化:对于 dp[0] 不存在序列,初始化为0即可
  4. 动态规划数组的遍历顺序:从前向后遍历
  5. 举例验证:对于 nums = [-2,1,-3,4,-1,2,1,-5,4] 对应的动态规划数组输出为 dp=-2,1,-2,4,3,5,6,1,5 ,结果为6,验证正确。
阅读全文 »

动态规划

本题也是一个求解最长公共子序列的问题,但是不同于718.最长重复子数组,在本题中的子序列是不连续的,那么使用动态规划进行求解,就需要改变动态规划数组的定义。

  1. 动态规划数组的定义:定义数组 dp[text1.size()+1][text2.size()+1] ,其中 dp[i][j] 表示在 text1[i-1]text2[j-1] 前的最长子序列的长度

  2. 动态规划数组的推导:对于 dp[i][j] ,那么首先需要判断 text1[i-1]==text2[j-1] ,不相等 dp[i][j]=max(dp[i-1][j],dp[i][j-1]) (也就是等于两个更短序列的最长的公共子序列的长度,更短的方式有两种,分别是缺少 text1[i-2]text2[j-2] ),若是相等, dp[i][j]=dp[i-1][j-1]+1 ,相等则是在 text1[i-2]text2[j-2] 的基础上在增加一个长度值。

  3. 动态规划数组的初始化:在初始时只需要全部初始化为0即可。

  4. 动态规划数组的遍历:逐行遍历,在行内采取从前向后的遍历方式。

  5. 举例验证:对于 text1 = "abcde", text2 = "ace" 对应的动态规划数组为:

0,0,0,0,
0,1,1,1,
0,1,1,1,
0,1,2,2,
0,1,2,2,
0,1,2,3,

阅读全文 »

动态规划

本质上就是在两个序列中,寻找两个最长的公共子序列(此处的公共子序列是连续的)。使用动态规划求解,重点依旧是动态规划数组的定义。

  1. 动态规划数组的定义:定义数组 dp[nums1.size()][nums2.size()] 其中 dp[i][j] 表示以 nums1[i]nums2[j] 结尾的最长公共子序列的长度。

  2. 动态规划数组的推导:对于 dp[i][j] ,若是 nums1[i]==nums2[j] 那么 dp[i][j]=dp[i-1][j-1]+1 ,否则 dp[i][j]=0

  3. 动态规划数组的初始化:此处的初始化主要是针对于第一行和第一列进行, i=0dp[i][j]=1 if nums1[0]==nums2[j] else =0j=0dp[i][j]=1 if nums1[i]==nums2[0] else =0

  4. 动态规划数组的遍历顺序:从前向后,逐行进行遍历。

  5. 举例验证:

阅读全文 »

贪心实现

基于贪心实现,使用双指针的方式,只需要对数组进行一次遍历。

定义指针 i 直线当前连续递增子序列的第一个元素,指针 j 指向当前递增子序列的最后一个元素。初始时 i==j ,指针 j 后移一位,若是 nums[j]>nums[j+1] 那么 j++ ,否则 len=j-i,res=max(res,len) ,然后 i=j 继续循环。

阅读全文 »

动态规划

此处子序列是不连续的。本题的重点依旧是动态规划数组的定义:也就是如何从i推导到i+1。

  1. 动态规划数组的定义:定义数组 dp[i] 表示 i 之前包括 i 的以 nums[i] 结尾的最长递增子序列的长度。本题的重点应该就是关注于递增序列的结尾元素,因此要让递增序列继续增长,那么就需要和序列末尾的元素进行比较,因此将动态规划数组做此定义。

  2. 动态规划数组的推导:那么 dp[i+1] 则表示,在 i+1 之前包括 i+1 的以 nums[i+1] 结尾的最长递增子序列的长度,那么推导为:dp[i+1]=max(dp[j])+1 其中 j=0...i 并且要求 nums[j]<nums[i+1]

  3. 动态规划数组的初始化:dp[0] 只包含一个元素,最长的递增子序列长度为1, dp[0]=1

  4. 动态规划数组的遍历顺序:从前向后遍历

  5. 举例验证:输入 nums=[10,9,2,5,3,7,101,18] 动态规划数组的变化过程为:

dp=[1,1,0,0,0,0,0,0]
dp=[1,1,1,0,0,0,0,0]
dp=[1,1,1,2,0,0,0,0]
dp=[1,1,1,2,2,0,0,0]
dp=[1,1,1,2,2,3,0,0]
dp=[1,1,1,2,2,3,4,0]
dp=[1,1,1,2,2,3,4,4]

阅读全文 »

股票买卖问题总结

问题的描述都为:给定一支股票的价格变动数组,根据相应的价格变动数组买卖股票,要求能够获得最大的利润。

条件上的改变:股票只能交易一次,股票可以交易任意次,股票可以交易常数次,股票可以交易k次,股票在卖出后的一天冷冻期不能交易,股票交易需要收取手续费。

基本的求解方式为:动态规划和贪心

阅读全文 »

动态规划

依旧是对交易的次数不进行限制,但是每买卖一次都会产生相应的手续费。使用动态规划求解,重点依旧是动态规划数组的定义。本题相对于122.买卖股票的最佳时机II改变的仅仅是卖出环节需要收取手续费,那么就需要修改递推公式。

  1. 动态规划数组的定义:定义动态规划数组 dp[n][2] ,其中 dp[i][0] 表示在第 i 天持有股票所拥有的最大现金数, dp[i][1] 表示在第 i 天不持有股票所拥有的最大现金数

  2. 动态规划数组的推导:分别推导 dp[i][0]dp[i][1]

对于 dp[i][0] 的推导:

  • 前一天持有: dp[i][0]=dp[i-1][0]
  • 前一天不持有: dp[i][0]=dp[i-1][1]-prices[i]

对于 dp[i][1] 的推导:

  • 前一天持有: dp[i][1]=dp[i-1][0]+prices[i]-fee
  • 前一天不持有: dp[i][1]=dp[i-1][1]

总体的推导为:

1
2
dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i]);
dp[i][1]=max(dp[i-1][0]+prices[i]-fee,dp[i-1][1]);
  1. 动态规划数组的初始化:在第一天 dp[0][0]=-peices[0] 买入,不持有只需不买入 dp[0][1]=0

  2. 动态规划数组的遍历顺序:从前向后遍历

  3. 举例验证:对于 prices = [1, 3, 2, 8, 4, 9], fee = 2 动态规划数组的变化过程为:(仅展示最后一位)

dp[i]
-1 0
-1 0
-1 0
-1 5
1 5
1 8

阅读全文 »

动态规划

要使用动态规划对本题进行求解,重点依旧是动态规划数组的定义。对于股票买卖的次数是不做限制的,对于股票的状态也仅有两种状态,持有或不持有,但是对于卖出股票后,需要限制在后一天买入股票,也就是后一天是无法持有股票的。此处需要对于每一天的状态进行进一步细分

  1. 动态规划数组的定义:定义数组 dp[n][4] ,其中
  • dp[i][0] 表示在 i 天持有股票所拥有的最大现金,
  • dp[i][1] 表示在第 i 天不持有股票并且不是冷冻期所拥有的最大现金数
  • dp[i][2] 表示在第 i 天卖出股票所拥有的最大现金数
  • dp[i][3] 表示在第 i 天为冷冻期所拥有的最大现金数
  1. 动态规划数组的推导:

对于 dp[i][0] 的推导:三种情形进行推导

  • 前一天持有的情形,在第 i 天无需对股票进行操作 dp[i][0]=dp[i-1][0]
  • 前一天不持有的情形:
    • 前一天是不持有的并且不是冷冻期: dp[i][0]=dp[i-1][1]-prices[i]
    • 前一天是冷冻期,在今天恰好可以买入: dp[i][0]=dp[i-1][3]-prices[i]

对于 dp[i][1] 的推导:两种情形

  • 前一天不持有且不是冷冻期的情形: dp[i][1]=dp[i-1][1]
  • 前一天是冷冻期的情形: dp[i][1]=dp[i-1][3]

对于 dp[i][2] 的推导:一种情形

  • 前一天持有股票: dp[i][2]=dp[i-1][0]+prices[i]

对于 dp[i][3] 的推导:一种情形

  • 前一天卖出股票: dp[i][3]=dp[i-1][2]

综上所述,总体的递推代码为:

1
2
3
4
dp[i][0]=max(dp[i-1][0],max(dp[i-1][1]-prices[i],dp[i-1][3]-prices[i]));
dp[i][1]=max(dp[i-1][1],dp[i-1][3]);
dp[i][2]=dp[i-1][0]+prices[i];
dp[i][3]=dp[i-1][2];
  1. 动态规划数组的初始化:对于 dp[0][0] 在第一天买入 dp[0][0]=-prices[0] ,对于 dp[0][1] 是不持有的状态,那么就只需要在一开始就不买入: dp[0][1]=0 对于 dp[0][2] 也就是当天买入当天卖出 dp[0][2]=0 不存在第一天为冷冻期的情形,那么此时的现金数就一定是0

  2. 动态规划数组的遍历顺序:从前向后遍历

阅读全文 »

动态规划

相较于 123.买卖股票的最佳时机III,此处对于交易的次数进行了另一种限定,交易的次数是可变的。尝试依旧采取同样的方式去定义动态规划数组:

  1. 动态规划数组的定义:定义数组 dp[i][2*k+1] ,分别表示在第 i 天的 2*k+1 种状态
  • dp[i][0] 表示在第 i 天未对股票进行任何操作所拥有的最大现金数
  • dp[i][1] 表示在第 i 天第一次持有股票所拥有的最大现金数
  • dp[i][2] 表示在第 i 天第一次不持有股票所拥有的最大现金数
  1. 动态规划数组的推导:推导的方式依旧是是从前一天进行推导。
  • dp[i][1] 表示在第 i 天第一次持有股票所拥有的最大现金数,那么只有前一天就持有和前一天不持有两种情况: dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i])
  • dp[i][2] 表示在第 i 天第一次不持有股票所拥有的最大现金数,那么只有前一天持有和前一天不持有两种情况: dp[i][2]=max(dp[i-1][1]+prices[i],dp[i-1][2])
    • dp[i][3] 表示在第 i 天第二次持有股票所拥有的最大现金数,那么只有前一天就持有和前一天不持有两种情况: dp[i][3]=max(dp[i-1][3],dp[i-1][2]-prices[i])
  • dp[i][4] 表示在第 i 天第二次不持有股票所拥有的最大现金数,那么只有前一天持有和前一天不持有两种情况: dp[i][4]=max(dp[i-1][3]+prices[i],dp[i-1][4])
  1. 动态规划数组的初始化:对于第 0 天情形,不操作股票现金为0: dp[0][0]=0 。第 2i+1 次持有就是在当天买入 dp[0][2i+1]=-prices[0]2i 次持有就是在当天卖出 dp[0][2i]=0
  2. 动态规划数组的遍历:对于当前状态的推导需要使用前一天的数据,从前向后遍历。
  3. 举例验证:对于 k = 2, prices = [2,4,1] ,求解的过程为:

dp={0,-2, 0,-2, 0}
dp={0,-2, 2,-2, 2}
dp={0, 0, 0, 0, 0}
dp={0,-2, 0,-2, 0}
dp={0,-2, 2,-2, 2}
dp={0,-1, 2, 1, 2}

阅读全文 »