Medium草稿★★★★★O(n) 時間 · O(1) 空間
GreedyDynamic ProgrammingArray
Patterns🪙 貪心
尚未複習過

解法已隱藏 — 先讀題目敘述、自己想想看,再點上方按鈕揭曉。

918Maximum Sum Circular SubarrayGreedyMediumGreedy

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

Example:

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

Intuition

TIP

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

Approaches

1. Two Kadane's Passes — O(n) / O(1)
  • Idea: 分別求最大子陣列和、最小子陣列和,答案取兩者中較大的。
  • Time: O(n)
  • Space: 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. Single Pass (as above, most concise) — O(n) / O(1)
  • Idea: 同時執行兩個 Kadane’s(一個求最大、一個求最小),一次遍歷完成。
  • Time: O(n)
  • Space: 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