子序列问题
最后更新于
最后更新于
给两个整数数组 A
和 B
,返回两个数组中公共的、长度最长的子数组的长度。
方法一:动态规划:
dp[i][j]
表示长度为 i,末尾项为A[i-1]
的子数组,长度为 j,末尾项为B[j-1]
的子数组,二者的最大公共后缀子数组长度。如果A[i-1] != B[j-1]
,dp[i][j] = 0
如果A[i-1] == B[j-1]
,dp[i][j] = dp[i-1][j-1] + 1
。base case:如果
i==0 || j==0
,其中一个数组长度为 0,没有公共部分,dp[i][j] = 0
最长公共子数组以哪一项为末尾项都有可能,即每个dp[i][j]
都可能是最大值。方法二:滑动窗口:枚举 A 和 B 所有的对齐方式。对齐的方式有两类:第一类为 A 不变,B 的首元素与 A 中的某个元素对齐;第二类为 B 不变,A 的首元素与 B 中的某个元素对齐。对于每一种对齐方式,计算它们相对位置相同的重复子数组即可。时间复杂度: 。
方法三:如果数组 A 和 B 有一个长度为 k 的公共子数组,那么它们一定有长度为 的公共子数组。这样我们可以通过二分查找的方法找到最大的 k。而为了优化时间复杂度,在二分查找的每一步中,使用哈希的方法来判断数组 A 和 B 中是否存在相同特定长度的子数组。(搬运一下官网的讲解)
给你一个整数数组 nums
,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
最长递增子序列(Longest Increasing Subsequence
,简写 LIS
):给定一个无序的整数数组,找到其中最长上升子序列的长度。
思路一:动态规划:
dp[i]
表示以第 i 个数字结尾的最长上升子序列的长度,nums[i]
必须被选取。则状态转移方程为:
思路二:二分查找:
给定一个整型数组,找到所有该数组的递增子序列,递增子序列的长度至少是2。
给定一个字符串 s
,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s
的最大长度为 1000
。
最长公共子序列(Longest Common Subsequence,简称 LCS): 给定两个字符串 text1
和 text2
,返回这两个字符串的最长公共子序列的长度。
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
思路:用 开表示以第 i 个元素结尾的乘积最大子数组的乘积。状态转移方程:
。这里需要 根据正负性进行分类讨论,考虑当前位置如果是一个负数的话,那么我们希望以它前一个位置结尾的某个段的积也是个负数,这样就可以负负得正,并且我们希望这个积尽可能「负得更多」,即尽可能小。如果当前位置是一个正数的话,我们更希望以它前一个位置结尾的某个段的积也是个正数,并且希望它尽可能地大。于是这里我们可以再维护一个 ,它表示以第 i 个元素结尾的乘积最小子数组的乘积,那么我们可以得到这样的动态规划转移方程:
优化空间:由于第 i 个状态只和第 i - 1 个状态相关,根据「滚动数组」思想,我们可以只用两个变量来维护 i - 1 时刻的状态,一个维护 ,一个维护 。
进阶:设计并实现时间复杂度为 的解决方案吗?