lc679.24点游戏

 

题目链接

这个题考虑用dfs或回溯法。一共有4个数和3个运算操作,因此可能性非常有限。一共有多少种可能性呢?首先从4个数字中有序地选出2个数字,共有4x3=12种选法,并选择加减乘除4种运算之一,得到的结果取代选出的两个数字,剩下3个数字。然后在剩下的3个数字中有序地选出2个数字,共有3x2=6种选法,并选择4种运算操作之一,用得到的结果取代选出的两个数字,剩下2个数字。最后剩下2个数字,有2种不同的顺序,并选择4中运算操作之一。因此,一共有12x4x6x4x2x4=9216种不同的可能性。

可以通过回溯的方法遍历所有不同的可能性,具体做法是,使用一个列表存储目前的全部数字,每次从列表中选出2个数字,再选择一种操作,用计算得到的结果取代选出的2个数字,这样列表中的数字就减少了1。重复以上步骤直到列表中只剩下1一个数字,这个数字就是一种可能性的结果,如果结果等于24,则说明可以通过运算得到24否则就不行。

实现时有一些细节需要注意。首先除法要使用实数除法,因此结果为浮点数,列表中存储的数字也都是浮点数。在判断结果是否为24时要考虑精度误差,因此我们用了一个足够小的值epsilon。另外,进行除法运算时除数不能为0,当遇到这种情况时可以直接排除,当然因为列表中存储的是浮点数因此判断除数是否为0时也要考虑精度误差。还有一个可以优化的点,加法和乘法满足交换率因此如果选择的运算操作是加法或乘法,则对于选出的两个数字不用考虑不同的顺序,在遇见第二种顺序时可以不运算而直接跳过。

因为可能的结果是有限的不和N有关因此算法的时间复杂度是O(1),空间复杂度是O(1)。

python:

class Solution:
    def judgePoint24(self, nums: List[int]) -> bool:
        target = 24
        epsilon = 1e-6
        ADD, MULTIPLY, SUBSTRACT, DIVIDE = 0, 1, 2, 3
        
        def solve(nums):
            if not nums:
                return False
            if len(nums) == 1:
                return abs(nums[0] - target) < epsilon
            for i, x in enumerate(nums):
                for j, y in enumerate(nums):
                    if i != j:
                        newNums = list()
                        for k, z in enumerate(nums):
                            if k != i and k != j:
                                newNums.append(z)
                        for k in range(4):
                            if k < 2 and i > j:
                                continue
                            if k == ADD:
                                newNums.append(x + y)
                            elif k == MULTIPLY:
                                newNums.append(x * y)
                            elif k == SUBSTRACT:
                                newNums.append(x - y)
                            elif k == DIVIDE:
                                if abs(y) < epsilon:
                                    continue
                                newNums.append(x / y)
                            if solve(newNums):
                                return True
                            newNums.pop()
            return False

        return solve(nums)