You are given an array of tokens, tokens
, where each tokens[i]
represents the value of the i-th token. You also have an initial power, power
, and a score, which starts at 0. Your goal is to maximize the score by strategically playing the tokens. You can play each token only once, either face-up or face-down.
tokens[i]
, you can play token i, losing tokens[i]
power and gaining 1 score.tokens[i]
power and losing 1 score.Return the maximum possible score you can achieve after playing any number of tokens.
Example 1:
tokens = [100], power = 50
Output: 0
Example 2:
tokens = [200, 100], power = 150
Output: 1
Example 3:
tokens = [100, 200, 300, 400], power = 200
Output: 2
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. |