双指针法
使用两个指针 i,j
分别指向串 s
和串 t
,s[i]==t[j],i++,j++
否则 j++
当 i=s.size()
时,说明是子序列,否则移动到 j=t.size()
结束。
代码实现:
1 | class Solution { |
此处寻找的是连续的子序列,要求子序列的和能够最大。重点依旧是动态规划数组的定义。
dp[n+1]
,其中 dp[i]
表示以 nums[i-1]
结尾的子序列的最大和。dp[i]
,推导公式为 dp[i]=max(nums[i-1],nums[i-1]+dp[i-1])
dp[0]
不存在序列,初始化为0即可nums = [-2,1,-3,4,-1,2,1,-5,4]
对应的动态规划数组输出为 dp=-2,1,-2,4,3,5,6,1,5
,结果为6,验证正确。本题也是一个求解最长公共子序列的问题,但是不同于718.最长重复子数组,在本题中的子序列是不连续的,那么使用动态规划进行求解,就需要改变动态规划数组的定义。
动态规划数组的定义:定义数组 dp[text1.size()+1][text2.size()+1]
,其中 dp[i][j]
表示在 text1[i-1]
和 text2[j-1]
前的最长子序列的长度
动态规划数组的推导:对于 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]
的基础上在增加一个长度值。
动态规划数组的初始化:在初始时只需要全部初始化为0即可。
动态规划数组的遍历:逐行遍历,在行内采取从前向后的遍历方式。
举例验证:对于 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,
本质上就是在两个序列中,寻找两个最长的公共子序列(此处的公共子序列是连续的)。使用动态规划求解,重点依旧是动态规划数组的定义。
动态规划数组的定义:定义数组 dp[nums1.size()][nums2.size()]
其中 dp[i][j]
表示以 nums1[i]
和 nums2[j]
结尾的最长公共子序列的长度。
动态规划数组的推导:对于 dp[i][j]
,若是 nums1[i]==nums2[j]
那么 dp[i][j]=dp[i-1][j-1]+1
,否则 dp[i][j]=0
动态规划数组的初始化:此处的初始化主要是针对于第一行和第一列进行, i=0
时 dp[i][j]=1 if nums1[0]==nums2[j] else =0
, j=0
时 dp[i][j]=1 if nums1[i]==nums2[0] else =0
动态规划数组的遍历顺序:从前向后,逐行进行遍历。
举例验证:
此处子序列是不连续的。本题的重点依旧是动态规划数组的定义:也就是如何从i推导到i+1。
动态规划数组的定义:定义数组 dp[i]
表示 i
之前包括 i
的以 nums[i]
结尾的最长递增子序列的长度。本题的重点应该就是关注于递增序列的结尾元素,因此要让递增序列继续增长,那么就需要和序列末尾的元素进行比较,因此将动态规划数组做此定义。
动态规划数组的推导:那么 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]
动态规划数组的初始化:dp[0]
只包含一个元素,最长的递增子序列长度为1, dp[0]=1
动态规划数组的遍历顺序:从前向后遍历
举例验证:输入 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]
依旧是对交易的次数不进行限制,但是每买卖一次都会产生相应的手续费。使用动态规划求解,重点依旧是动态规划数组的定义。本题相对于122.买卖股票的最佳时机II改变的仅仅是卖出环节需要收取手续费,那么就需要修改递推公式。
动态规划数组的定义:定义动态规划数组 dp[n][2]
,其中 dp[i][0]
表示在第 i
天持有股票所拥有的最大现金数, dp[i][1]
表示在第 i
天不持有股票所拥有的最大现金数
动态规划数组的推导:分别推导 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 | dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i]); |
动态规划数组的初始化:在第一天 dp[0][0]=-peices[0]
买入,不持有只需不买入 dp[0][1]=0
动态规划数组的遍历顺序:从前向后遍历
举例验证:对于 prices = [1, 3, 2, 8, 4, 9], fee = 2
动态规划数组的变化过程为:(仅展示最后一位)
dp[i]
-1 0
-1 0
-1 0
-1 5
1 5
1 8
要使用动态规划对本题进行求解,重点依旧是动态规划数组的定义。对于股票买卖的次数是不做限制的,对于股票的状态也仅有两种状态,持有或不持有,但是对于卖出股票后,需要限制在后一天买入股票,也就是后一天是无法持有股票的。此处需要对于每一天的状态进行进一步细分
dp[n][4]
,其中 dp[i][0]
表示在 i
天持有股票所拥有的最大现金, dp[i][1]
表示在第 i
天不持有股票并且不是冷冻期所拥有的最大现金数dp[i][2]
表示在第 i
天卖出股票所拥有的最大现金数dp[i][3]
表示在第 i
天为冷冻期所拥有的最大现金数对于 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 | dp[i][0]=max(dp[i-1][0],max(dp[i-1][1]-prices[i],dp[i-1][3]-prices[i])); |
动态规划数组的初始化:对于 dp[0][0]
在第一天买入 dp[0][0]=-prices[0]
,对于 dp[0][1]
是不持有的状态,那么就只需要在一开始就不买入: dp[0][1]=0
对于 dp[0][2]
也就是当天买入当天卖出 dp[0][2]=0
不存在第一天为冷冻期的情形,那么此时的现金数就一定是0
动态规划数组的遍历顺序:从前向后遍历
相较于 123.买卖股票的最佳时机III,此处对于交易的次数进行了另一种限定,交易的次数是可变的。尝试依旧采取同样的方式去定义动态规划数组:
dp[i][2*k+1]
,分别表示在第 i
天的 2*k+1
种状态dp[i][0]
表示在第 i
天未对股票进行任何操作所拥有的最大现金数dp[i][1]
表示在第 i
天第一次持有股票所拥有的最大现金数dp[i][2]
表示在第 i
天第一次不持有股票所拥有的最大现金数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])
0
天情形,不操作股票现金为0: dp[0][0]=0
。第 2i+1
次持有就是在当天买入 dp[0][2i+1]=-prices[0]
第 2i
次持有就是在当天卖出 dp[0][2i]=0
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}