在问 · 算法题解

679. 24 点游戏

题目描述

输入长度为 4 的整数数组 cards,每张牌上是 1 到 9 之间的数字。

用这 4 个数各一次,配合加、减、乘、除四种运算和括号组成一个算式,判断能否让算式的值等于 24。

规则如下:除法按实数计算,不取整,例如 4 / (1 - 2 / 3) = 12;每个运算符都必须连接两个运算数,不能把减号当作负号用在单个数前面;不能把几张牌上的数字拼成一个多位数,例如用 1 和 2 拼成 12。

能得到 24 返回 true,否则返回 false。

示例 1
输入:cards = [4,1,8,7]
输出:true

解释:(8 - 4) * (7 - 1) = 24。

示例 2
输入:cards = [1,2,1,2]
输出:false

解释:这四个数怎样组合都得不到 24。

数据范围

  • cards.length == 4
  • 1 <= cards[i] <= 9

解题思路

每次从当前数字里任选两个(有序),用一种运算把它们合成一个新数,再放回剩下的数字中,数字个数减一。递归到只剩一个数时,判断它是否等于 24。因为选的是有序对,a - b 与 b - a、a / b 与 b / a 都会被枚举到,括号的所有结合方式也自然被覆盖。实数除法有精度误差,比较时用 1e-6 容差,除数为 0 时跳过除法。

为什么正确

任何时刻,当前列表中的每个数都是若干张原始牌组成的子表达式的值,并且这些子表达式恰好把 4 张牌各用了一次。

复杂度分析

时间 O(1):4 个数时最多 12*4 * 6*4 * 2*4 种组合;空间 O(1)。

易错点

用整数除法或用 == 24 直接比较浮点数都会出错,例如 8 / (3 - 8 / 3) = 24 需要实数除法和容差比较。还要记得除数为 0 时跳过除法。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def judgePoint24(self, cards: List[int]) -> bool:
        def dfs(nums):
            if len(nums) == 1:
                return abs(nums[0] - 24) < 1e-6
            for i in range(len(nums)):
                for j in range(len(nums)):
                    if i == j:
                        continue
                    rest = [nums[k] for k in range(len(nums)) if k != i and k != j]
                    a, b = nums[i], nums[j]
                    cands = [a + b, a - b, a * b]
                    if abs(b) > 1e-6:
                        cands.append(a / b)
                    for c in cands:
                        if dfs(rest + [c]):
                            return True
            return False

        return dfs(cards)

载入编辑器,自己跑一遍 →

回溯 专题的其他题目

查看 回溯 全部题目 →