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
The 24 Game problem challenges us to determine if a given set of four cards (numbers 1-9) can be arranged using arithmetic operations (+, -, *, /) and parentheses to equal 24. The solution presented uses Depth-First Search (DFS) to explore all possible combinations of operations and arrangements.
Approach:
The core idea is to recursively explore all possible ways to combine the numbers. The DFS function (dfs
in the code examples) handles this recursion:
Base Case: If there's only one number left (nums.length == 1
), check if it's approximately equal to 24 (allowing for floating-point precision issues). If it is, return true
. Otherwise, return false
.
Recursive Step: Iterate through all pairs of numbers (i
and j
) in the current list nums
. For each pair:
nxt
containing the remaining numbers (excluding nums[i]
and nums[j]
).ops
).nums[i] op nums[j]
).nxt
.dfs(nxt)
. If the recursive call returns true
, it means a solution has been found, so return true
.false
, remove the last element from nxt
(backtrack) and continue to the next operator.Return false
: If no combination leads to 24 after exploring all possibilities, return false
.
Code Structure (Python example):
The Python code efficiently implements this approach:
class Solution:
def judgePoint24(self, cards: List[int]) -> bool:
def dfs(nums: List[float]):
# ... (code as shown previously) ...
ops = ("+", "-", "*", "/")
nums = [float(x) for x in cards]
return dfs(nums)
judgePoint24
function initializes the nums
list with floating-point values of card numbers to handle potential divisions.dfs
function to start the search.Time Complexity Analysis:
The time complexity is dominated by the nested loops within the dfs
function. We have:
Therefore, the overall time complexity is approximately O(n² * 4 * k), where k represents the branching factor in the recursion, and n is constant (4). This is essentially exponential, although practically it explores a manageable search space for four cards.
Space Complexity Analysis:
The space complexity is determined by the recursion depth. In the worst case, the recursion depth is proportional to the number of cards (4). The space used for storing lists like nums
and nxt
is also linear with respect to the number of cards.
Thus, the space complexity is O(n), which is linear, mainly due to the recursive call stack.
The provided code in Java, C++, Go, and TypeScript follows the same logical structure and algorithm, differing only in syntax. The time and space complexity analyses remain consistent across all languages.