1. 程式人生 > 其它 >leetcode1423. 可獲得的最大點數,逆向思維+滑動視窗

leetcode1423. 可獲得的最大點數,逆向思維+滑動視窗

技術標籤:演算法刷題python演算法leetcode

考研人資訊庫

此公眾號會發表計算機考研(初複試資訊)、夏令營等資料,方便考研人對資訊的獲取,節約自身查詢資料的時間,回覆408,可獲得資料結構、作業系統、計算機網路、計算機組成原理全科資料


題目描述

幾張卡牌 排成一行,每張卡牌都有一個對應的點數。點數由整數陣列 cardPoints 給出。

每次行動,你可以從行的開頭或者末尾拿一張卡牌,最終你必須正好拿 k 張卡牌。

你的點數就是你拿到手中的所有卡牌的點數之和。

給你一個整數陣列 cardPoints 和整數 k,請你返回可以獲得的最大點數。

示例 1:

輸入:cardPoints = [1,2,3,4,5,6,1], k = 3

輸出:12
解釋:第一次行動,不管拿哪張牌,你的點數總是 1 。但是,先拿最右邊的卡牌將會最大化你的可獲得點數。最優策略是拿右邊的三張牌,最終點數為 1 + 6 + 5 = 12 。

示例 2:

輸入:cardPoints = [2,2,2], k = 2
輸出:4
解釋:無論你拿起哪兩張卡牌,可獲得的點數總是 4 。

示例 3:

輸入:cardPoints = [9,7,7,9,7,7,9], k = 7
輸出:55
解釋:你必須拿起所有卡牌,可以獲得的點數為所有卡牌的點數之和。

示例 4:

輸入:cardPoints = [1,1000,1], k = 1
輸出:1
解釋:你無法拿到中間那張卡牌,所以可以獲得的最大點數為 1 。

示例 5:

輸入:cardPoints = [1,79,80,1,1,1,200,1], k = 3
輸出:202

提示:

1 <= cardPoints.length <= 10^5
1 <= cardPoints[i] <= 10^4
1 <= k <= cardPoints.length

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/maximum-points-you-can-obtain-from-cards

開始想到的是模擬,使用雙指標進行比較,加上大的一方,指標移動,若大小相等,記錄現在指標位置,兩邊指標同時移動,直到大的一方出現或者已經滿足k的長度

最佳解法就是滑動視窗,題目指明拿牌只能從左右拿,所以說左右拿的牌是連續的,假設左邊拿x張,則右邊拿了k-x張,所以答案就是求x張+k-x張的最大值,那麼最大值怎麼求呢,巧妙的方法是求出cardPoints 整個和減去中間的牌的和最小值,也就是逆向思維,將最大值問題轉換成最小值問題,可直接使用滑動視窗

Python3

class Solution:
    def maxScore(self, cardPoints: List[int], k: int) -> int:
        n = len(cardPoints)
        # 滑動視窗大小為 n-k
        windowSize = n - k
        # 選前 n-k 個作為初始值
        s = sum(cardPoints[:windowSize])
        minSum = s
        for i in range(1, n-windowSize+1):
            # 滑動視窗每向右移動一格,增加從右側進入視窗的元素值,並減少從左側離開視窗的元素值
            s += cardPoints[i+windowSize-1] - cardPoints[i - 1]
            minSum = min(minSum, s)
        return sum(cardPoints) - minSum