You start with an initial power of power
, an initial score of 0
, and a bag of tokens given as an integer array tokens
, where each tokens[i]
denotes the value of tokeni.
Your goal is to maximize the total score by strategically playing these tokens. In one move, you can play an unplayed token in one of the two ways (but not both for the same token):
tokens[i]
, you may play tokeni, losing tokens[i]
power and gaining 1
score.1
, you may play tokeni, gaining tokens[i]
power and losing 1
score.Return the maximum possible score you can achieve after playing any number of tokens.
Example 1:
Input: tokens = [100], power = 50
Output: 0
Explanation: Since your score is 0
initially, you cannot play the token face-down. You also cannot play it face-up since your power (50
) is less than tokens[0]
(100
).
Example 2:
Input: tokens = [200,100], power = 150
Output: 1
Explanation: Play token1 (100
) face-up, reducing your power to 50
and increasing your score to 1
.
There is no need to play token0, since you cannot play it face-up to add to your score. The maximum score achievable is 1
.
Example 3:
Input: tokens = [100,200,300,400], power = 200
Output: 2
Explanation: Play the tokens in this order to get a score of 2
:
100
) face-up, reducing power to 100
and increasing score to 1
.400
) face-down, increasing power to 500
and reducing score to 0
.200
) face-up, reducing power to 300
and increasing score to 1
.300
) face-up, reducing power to 0
and increasing score to 2
.The maximum score achievable is 2
.
Constraints:
0 <= tokens.length <= 1000
0 <= tokens[i], power < 104
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to the 'Bag of Tokens' problem means trying out every possible sequence of actions with the tokens. We essentially explore every possible order of playing tokens face-up or face-down. We aim to find the highest possible score we can achieve.
Here's how the algorithm would work step-by-step:
def bag_of_tokens_brute_force(tokens, power):
maximum_score = 0
def solve(current_power, current_score, remaining_tokens, current_score_list):
nonlocal maximum_score
maximum_score = max(maximum_score, current_score)
if not remaining_tokens:
return
for index in range(len(remaining_tokens)):
token_value = remaining_tokens[index]
new_remaining_tokens = remaining_tokens[:index] + remaining_tokens[index+1:]
# Try playing the token face-up (lose power, gain score)
if current_power >= token_value:
solve(current_power - token_value, current_score + 1, new_remaining_tokens, current_score_list + [current_score + 1])
# Try playing the token face-down (lose score, gain power)
if current_score > 0:
# Explore playing the token face down
solve(current_power + token_value, current_score - 1, new_remaining_tokens, current_score_list + [current_score - 1])
# We explore every possible starting state.
solve(power, 0, tokens, [0])
return maximum_score
The key is to maximize your score by strategically playing the tokens. We want to use the smallest tokens to gain power and the largest tokens to gain points.
Here's how the algorithm would work step-by-step:
def bag_of_tokens_score(tokens, power):
tokens.sort()
left_pointer = 0
right_pointer = len(tokens) - 1
current_score = 0
maximum_score = 0
while left_pointer <= right_pointer:
# Try to increase score if possible
if power >= tokens[left_pointer]:
power -= tokens[left_pointer]
current_score += 1
left_pointer += 1
maximum_score = max(maximum_score, current_score)
# If can't increase score and have score, then use score to increase power
elif current_score > 0:
# Need score to buy power
if left_pointer < right_pointer:
power += tokens[right_pointer]
current_score -= 1
right_pointer -= 1
#if left and right are the same index, it means it is the last token
else:
break
else:
#No more moves possible
break
return maximum_score
Case | How to Handle |
---|---|
Empty tokens array | Return 0 immediately as there are no tokens to play. |
Null tokens array | Throw an IllegalArgumentException or return 0, depending on requirements, to handle null input. |
Single token in the array, initial power is sufficient | Return 1, as we can play the single token face up to gain one point. |
Single token in the array, initial power is insufficient, no points to spend | Return 0 as the token cannot be played in any configuration. |
Single token in the array, initial power is insufficient, but we have one point to spend. | Return 0 as the token can be flipped for the power but the point must already be present. |
All tokens have the same value, and power is less than the token value, and no points to spend | Return 0, as playing any token is impossible without points. |
All tokens have the same value, and power is less than the token value, but we have points to spend | Check that points are being spent correctly and not resulting in negative points. |
Tokens array contains very large integer values that could lead to integer overflow during power calculation | Use a data type with sufficient range (e.g., long) or check for potential overflows during power updates. |