[LeetCode] 948. Bag of Tokens 令牌包



You have an initial power P, an initial score of 0 points, and a bag of tokens.

Each token can be used at most once, has a value token[i], and has potentially two ways to use it.

  • If we have at least token[i] power, we may play the token face up, losing token[i] power, and gaining 1 point.
  • If we have at least 1 point, we may play the token face down, gaining token[i] power, and losing 1 point.

Return the largest number of points we can have after playing any number of tokens.

Example 1:

Input: tokens = [100], P = 50
Output: 0

Example 2:

Input: tokens = [100,200], P = 150
Output: 1

Example 3:

Input: tokens = [100,200,300,400], P = 200
Output: 2

Note:

  1. tokens.length <= 1000
  2. 0 <= tokens[i] < 10000
  3. 0 <= P < 10000

這道題說是給了一個初始力量值P,然后有一個 tokens 數組,有兩種操作可以選擇,一種是減去 tokens[i] 的力量,得到一分,但是前提是減去后剩余的力量不能為負。另一種是減去一分,得到 tokens[i] 的力量,前提是減去后的分數不能為負,問一頓操作猛如虎后可以得到的最高分數是多少。這道題其實題意不是太容易理解,而且例子也沒給解釋,博主也是讀了好幾遍題目才明白的。比如例子3,開始有 200 的力量,可以先花 100,得到1個積分,此時還剩 100 的力量,但由於剩下的 token 值都太大,沒法換積分了,只能用積分來換力量,既然都是花一個1個積分,肯定是要換最多的力量,於是換來 400 力量,此時總共有 500 的力量,積分還是0,但是一頓操作后,白嫖了 400 的力量,豈不美哉?!這 500 的力量剛好可以換兩個積分,所以最后返回的就是2。通過上述分析,基本上可以知道策略了,從最小的 token 開始,用力量換積分,當力量不夠時,就用基本換最大的力量,如果沒有積分可以換力量,就結束,或者所有的 token 都使用過了,也結束,這就是典型的貪婪算法 Greedy Algorithm,也算對得起其 Medium 的身價。這里先給 tokens 數組排個序,然后使用雙指針i和j,分別指向開頭和末尾,當 i<=j 進行循環,從小的 token 開始查找,只要力量夠,就換成積分,不能換的時候,假如 i>j 或者此時積分為0,則退出;否則用一個積分換最大的力量,參見代碼如下:

解法一:

class Solution {
public:
    int bagOfTokensScore(vector<int>& tokens, int P) {
        int res = 0, cur = 0, n = tokens.size(), i = 0, j = n - 1;
        sort(tokens.begin(), tokens.end());
        while (i <= j) {
            while (i <= j && tokens[i] <= P) {
                P -= tokens[i++];
                res = max(res, ++cur);
            }
            if (i > j || cur == 0) break;
            --cur;
            P += tokens[j--];
        }
        return res;
    }
};

我們也可以換一種寫法,不用 while 套 while,而是換成賞心悅目的 if ... else 語句,其實也沒差啦,參見代碼如下:


解法二:

class Solution {
public:
    int bagOfTokensScore(vector<int>& tokens, int P) {
        int res = 0, cur = 0, n = tokens.size(), i = 0, j = n - 1;
        sort(tokens.begin(), tokens.end());
        while (i <= j) {
            if (P >= tokens[i]) {
                P -= tokens[i++];
                res = max(res, ++cur);
            } else if (cur > 0) {
                --cur;
                P += tokens[j--];
            } else {
                break;
            }
        }
        return res;
    }
};

我們也可以使用遞歸來做,使用一個子函數 helper,將i和j當作參數輸入,其實原理跟上的方法一摸一樣,不難理解,參見代碼如下:


解法三:

class Solution {
public:
    int bagOfTokensScore(vector<int>& tokens, int P) {
        sort(tokens.begin(), tokens.end());
        return helper(tokens, P, 0, (int)tokens.size() - 1, 0);
    }
    int helper(vector<int>& tokens, int P, int i, int j, int cur) {
        if (i > j) return cur;
        int res = cur;
        if (tokens[i] <= P) {
            res = max(res, helper(tokens, P - tokens[i], i + 1, j, cur + 1));
        } else if (cur > 0) {
            res = max(res, helper(tokens, P + tokens[j], i, j - 1, cur - 1));
        }
        return res;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/948


參考資料:

https://leetcode.com/problems/bag-of-tokens/

https://leetcode.com/problems/bag-of-tokens/discuss/383249/Java-Solution-With-Explanation

https://leetcode.com/problems/bag-of-tokens/discuss/197696/C%2B%2BJavaPython-Greedy-%2B-Two-Pointers


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM