Description

給定一個環形整數陣列 nums,找出環形子陣列的最大和。環形子陣列表示陣列可以從尾部接回頭部。

Example:

Input: nums = [1,-2,3,-2] Output: 3

Intuition#

最大環形子陣列和 = max(普通最大子陣列和, 總和 - 最小子陣列和)。

  • 情況一:最大子陣列不跨越邊界 → 直接用 Kadane’s 求最大
  • 情況二:最大子陣列跨越邊界 → 等於總和減去中間的最小子陣列
  • 特殊情況:如果所有元素都是負數,最小子陣列 = 全部,此時取最大子陣列

Approaches#

1: 兩次 Kadane’s#

  • 概念: 分別求最大子陣列和、最小子陣列和,答案取兩者中較大的。
  • 時間複雜度: O(n)
  • 空間複雜度: O(1)
class Solution {
    fun maxSubarraySumCircular(nums: IntArray): Int {
        var maxSum = nums[0]; var curMax = 0
        var minSum = nums[0]; var curMin = 0
        var total = 0

        for (num in nums) {
            curMax = maxOf(curMax + num, num)
            maxSum = maxOf(maxSum, curMax)
            curMin = minOf(curMin + num, num)
            minSum = minOf(minSum, curMin)
            total += num
        }

        // 所有元素都是負數時,total - minSum = 0,應取 maxSum
        return if (total == minSum) maxSum else maxOf(maxSum, total - minSum)
    }
}

⭐2: 一次遍歷(同上,最簡潔寫法)#

  • 概念: 同時執行兩個 Kadane’s(一個求最大、一個求最小),一次遍歷完成。
  • 時間複雜度: O(n)
  • 空間複雜度: O(1)
class Solution {
    fun maxSubarraySumCircular(nums: IntArray): Int {
        var totalSum = 0
        var maxSum = Int.MIN_VALUE; var curMax = 0
        var minSum = Int.MAX_VALUE; var curMin = 0

        for (num in nums) {
            totalSum += num
            curMax = maxOf(curMax + num, num)
            maxSum = maxOf(maxSum, curMax)
            curMin = minOf(curMin + num, num)
            minSum = minOf(minSum, curMin)
        }

        return if (maxSum < 0) maxSum else maxOf(maxSum, totalSum - minSum)
    }
}

🔑 Takeaways#

  • Pattern: 環形問題拆分 — 跨越邊界的最大 = 總和 - 不跨越邊界的最小
  • 關鍵技巧: 雙 Kadane’s 同時求最大和最小;全負數情況需特殊處理