题目描述
你的初始能量为 P
,初始分数为 0
,只有一包令牌。
令牌的值为 token[i]
,每个令牌最多只能使用一次,可能的两种使用方法如下:
- 如果你至少有
token[i]
点能量,可以将令牌置为正面朝上,失去token[i]
点能量,并得到1
分。 - 如果我们至少有
1
分,可以将令牌置为反面朝上,获得token[i]
点能量,并失去1
分。
在使用任意数量的令牌后,返回我们可以得到的最大分数。
示例 1:
输入:tokens = [100], P = 50 输出:0
示例 2:
输入:tokens = [100,200], P = 150 输出:1
示例 3:
输入:tokens = [100,200,300,400], P = 200 输出:2
提示:
tokens.length <= 1000
0 <= tokens[i] < 10000
0 <= P < 10000
解题思路
个人感觉题目容易给人误解,
- 如果我们至少有
1
分,可以将令牌置为反面朝上,获得token[i]
点能量,并失去1
分。
本人错误的理解成正面朝上的然后再消耗一点得分使反面朝上,然后看评论区大佬的解答才明白不是这么回事。其实应该说是消耗一点能量获得一张令牌的tokens[i]值。然后可以使用双指针和贪心解答,先对所有令牌排序,用能量尽可能多的反转牌面值小的令牌,消耗一点得分去获得尽可能多的能量。用i指向要消耗最小能量获得得分的卡牌索引,j指向消耗一点得分获得最大能量的卡牌,外层循环控制条件是当前P大于等于tokens[i]表示可以反转令牌获得一分,或则可能至少还有一张没有反转的令牌并且scores大于0表示可以消耗一分获得能量。
void qsort(vector<int>& tokens,int l,int r){
if(l < r){
int i = l,j = r;
int tmp = tokens[i];
while(i<j){
while(i<j && tokens[j] >= tmp) j--;
tokens[i] = tokens[j];
while(i<j && tokens[i] < tmp) i++;
tokens[j] = tokens[i];
}
tokens[i] = tmp;
qsort(tokens,l,i-1);
qsort(tokens,i+1,r);
}
}
int bagOfTokensScore(vector<int>& tokens, int P) {
int len = tokens.size();
qsort(tokens,0,len-1);
int i = 0,j=len-1,scores = 0;
while((i<=j && P>=tokens[i]) || (i<j && scores > 0)){
while(i<=j && P>=tokens[i]){
P-=tokens[i++];
scores++;
}
if(i>=j) break;
else if(scores > 0){
P+=tokens[j--];
scores--;
}
}
return scores;
}