代码随想录day46|1143最长公共子序列1035不相交的线53最大子序和|01笔记

164 阅读3分钟
  • 1143最长公共子序列

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 本题和718最长重复子数组的区别就是子集是否是连续的。
  • 本题用暴力解法很难搜索出来。考虑直接使用动态规划的方法推导。回忆之前解决300最长上升的搜索不连续子集的方法。我们需要两层循环。
  • 讲解观后感

  • 确定dp数组(dp table)以及下标的含义
    dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]
  • 确定递推公式
  • 主要就是两大情况: text1[i - 1] 与 text2[j - 1]相同,text1[i - 1] 与 text2[j - 1]不相同
    如果text1[i - 1] 与 text2[j - 1]相同,那么找到了一个公共元素,所以dp[i][j] = dp[i - 1][j - 1] + 1;
    如果text1[i - 1] 与 text2[j - 1]不相同,那就看看text1[0, i - 2]与text2[0, j - 1]的最长公共子序列 和 text1[0, i - 1]与text2[0, j - 2]的最长公共子序列,取最大的。
    即:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
  • dp数组初始化
    test1[0, i-1]和空串的最长公共子序列自然是0,所以dp[i][0] = 0;同理dp[0][j]也是0
  • 解题代码

  •     func longestCommonSubsequence(text1 string, text2 string) int {
        	t1 := len(text1)
        	t2 := len(text2)
        	dp:=make([][]int,t1+1)
        	for i:=range dp{
        		dp[i]=make([]int,t2+1)
        	}
        
        	for i := 1; i <= t1; i++ {
        		for j := 1; j <=t2; 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[t1][t2]
        }
        
        func max(a,b int)int  {
        	if a>b{
        		return a
        	}
        	return b
        }
    
  • 1035不相交的线

  • 代码随想录 (programmercarl.com)
  • 讲解观后感

  • 本题表面看似是一道图形题。但是我们可以发现,要想实现连接的线不相交,那么我们只要找到相同顺序的最大子序列就可以了。于是本题的解法就和上题完全一样了。
  • 解题代码

  •     
        func maxUncrossedLines(A []int, B []int) int {
        	m, n := len(A), len(B)
        	dp := make([][]int, m+1)
            for i := range dp {
                dp[i] = make([]int, n+1)
            }
        
        	for i := 1; i <= len(A); i++ {
        		for j := 1; j <= len(B); j++ {
        			if (A[i - 1] == B[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[m][n]
        
        }
        
        func max(a, b int) int {
            if a > b {
                return a
            }
            return b
        }
    
  • 53最大子序和

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 这题之前在用过一次贪心的方法,53最大子序和|01笔记 - 掘金 (juejin.cn)
  • 这次尝试用动态规划的方式推导一遍。
  • 讲解观后感

  • 运用动态规划的方法,首先确定dp数组的含义。dp[i]表示最大的连续子数组和,包含num[i] 元素。
  • 易得dp[i]的结果只能由dp[i-1]+nums[i]得到。所以状态转移公式为dp[i] = max(dp[i-1]+nums[i],nums[i])
  • 初始化时,dp[0]就等于nums[0]的值
  • 由于我们得到的最大值不一定是最后位置的值,所以我们还需要维护一个最大值。
  • 解题代码

  •     func maxSubArray(nums []int) int {
            n := len(nums)
            // 这里的dp[i] 表示,最大的连续子数组和,包含num[i] 元素
            dp := make([]int,n)
            // 初始化,由于dp 状态转移方程依赖dp[0]
            dp[0] = nums[0]
            // 初始化最大的和
            mx := nums[0]
            for i:=1;i<n;i++ {
                // 这里的状态转移方程就是:求最大和
                // 会面临2种情况,一个是带前面的和,一个是不带前面的和
                dp[i] = max(dp[i-1]+nums[i],nums[i])
                mx = max(mx,dp[i])
            }
            return mx
        }
        
        func max(a,b int) int{
            if a>b {
                return a 
            }
            return b
        }