【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. 解码方法

目录
相关文章
|
算法 Go
🚀 力扣热题 78:子集(详细解析)
✅ 回溯法:经典通用模板,逻辑清晰易扩展。 ✅ 二进制法:简洁高效,适合面试快速写出解法。
562 30
|
索引
Leetcode第三十三题(搜索旋转排序数组)
这篇文章介绍了解决LeetCode第33题“搜索旋转排序数组”的方法,该问题要求在旋转过的升序数组中找到给定目标值的索引,如果存在则返回索引,否则返回-1,文章提供了一个时间复杂度为O(logn)的二分搜索算法实现。
302 0
Leetcode第三十三题(搜索旋转排序数组)
|
算法 C++
Leetcode第53题(最大子数组和)
这篇文章介绍了LeetCode第53题“最大子数组和”的动态规划解法,提供了详细的状态转移方程和C++代码实现,并讨论了其他算法如贪心、分治、改进动态规划和分块累计法。
370 0
|
编译器 Go
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
9月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
428 2
|
11月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
646 1
|
开发框架 JSON 中间件
Go语言Web开发框架实践:路由、中间件、参数校验
Gin框架以其极简风格、强大路由管理、灵活中间件机制及参数绑定校验系统著称。本文详解其核心功能:1) 路由管理,支持分组与路径参数;2) 中间件机制,实现全局与局部控制;3) 参数绑定,涵盖多种来源;4) 结构体绑定与字段校验,确保数据合法性;5) 自定义校验器扩展功能;6) 统一错误处理提升用户体验。Gin以清晰模块化、流程可控及自动化校验等优势,成为开发者的优选工具。
|
11月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
645 0
|
11月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
469 0