-
300最长递增子序列
- 300
-
第一印象
- 暴力的算法可以是遍历每一个数字开头的数组,向后检查能够递增的数量,最后给出最大值。这种方法接近O(n^2)。
-
讲解观后感
- 我们依旧用dp的方式来表示题解。这里dp数组的意义是dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度。
- 状态转移方程:
- 位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 + 1 的最大值。
- 所以:
if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
- 存在的最小递增序列就是自身,所以初始化所有dp数组元素为1即可。
- 推导顺序是从前向后。最后返回dp数组中出现过的最大值,因此我们需要一个变量ans存储最大值。
-
解题代码
-
func lengthOfLIS(nums []int) int {
dp := make([]int, len(nums))
for i := range dp {
dp[i] = 1
}
ans := dp[0]
for i := 1; i < len(nums); i++ {
for j := 0; j < i; j++ {
if nums[i] > nums[j] {
dp[i] = max(dp[i], dp[j] + 1)
}
}
if dp[i] > ans {
ans = dp[i]
}
}
return ans
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
-
674最长连续递增序列
- 674
-
第一印象
- 本题换成了连续,所以使用暴力解法时可以更快的迭代。遍历每一个元素开头时产生的序列,不再递增时继续下一个。复杂度接近O(n*m)
-
讲解观后感
- 在动态规划的方法上。因为我们只验证连续递增的情况,所以只需要利用上一个值就可以推导出当前值了。
- 我们可以定义dp数组的意义为dp[i]:以下标i为结尾的连续递增的子序列长度为dp[i]。
- 递推公式:
- 如果 nums[i] > nums[i - 1],那么以 i 为结尾的连续递增的子序列长度 一定等于 以i - 1为结尾的连续递增的子序列长度 + 1 。
即:dp[i] = dp[i - 1] + 1;
- 这里与上题的区别就出现了。由于我们的递增序列是连续的,所以不需要像之前从头寻找,只要直接判断
num[i-1]与现在的关系即可
- 在初始化与遍历顺序上一样,存在的最小递增序列就是自身,所以初始化所有dp数组元素为1即可。
- 最后还是返回dp数组中出现过的最大值,因此我们需要一个变量ans存储最大值。
-
解题代码
- 动态规划
-
func findLengthOfLCIS(nums []int) int {
dp := make([]int, len(nums))
for i := range dp {
dp[i] = 1
}
ans := dp[0]
for i := 1; i < len(nums); i++ {
if nums[i] > nums[i-1] {
dp[i] = dp[i-1]+1
}
if dp[i] > ans {
ans = dp[i]
}
}
return ans
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
- 贪心
- 贪心的解法时利用每次递增结束然后重置序列长度的方法。使用一个变量记录出现的最大值即可。
-
func findLengthOfLCIS(nums []int) int {
if len(nums) == 0 {return 0}
res, count := 1, 1
for i := 0; i < len(nums)-1; i++ {
if nums[i+1] > nums[i] {
count++
}else {
count = 1
}
if count > res {
res = count
}
}
return res
}
-
718最长重复子数组
- 718
-
第一印象
- 这题的子数组指的是连续子数组。暴力的方法是先遍历一个数组,以每个元素为开头,然后再遍历下一个数组,遇到相同时开始计数,不同时再重新计数。存储出现的最大值。复杂度接近O(n^3).
-
讲解观后感
- 本题使用二维数组来记录两个字符串的所有比较情况。
- 首先确定dp数组(dp table)以及下标的含义
dp[i][j] :以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度为dp[i][j]。(字符串最后结束位置为i-1)。这种定义方法也决定了我们要从dp[1][1]初始开始
- 确定递推公式
根据dp[i][j]的定义,dp[i][j]的状态只能由dp[i - 1][j - 1]推导出来。
即当A[i - 1] 和B[j - 1]相等的时候,dp[i][j] = dp[i - 1][j - 1] + 1
- 初始化使dp[i][0]和dp[0][j]为0,这样当遇见相等时
dp[i - 1][j - 1] 进行+1,相同数组就会从1开始计数。
- 我们还是需要一个变量记录出现的最大长度值
-
解题代码
-
func findLength(A []int, B []int) int {
m, n := len(A), len(B)
res := 0
dp := make([][]int, m+1)
for i := 0; i <= m; i++ {
dp[i] = make([]int, n+1)
}
for i := 1; i <= m; i++ {
for j := 1; j <= n; j++ {
if A[i-1] == B[j-1] {
dp[i][j] = dp[i-1][j-1] + 1
}
if dp[i][j] > res {
res = dp[i][j]
}
}
}
return res
}
// 滚动数组
func findLength(nums1 []int, nums2 []int) int {
n, m, res := len(nums1), len(nums2), 0
dp := make([]int, m+1)
for i := 1; i <= n; i++ {
for j := m; j >= 1; j-- {
if nums1[i-1] == nums2[j-1] {
dp[j] = dp[j-1] + 1
} else {
dp[j] = 0 // 注意这里不相等要赋值为0,供下一层使用
}
res = max(res, dp[j])
}
}
return res
}
func max(a, b int) int {
if a > b {
return a
}
return b
}