Description
給定一個整數陣列
cardPoints和整數k。每次只能從陣列的最左或最右邊取一張卡牌,共取k張。回傳能獲得的最大點數。
Example:
Input: cardPoints = [1,2,3,4,5,6,1], k = 3 Output: 12
Intuition#
取左右共 k 張 = 總和減去中間連續 n-k 張的最小和。
- 從左邊取
i張、右邊取k-i張,等價於留下中間n-k張連續子陣列 - 問題轉化為:找長度為
n-k的子陣列使其和最小 - 用滑動視窗找最小和
Approaches#
1: 前綴和枚舉#
- 概念: 預計算左右前綴和,枚舉左邊取 0~k 張的所有組合。
- 時間複雜度:
O(k) - 空間複雜度:
O(k)
class Solution {
fun maxScore(cardPoints: IntArray, k: Int): Int {
val n = cardPoints.size
val leftSum = IntArray(k + 1)
for (i in 0 until k) leftSum[i + 1] = leftSum[i] + cardPoints[i]
var result = 0
var rightSum = 0
for (i in 0..k) {
// 左邊取 k-i 張,右邊取 i 張
result = maxOf(result, leftSum[k - i] + rightSum)
if (i < k) rightSum += cardPoints[n - 1 - i]
}
return result
}
}⭐2: 滑動視窗#
- 概念: 找長度為
n-k的子陣列最小和,答案 = 總和 - 最小窗口和。 - 時間複雜度:
O(n) - 空間複雜度:
O(1)
class Solution {
fun maxScore(cardPoints: IntArray, k: Int): Int {
val n = cardPoints.size
val windowSize = n - k
val totalSum = cardPoints.sum()
var windowSum = 0
for (i in 0 until windowSize) windowSum += cardPoints[i]
var minWindowSum = windowSum
for (i in windowSize until n) {
windowSum += cardPoints[i] - cardPoints[i - windowSize]
minWindowSum = minOf(minWindowSum, windowSum)
}
return totalSum - minWindowSum
}
}🔑 Takeaways#
- Pattern: 反向思維 — 取兩端等於留中間,轉化為滑動視窗找最小
- 關鍵技巧: 「從兩端取 k 個」的問題可轉化為「留中間 n-k 個」,用滑動視窗解決