1423 可獲得的最大點數(滑動窗口)

1. 問題描述:

幾張卡牌 排成一行,每張卡牌都有一個對應的點數。點數由整數數組 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

2. 思路分析:

① 一開始的時候想到使用dfs來做,但是看到數組長度在10的五次方左右果斷放棄了,因爲它可能後面的測試數據非常大所以肯定會超時的,在領釦的題解中發現了可以使用逆向思維來解決,因爲考慮到每一次都是從頭或者是尾來拿取的,所以假如最後拿取的k張牌中和是最大的,那麼剩下來的連續的子數組中的總和肯定是最小的,我們可以將其轉化爲最小連續子數組問題的求解即可

② 求解最小連續子數組的總和我們可以使用滑動窗口的思路來求解,我們可以先求解出前len - k個數字的總和,這個總和用來表示一開始的最小連續子數組的總和,然後進行對當前最小連續子數組的範圍進行移動,左右邊界都向右進行移動,也即表示整個窗口向右移動一位,可以使用具體的例子來確定窗口的最後的左邊界的值

3. 代碼如下:

class Solution {
    public int maxScore(int[] cardPoints, int k) {
        /*計算出數組的總和*/
        int len = cardPoints.length;
        int lastsum = 0;
        for (int i = 0; i < len - k; ++i){
            lastsum += cardPoints[i];
        }
        int totalsum = lastsum;
        for (int i = len - k; i < len; ++i){
            totalsum += cardPoints[i];
        }
        if (len == k) return totalsum;
        int res = totalsum - lastsum, l = 0, r = len - k - 1;
        /*注意是小於等於這個可以使用具體的例子來得到邊界問題*/
        while(l - k < 0){
            /*需要注意其中運算的順序*/
            lastsum -= cardPoints[l];
            ++l;
            ++r;
            lastsum += cardPoints[r];
            res = Math.max(res, totalsum - lastsum);
        }
        return res;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章