Maximum Points You Can Obtain from Cards

There are several cards arranged in a row, and each card has an associated number of points The points are given in the integer array cardPoints.

In one step, you can take one card from the beginning or from the end of the row. You have to take exactly k cards.

Your score is the sum of the points of the cards you have taken.

Given the integer array cardPoints and the integer k, return the maximum score you can obtain.

Example 1:

Input: cardPoints = [1,2,3,4,5,6,1], k = 3
Output: 12
Explanation: After the first step, your score will always be 1. However, choosing the rightmost card first will maximize your total score. The optimal strategy is to take the three cards on the right, giving a final score of 1 + 6 + 5 = 12.

Example 2:

Input: cardPoints = [2,2,2], k = 2
Output: 4
Explanation: Regardless of which two cards you take, your score will always be 4.

Example 3:

Input: cardPoints = [9,7,7,9,7,7,9], k = 7
Output: 55
Explanation: You have to take all the cards. Your score is the sum of points of all cards.

Example 4:

Input: cardPoints = [1,1000,1], k = 1
Output: 1
Explanation: You cannot take the card in the middle. Your best score is 1. 

Example 5:

Input: cardPoints = [1,79,80,1,1,1,200,1], k = 3
Output: 202

Constraints:

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

思路:用記憶化搜索dp來做,O(N^2) ,不能通過;注意base case是k ==1, Math.max(cardPoints[start], cardPoints[end]);

class Solution {
    
    public int maxScore(int[] cardPoints, int k) {
        int n = cardPoints.length;
        Integer[][] dp = new Integer[n][n];
        return dfs(cardPoints, 0, n - 1, k, dp);
    }
    
    private int dfs(int[] cardPoints, int start, int end, int k, Integer[][] dp) {
        if(start > end) {
            return 0;
        }
        if(dp[start][end] != null) {
            return dp[start][end];
        }
        if(k == 1) {
            return Math.max(cardPoints[start], cardPoints[end]);
        }
         
        int res = 0;
        res =  Math.max(cardPoints[start] + dfs(cardPoints, start + 1, end, k-1, dp),
                        cardPoints[end] + dfs(cardPoints, start, end - 1, k-1, dp));
        dp[start][end] = res;
        return dp[start][end];
    }
}

 思路2:這個取值是頭跟尾巴,那麼可以發現沒有取走的數,是個連續的區間,而且是個滑動窗口;逆向思維;

我求得totalsum之後,可以去掉沒有取走的區間的sum,就是我取的sum;沒有取走的sum,可以由滑動窗口求得;O(N);

class Solution {
    public int maxScore(int[] A, int k) {
        int n = A.length;
        int totalsum = 0;
        for(int i : A) {
            totalsum += i;
        }
        if(k == n) return totalsum;
        
        int j = 0;
        int notPickSum = 0;
        int res = 0;
        int count = 0;
        for(int i = 0; i < n; i++) {
            // move j;
            while(j < n && count <= n - k) {
                if(count == n - k) {
                    break;
                }
                notPickSum += A[j];
                count++;
                j++;
            }
            
            // update res;
            if(count == n - k) {
                res = Math.max(res, totalsum - notPickSum);
            }
           
            // move i;
            notPickSum -= A[i];
            count--;
        }
        return res;
    }
}

另外一種寫法:加上前面的值,減去後面的值;

class Solution {
    public int maxScore(int[] A, int k) {
        int n = A.length;
        int totalsum = 0;
        for(int i : A) {
            totalsum += i;
        }
        
        int notPickSum = 0;
        for(int i = 0; i < n - k; i++) {
            notPickSum += A[i];
        }
        
        int res = totalsum - notPickSum;
        for(int i = n - k; i < n; i++) {
            notPickSum = notPickSum + A[i] - A[i - (n - k)]; // 注意window的距離是n - k,不是k
            res = Math.max(res, totalsum - notPickSum);
        }
        return res;
    }
}

 

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