0
点赞
收藏
分享

微信扫一扫

Leetcode-动态规划

老榆 2022-02-11 阅读 78
leetcode

文章目录


q5 最长回文子串


题目传送门


题解

首先要把动态转移方程给找出来,可以发现dp[i][j]如果是回文串,那么dp[i + 1][j - 1]得是回文串,其中dp[i][j]表示字符串下标i到j的子串。同时还要考虑边界条件,那就是如果子串长度小于2,那么就一定是回文串,如果子串长度等于2,那么是回文串就只需要满足dp[i] == d[j]。

func longestPalindrome(s string) string {
	n := len(s)
	dp := make([][]bool, n)
	for i, _ := range dp {
		dp[i] = make([]bool, n)
	}
	ans := ""
	// 第一层遍历子串的长度
	for l := 0; l < n; l++ {
		// 第二层是子串的左边界
		for i := 0; i + l < n; i++ {
			// j是子串的右边界
			j := i + l
			if l == 0 {
				dp[i][j] = true
			} else if l == 1 {
				dp[i][j] = (s[i] == s[j])
			} else {
				dp[i][j] = (s[i] == s[j] && dp[i + 1][j - 1])
			}
			// 更新最大值
			if dp[i][j] && l + 1 > len(ans) {
				ans = s[i:j + 1]
			}
		}
	}
	return ans
}

q53 最大子数组和


题目传送门


题解

遍历数组,开辟一个新数组dp,循环遍历nums,让dp[i] = nums[i],然后判断dp[i] + dp[i - 1]是否大于dp[i],如果大于就让dp[i] += dp[i - 1]

func maxSubArray(nums []int) int {
	dp := make([]int, len(nums))
	dp[0] =  nums[0]
	maxSum := nums[0]
	for i := 1; i < len(nums); i++ {
		dp[i] = nums[i]
		if dp[i - 1] + dp[i] > dp[i] {
			dp[i] += dp[i - 1]
		}
		if dp[i] > maxSum {
			maxSum = dp[i]
		}
	}
	return maxSum
}

q62 不同路径


题目传送门


题解

这道题目的动态转移方程非常简单,因为只能向下和向右走,所以dp[i][j] = dp[i - 1][j] + dp[i][j - 1],最后处理一下边界条件即可,dp[i][0]和dp[0][j]都等于1,因为都只有一条路径通往边界。

func uniquePaths(m int, n int) int {
	dp := make([][]int, m)
	for i := 0; i < m; i++ {
		dp[i] = make([]int, n)
		dp[i][0] = 1
	}
	for j := 0; j < n; j++ {
		dp[0][j] = 1
	}
	for i := 1; i < m; i++ {
		for j := 1; j < n; j++ {
			dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
		}
	}
	return dp[m - 1][n - 1]
}

q64 最小路径和


题目传送门


题解

这道题使用动态规划求解,动态转移方程是dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]),然后处理一下边界情况即可,边界是当i == 0或者j == 0的时候,这个时候dp[i][0] = dp[i - 1][0],dp[0][j] = dp[0][j - 1]。

func minPathSum(grid [][]int) int {
	m, n := len(grid), len(grid[0])
	dp := make([][]int, m)
	dp[0] = make([]int, n)
	dp[0][0] = grid[0][0]
	for i := 1; i < m; i++ {
		dp[i] = make([]int, n)
		dp[i][0] = grid[i][0]
		dp[i][0] += dp[i - 1][0]
	}
	for j := 1; j < n; j++ {
		dp[0][j] = grid[0][j]
		dp[0][j] += dp[0][j - 1]
	}
	for i := 1; i < m; i++ {
		for j := 1; j < n; j++ {
			dp[i][j] = grid[i][j]
			dp[i][j] += min(dp[i - 1][j], dp[i][j - 1])
		}
	}
	return dp[m - 1][n - 1]
}
func min(a, b int) int {
	if a < b {
		return a
	} else {
		return b
	}
}

q70 爬楼梯


题目传送门


题解

这道题使用递推来求解即可,递推公式是step[i] = step[i - 1] + step[i - 2],然后处理一下边界条件即可,当i == 1时,step[1] = 1,当i == 2时,step[2] = 2。

func climbStairs(n int) int {
	if n <= 2 {
		return n
	}
	step1, step2, step3 := 1, 2, 0
	for i := 3; i <= n; i++ {
		step3 = step1 + step2
		step1 = step2
		step2 = step3
	}
	return step3
}

q118 杨辉三角


题目传送门


题解

这道题使用动态规划求解,状态转移方程是dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j],然后处理一下边界条件即可,如果行数小于3,那么所有元素都是1,当行数大于等于3时,只有当列数不是第一个和最后一个时才满足状态转移方程,否则都为1 。

func generate(numRows int) [][]int {
	res := [][]int{{1}}
	if numRows == 1 {
		return res
	}
	res = append(res, []int{1, 1})
	if numRows == 2 {
		return res
	}
	for i := 3; i <= numRows; i++ {
		var rows []int
		for j := 1; j <= i; j++ {
			if j != 1 && j != i {
				rows = append(rows, res[i - 2][j - 2] + res[i - 2][j - 1])
			} else {
				rows = append(rows, 1)
			}
		}
		res = append(res, rows)
	}
	return res
}

q300 最长上升子序列


题目传送门


题解

首先定义一个数组dp用来保存到当前元素位置为止的最长上升子序列长度。要使用两层循环,第一层循环遍历nums数组,第二层循环遍历从零开始到nums数组当前元素的前一个元素,如果当前元素满足nums[i] > num[j] && dp[j] + 1 > dp[i],就执行dp[i] = dp[j] + 1来更新最长上升子序列。

func lengthOfLIS(nums []int) int {
	dp := make([]int, len(nums))
	maxLen := 0
	for i := 0; i < len(nums); i++ {
		dp[i] = 1
		for j := 0; j < i; j++ {
			if nums[i] > nums[j] && dp[j] + 1 > dp[i] {
				dp[i] = dp[j] + 1
			}
		}
		if dp[i] > maxLen {
			maxLen = dp[i]
		}
	}
	return maxLen
}

q1143 最长公共子序列


题目传送门


题解

定义一个数组dp[i][j]表示text1[1…i]和text2[1…j]的最长公共子序列的长度,那么最终答案就是dp[len1][len2]。
这道题可以分为三种情况来考虑:

  1. text1[i]不在公共子序列中,那么dp[i][j] = dp[i - 1][j]
  2. text2[j]不在公共子序列中,那么dp[i][j] = dp[i][j - 1]
  3. text1[i] == text2[j],这个时候dp[i][j] = dp[i - 1][j - 1] + 1

dp[i][j]取上述三种情况的最大值。然后处理一下边界条件,dp[i][0]和dp[0][j]都为0 。

func longestCommonSubsequence(text1 string, text2 string) int {
	len1, len2 := len(text1), len(text2)
	dp := make([][]int, len1 + 1)
	for i := 0; i <= len1; i++ {
		dp[i] = make([]int, len2 + 1)
	}
	for i := 1; i <= len1; i++ {
		for j := 1; j <= len2; j++ {
			dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
			if text1[i - 1] == text2[j - 1] {
				dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1)
			}
		}
	}
	return dp[len1][len2]
}

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

举报

相关推荐

0 条评论