You are given an integer array cards
of length 4
. You have four cards, each containing a number in the range [1, 9]
. You should arrange the numbers on these cards in a mathematical expression using the operators ['+', '-', '*', '/']
and the parentheses '('
and ')'
to get the value 24.
You are restricted with the following rules:
'/'
represents real division, not integer division.
4 / (1 - 2 / 3) = 4 / (1 / 3) = 12
.'-'
as a unary operator.
cards = [1, 1, 1, 1]
, the expression "-1 - 1 - 1 - 1"
is not allowed.cards = [1, 2, 1, 2]
, the expression "12 + 12"
is not valid.Return true
if you can get such expression that evaluates to 24
, and false
otherwise.
Example 1:
Input: cards = [4,1,8,7] Output: true Explanation: (8-4) * (7-1) = 24
Example 2:
Input: cards = [1,2,1,2] Output: false
Constraints:
cards.length == 4
1 <= cards[i] <= 9
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 24 Game involves using four numbers and basic arithmetic operations to reach the number 24. A brute force strategy means trying every possible combination of numbers, operations, and orders until a solution is found.
Here's how the algorithm would work step-by-step:
def is_24_game_solvable(numbers):
import itertools
# Generate all permutations of the input numbers
for number_permutation in itertools.permutations(numbers):
first_number = number_permutation[0]
second_number = number_permutation[1]
third_number = number_permutation[2]
fourth_number = number_permutation[3]
# Iterate through all possible operations
operations = ['+', '-', '*', '/']
for first_operation in operations:
for second_operation in operations:
for third_operation in operations:
# Apply operations in different orders
try:
# Order 1: ((a op b) op c) op d
result1 = eval('((' + str(first_number) + first_operation + str(second_number) + ')' + \
second_operation + str(third_number) + ')' + third_operation + str(fourth_number))
# Order 2: (a op b) op (c op d)
result2 = eval('(' + str(first_number) + first_operation + str(second_number) + ')' + \
second_operation + '(' + str(third_number) + third_operation + str(fourth_number) + ')')
# Order 3: (a op (b op c)) op d
result3 = eval('(' + str(first_number) + first_operation + '(' + str(second_number) + \
second_operation + str(third_number) + '))' + third_operation + str(fourth_number))
# Order 4: a op ((b op c) op d)
result4 = eval(str(first_number) + first_operation + '((' + str(second_number) + \
second_operation + str(third_number) + ')' + third_operation + str(fourth_number) + ')')
# Order 5: a op (b op (c op d))
result5 = eval(str(first_number) + first_operation + '(' + str(second_number) + \
second_operation + '(' + str(third_number) + third_operation + str(fourth_number) + '))')
if abs(result1 - 24) < 1e-6 or abs(result2 - 24) < 1e-6 or \
abs(result3 - 24) < 1e-6 or abs(result4 - 24) < 1e-6 or \
abs(result5 - 24) < 1e-6:
return True
except ZeroDivisionError:
# Division by zero is not a valid operation
continue
return False
The goal is to use basic arithmetic operations (+, -, *, /) on four given numbers to obtain 24. The clever approach breaks down the problem by systematically combining numbers and using recursion to explore possible solutions efficiently, avoiding redundant calculations. This ensures all combinations are tested while keeping the process manageable.
Here's how the algorithm would work step-by-step:
def is_24_game_solvable(input_numbers):
target_value = 24
epsilon = 0.001
def solve_recursively(current_numbers):
# Base case: if only one number remains
if len(current_numbers) == 1:
return abs(current_numbers[0] - target_value) < epsilon
# Iterate through all pairs of numbers
for i in range(len(current_numbers)):
for j in range(i + 1, len(current_numbers)):
first_number = current_numbers[i]
second_number = current_numbers[j]
# Create a new list without the selected numbers
remaining_numbers = [current_numbers[k] for k in range(len(current_numbers)) if k != i and k != j]
# Perform all possible operations
possible_results = [
first_number + second_number,
first_number - second_number,
second_number - first_number,
first_number * second_number,
]
#Avoid division by zero.
if second_number != 0:
possible_results.append(first_number / second_number)
if first_number != 0:
possible_results.append(second_number / first_number)
# Recursively call solve with the new numbers
for result in possible_results:
new_numbers = remaining_numbers + [result]
if solve_recursively(new_numbers):
return True
return False
# Begin recursive solution process.
return solve_recursively(input_numbers)
Case | How to Handle |
---|---|
Input array is null or empty | Return false immediately as no calculation can be performed with no numbers. |
Input array contains less than 4 numbers | Return false as the 24 game requires exactly four numbers. |
Input array contains numbers that are not integers or are outside a reasonable range (e.g., very large numbers leading to overflow) | Handle invalid input by returning false or throwing an exception, and limit input number size to avoid integer overflow. |
Floating point precision errors prevent reaching exactly 24 | Compare the final result to 24 with a small tolerance (e.g., absolute difference less than 1e-6). |
All input numbers are the same (e.g., [6, 6, 6, 6]) | The algorithm should explore all permutations and combinations of operations, and potentially find a valid solution or return false if none exist. |
No solution exists for the given input numbers | The algorithm should exhaust all possible combinations and operations and return false if no combination results in 24 within the allowed tolerance. |
Division by zero can occur during calculation | Check for division by zero before performing the division operation and skip or handle the case appropriately to avoid errors. |
Integer overflow during intermediate calculations | Use a larger data type (e.g., long) for intermediate calculations or check for potential overflow before performing the operation. |