动态规划 子数组与子序列问题

332 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

动态规划 子数组与子序列问题

动态规划经典题目,718. 最长重复子数组1143. 最长公共子序列 。 两个字符串求最长重复子数组和最长子序列

两道题不同之处在于 子数组要求连续,而子序列不一定都是连续的,只要前面有相同的子序列,哪怕当前比较的字符不一样,那么当前字符串之前的子序列也不会为 0。而子串(子数组)是连续的,若当前比较的字符不相同,则当前位置的最长公共子数组(子串)的长度为 0,即 dp[i][j] = 0(就是没有)。

所以DP里不同之处在于两点:

  • dp的定义。1143题定义dp[i][j]为截止到nums1[:i-1]和nums2[:j-1]的最长公共子序列的长度。718题dp的定义是nums1[:i-1]和nums2[:j-1]的最大"公共后缀""子数组长度。718题dp的定义保证了所求得的dp值反映了连续的子数组匹配,即nums1[:i-1]和nums2[:j-1]的末尾部分是匹配的。

  • 状态的转移。1143题找的截止到nums1[:i-1]和nums2[:j-1]的最长公共子序列的长度,所以即便是尾部不相等,都要考虑截止到nums1[:i - 2]和nums2[:j-1],和截止到nums1[:i-1]和nums2[:j - 2]的状态(取dp[i - 1][j]和dp[i][j - 1]的较大值)。但718题中,如果尾部不相等,表明没有公共后缀(从后向前看),所以dp[i][j] = 0。

故718题 如果nums1[i - 1] != nums2[j - 1],则dp[i][j] = 0,因为必须要以第i和第j个元素结尾

代码

1143. 最长公共子序列

func longestCommonSubsequence(text1 string, text2 string) int {
    //dp[i][j]代表长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]
    dp := make([][]int,len(text1)+1)
    for i:=0;i<=len(text1);i++{
        dp[i] = make([]int,len(text2)+1)
    }

    for i:=1;i<=len(text1);i++{
        for j:=1;j<=len(text2);j++{
            if text1[i-1] == text2[j-1]{
                dp[i][j] = dp[i-1][j-1] + 1
            }else{
                dp[i][j] = max(dp[i-1][j],dp[i][j-1])
            }
        }
    }
return dp[len(text1)][len(text2)]

}

func max(a,b int)int{
    if a>b{
        return a
    }
    return b
}

718. 最长重复子数组

func findLength(nums1 []int, nums2 []int) int {
    //因为dp[i][j] 和 dp[i-1][j-1]有关,当i=0或j=0时,dp[-1][-1]无意义,所以dp[0][j]、dp[i][0]、dp[0][0]要手动初始化,太过麻烦
  //故以dp[i][j] 代表以nums[i-1]和 nums[j-1]为结尾的最长子数组的长度。
  //也就是最大"公共后缀"子数组长度,注意这里一定要是以i-1和j-1为结尾的
  // 如果nums1[i - 1] != nums2[j - 1],则dp[i][j] = 0,因为必须要以第i和第j个元素结尾

  dp := make([][]int,len(nums1)+1)  //长度多增加1
  for i:=0;i<len(nums1)+1;i++{
      dp[i] = make([]int,len(nums2)+1)
  }
  
    res := 0
    //从dp定义可知要从 1 开始遍历
  for i:=1;i<len(nums1)+1;i++{
      for j:=1;j<len(nums2)+1;j++{
          if nums1[i-1] == nums2[j-1]{
              dp[i][j] = dp[i-1][j-1] + 1
          }
          if dp[i][j] > res{
              res = dp[i][j]
          }
      }
  }
  return res  
}