【LeetCode 热题100】DP 实战进阶:最长递增子序列、乘积最大子数组、分割等和子集(力扣300 / 152/ 416 )(Go语言版)

简介: 本文深入解析三道经典的动态规划问题:**最长递增子序列(LIS)**、**乘积最大子数组** 和 **分割等和子集**。 - **300. LIS** 通过 `dp[i]` 表示以第 `i` 个元素结尾的最长递增子序列长度,支持 O(n²) 动态规划与 O(n log n) 的二分优化。 - **152. 乘积最大子数组** 利用正负数特性,同时维护最大值与最小值的状态转移方程。 - **416. 分割等和子集** 转化为 0-1 背包问题,通过布尔型 DP 实现子集和判断。 总结对比了三题的状态定义与解法技巧,并延伸至相关变种问题,助你掌握动态规划的核心思想与灵活应用!

🧠 DP 实战进阶:最长递增子序列、乘积最大子数组、分割等和子集(LeetCode 300 / 152 / 416)

在动态规划的学习路径中,这三道题常被视作进阶经典,它们分别对应不同的状态定义与优化思路:

  • 📈 300. 最长递增子序列(LIS):子序列类动态规划
  • ✖️ 152. 乘积最大子数组:带正负号波动的区间 DP
  • 🎯 416. 分割等和子集:0-1 背包问题的变种

📈 一、300. 最长递增子序列

📌 题目描述

给你一个整数数组 nums,返回其中最长严格递增子序列的长度。


💡 解题思路(一):动态规划

状态定义:

  • dp[i] 表示以 nums[i] 结尾的最长递增子序列长度。

状态转移方程:

for j := 0; j < i; j++ {
   
    if nums[i] > nums[j] {
   
        dp[i] = max(dp[i], dp[j] + 1)
    }
}

时间复杂度:O(n²)


✅ Go 实现

func lengthOfLIS(nums []int) int {
   
    n := len(nums)
    dp := make([]int, n)
    for i := range dp {
   
        dp[i] = 1
    }

    maxLen := 1
    for i := 1; i < n; i++ {
   
        for j := 0; j < i; j++ {
   
            if nums[i] > nums[j] {
   
                dp[i] = max(dp[i], dp[j]+1)
            }
        }
        maxLen = max(maxLen, dp[i])
    }
    return maxLen
}

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

💡 解法(二):二分优化(贪心 + 二分)

维护一个数组 tailstails[i] 表示长度为 i+1 的递增子序列中末尾最小的值。

时间复杂度:O(n log n)


✖️ 二、152. 乘积最大子数组

📌 题目描述

给你一个整数数组 nums,找出一个乘积最大的连续子数组,返回该乘积。


💡 解题思路

因为负负得正的存在,我们需要同时记录当前的最大值和最小值:

  • dpMax[i]:以 i 结尾的最大乘积
  • dpMin[i]:以 i 结尾的最小乘积

状态转移:

dpMax[i] = max(nums[i], nums[i]*dpMax[i-1], nums[i]*dpMin[i-1])
dpMin[i] = min(nums[i], nums[i]*dpMax[i-1], nums[i]*dpMin[i-1])

✅ Go 实现(空间优化)

func maxProduct(nums []int) int {
   
    maxVal, minVal := nums[0], nums[0]
    res := nums[0]

    for i := 1; i < len(nums); i++ {
   
        tempMax := maxVal
        maxVal = max(nums[i], max(nums[i]*maxVal, nums[i]*minVal))
        minVal = min(nums[i], min(nums[i]*tempMax, nums[i]*minVal))
        res = max(res, maxVal)
    }
    return res
}

🎯 三、416. 分割等和子集

📌 题目描述

给定一个只包含正整数的非空数组,判断能否将其分成两个子集,使得两个子集的和相等


💡 解题思路

转换为 0-1 背包问题

  • 目标是找到一个子集,使其和为 sum/2
  • 状态定义:dp[j] 表示是否存在和为 j 的子集;
  • 状态转移:
dp[j] = dp[j] || dp[j - num]

✅ Go 实现

func canPartition(nums []int) bool {
   
    total := 0
    for _, num := range nums {
   
        total += num
    }
    if total%2 != 0 {
   
        return false
    }
    target := total / 2
    dp := make([]bool, target+1)
    dp[0] = true

    for _, num := range nums {
   
        for j := target; j >= num; j-- {
   
            dp[j] = dp[j] || dp[j-num]
        }
    }
    return dp[target]
}

🔚 总结与对比

题目 类型 状态定义 难点与技巧
300. 最长递增子序列 子序列 DP dp[i] 为以 i 结尾 LIS 长度 可二分优化
152. 乘积最大子数组 区间 DP 同时维护最大最小 处理正负数乘积
416. 分割等和子集 0-1 背包 dp[j] 为是否能组成 j 典型集合和划分

📘 写在最后

这三道题展示了动态规划在处理不同问题时的状态建模能力转移逻辑多样性。可以举一反三,比如:

  • LIS 拓展题:673. 最长递增子序列的个数
  • 背包拓展题:494. 目标和
  • 区间动态规划:42. 接雨水、91. 解码方法

目录
相关文章
|
6月前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
10月前
|
Go
【LeetCode 热题100】BFS/DFS 实战:岛屿数量 & 腐烂的橘子(力扣200 / 994 )(Go语言版)
本篇博客详细解析了三道经典的动态规划问题:198. 打家劫舍(线性状态转移)、279. 完全平方数与322. 零钱兑换(完全背包问题)。通过 Go 语言实现,帮助读者掌握动态规划的核心思想及其实战技巧。从状态定义到转移方程,逐步剖析每道题的解法,并总结其异同点,助力解决更复杂的 DP 问题。适合初学者深入理解动态规划的应用场景和优化方法。
309 0
|
6月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
336 2
|
编译器 Go
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
8月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
514 1
|
8月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
541 0
|
8月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
366 0
|
8月前
|
Cloud Native Java 中间件
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
419 0
|
8月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
451 0