Week 19 @ 2025 算法周记【最大子数组和 + 括号 + 二叉树】

Week 19 @ 2025 算法周记【最大子数组和 + 括号 + 二叉树】

最大子数组和

LC 53. Maximum Subarray 最大子数组和

https://leetcode.com/problems/maximum-subarray/

动态规划 (Kadane's algorithm)

func maxSubArray(nums []int) int { dp := make([]int, len(nums)) // 以 i 结尾的最大 sum dp[0] = nums[0] for i := 1; i < len(nums); i++ { dp[i] = max(nums[i], dp[i-1] + nums[i]) } return slices.Max(dp) }

滑动窗口

func maxSubArray(nums []int) int { left, right := 0, 0 maxSum := nums[0] windowSum := 0 for right < len(nums) { windowSum += nums[right] right++ maxSum = max(maxSum, windowSum) for left < right && windowSum < 0 { windowSum -= nums[left] left++ } } return maxSum }

分治(线段树)

TODO https://leetcode.cn/problems/maximum-subarray/solutions/228009/zui-da-zi-xu-he-by-leetcode-solution/

LC 918. Maximum Sum Circular Subarray 环形子数组的最大和

https://leetcode.com/problems/maximum-sum-circular-subarray/description/

分开考虑

func maxSubarraySumCircular(nums []int) int { n := len(nums) maxSum := nums[0] pre := nums[0] preSum := nums[0] preSumMax := make([]int, n) preSumMax[0] = preSum for i := 1; i < len(nums); i++ { pre = nums[i] + max(pre, 0) maxSum = max(maxSum, pre) preSum += nums[i] preSumMax[i] = max(preSum, preSumMax[i-1]) } postSum := 0 for i := n-1; i > 0; i-- { postSum += nums[i] maxSum = max(maxSum, postSum + max(preSumMax[i-1], 0)) } return maxSum }

单调队列

func maxSubarraySumCircular(nums []int) int { n := len(nums) preSum := make([]int, 2*n) preSum[0] = nums[0] for i := 1; i < n; i++ { preSum[i] = preSum[i-1] + nums[i] } for i, num := range nums { preSum[n+i] = preSum[n+i-1] + num } maxSum := nums[0] window := NewMonotonicQueue() window.Push(0) for i := 0; i < len(preSum); i++ { maxSum = max(maxSum, preSum[i] - window.Min()) window.Push(preSum[i]) if window.Size() > n { window.Pop() } } return maxSum } type MonotonicQueue struct { q []int maxq []int minq []int } func NewMonotonicQueue() *MonotonicQueue { return &MonotonicQueue{ q: []int{}, maxq: []int{}, minq: []int{}, } } func (q *MonotonicQueue) Push(elem int) { q.q = append(q.q, elem) // maxq: 5 3 3 1 for len(q.maxq) > 0 && q.maxq[len(q.maxq)-1] < elem { q.maxq = q.maxq[:len(q.maxq)-1] } q.maxq = append(q.maxq, elem) // minq: 1 3 3 5 for len(q.minq) > 0 && q.minq[len(q.minq)-1] > elem { q.minq = q.minq[:len(q.minq)-1] } q.minq = append(q.minq, elem) } func (q *MonotonicQueue) Pop() int { elem := q.q[0] q.q = q.q[1:] if q.maxq[0] == elem { q.maxq = q.maxq[1:] } if q.minq[0] == elem { q.minq = q.minq[1:] } return elem } func (q *MonotonicQueue) Max() int { return q.maxq[0] } func (q *MonotonicQueue) Min() int { return q.minq[0] } func (q *MonotonicQueue) Size() int { return len(q.q) } func (q *MonotonicQueue) IsEmpty() bool { return len(q.q) == 0 }

括号类问题

LC 921. Minimum Add to Make Parentheses Valid 使括号有效的最少添加

https://leetcode.com/problems/minimum-add-to-make-parentheses-valid/description/

func minAddToMakeValid(s string) (count int) { lefts := 0 for _, b := range s { if b == '(' { lefts++ } else { if lefts > 0 { lefts-- } else { count++ } } } count += lefts return }

LC 1541. Minimum Insertions to Balance a Parentheses String 平衡括号字符串的最少插入次数

https://leetcode.com/problems/minimum-insertions-to-balance-a-parentheses-string/description/

func minInsertions(s string) int { lefts := 0 count := 0 i := 0 for i < len(s) { if s[i] == '(' { lefts++ i++ } else { if i+1 < len(s) && s[i+1] == ')' { // 找到 )) if lefts == 0 { count++ } else { lefts-- } i += 2 } else { // 只找到一个 ) if lefts == 0 { count += 2 // 需要补一个 ( 和一个 ) } else { count++ lefts-- } i++ } } } count += lefts * 2 // 每一个 ( 需要补两个 )) return count }

LC 104. Maximum Depth of Binary Tree 二叉树的最大深度

https://leetcode.com/problems/maximum-depth-of-binary-tree/

/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ func maxDepth(root *TreeNode) int { if root == nil { return 0 } return 1 + max(maxDepth(root.Left), maxDepth(root.Right)) }