文巾解题 679. 24 点游戏

1 题目描述

2 解题思路

2.1 遍历所有可能情况

我们先找出四张牌所有可能的排列组合。

然后对于每一种排列组合,我们先提出排列组合中最前面的两个数。然后对这两个数进行加\减\乘\除操作。将结果放入我们当前考虑的排列组合中。

此时排列组合中有三个元素:原来的后两个元素。和前两个元素进行数学计算后的结果。

慢的操作是对这三个数组成的序列,再求它们 的排列组合。但实际上后两个数的顺序我们是可以固定的。也就是说,如果我们接下来提取出来的两个数。有前两个数运算后的结果,那么这个结果可能在运算符的左边,也可能在运算符的右边。这两种情况我们都需要考虑

然后三个数组成的序列,经过上面一部变成了两个数。同第三步的考虑一样。两个操作数哪个在运算符的左边,哪个在右边。我们都需要进行讨论和考虑。

还有一个tips。因为这种方法我们没有排除掉除以0 的情况。为了防止除0报错,进行除法的时候,我们需要对被除数加上一个很小的数值。

class Solution:
    def judgePoint24(self, cards: List[int]) -> bool:

        ret=[]
        for i in cards:
            tmp=copy.deepcopy(cards)
            tmp.remove(i)
            for j in tmp:
                tmp1=copy.deepcopy(tmp)
                tmp1.remove(j)
                for k in tmp1:
                    tmp2=copy.deepcopy(tmp1)
                    tmp2.remove(k)
                    l=tmp2[0]
                    ret.append([i,j,k,l])
#四张牌所有的排列组合
'''
求排列组合的大致思想是:
我们先从四个元素组成的序列中提取一个;
然后从不含这个元素的三元素序列中提取一个;
然后是两个中选一个,最后就是另外的一个
'''



        def judge2(ab,cd):
            #print(ab,cd)
            return(
                (abs(ab+cd-24)<0.001)
                or
                (abs(ab*cd-24)<0.001)
                or
                (abs(ab-cd-24)<0.001)
                or
                (abs(ab/(cd+0.0000001)-24)<0.001)
                or
                (abs(cd-ab-24)<0.001)
                or
                (abs(cd/(ab+0.0000001)-24)<0.001)
            )
#三元序列中提取两个进行计算,得到的结果和序列中剩余的一个,这两个数能否通过某种运算达到24

        def judge3(ab,c,d):
            #print(ab,c,d)
            return( 
                judge2(ab+c,d) 
                or 
                judge2(ab-c,d)
                or
                judge2(ab*c,d)
                or
                judge2(ab/(c+0.0000001),d)
                or
                judge2(c/(ab+0.0000001),d)
                or
                judge2(c-ab,d)
                or
                judge2(ab,c+d)
                or
                judge2(ab,c-d)
                or
                judge2(ab,c*d)
                or
                judge2(ab,c/(d+0.0000001))) 
#四元序列中提取两个进行运算,得到的结果和序列中剩余的两个,这三个数能否通过什么方法使结果到24
           
                    
        def judge4(a,b,c,d):
            return( 
                judge3(a+b,c,d) 
                or 
                judge3(a-b,c,d)
                or
                judge3(a*b,c,d)
                or
                judge3(a/(b+0.0000001),c,d))
#四个数能否通过某些操作使得结果为24


        for i in ret:
            if(judge4(i[0],i[1],i[2],i[3])==True):
                return(True)

        return(False)

2.2 方法2 :递归

class Solution:
    def judgePoint24(self, nums: List[int]) -> bool:
        TARGET = 24
        EPSILON = 1e-6
        ADD, MULTIPLY, SUBTRACT, DIVIDE = 0, 1, 2, 3

        def solve(nums: List[float]) -> bool:
            if len(nums) == 1:
                return abs(nums[0] - TARGET) < EPSILON
#只剩下一个数了,就判断这个数和24之间的差距是否在临界差距以内
#在的话,那么说明可以通过运算得到24

            for i, x in enumerate(nums):
                for j, y in enumerate(nums):
                    if i != j:
#从nums中找不同的两个数(区别于方法2.1的思路)
                        newNums = list()
                        for s, z in enumerate(nums):
                            if s != i and s != j:
                                newNums.append(z)
#找第三个数

                        for k in range(4):
                            if k < 2 and i > j:
                                continue
'''
加和乘运算,而且第一个运算数比第二个大
这说明之前在x等于第二个运算数的时候,x+y 或者x*y已经计算过了
所以不用再次计算,直接继续循环
'''
                            if k == ADD:
                                newNums.append(x + y)
                            elif k == MULTIPLY:
                                newNums.append(x * y)
                            elif k == SUBTRACT:
                                newNums.append(x - y)
                            elif k == DIVIDE:
                                if abs(y) < EPSILON:
                                    continue
                                newNums.append(x / y)
                            if solve(newNums):
                                return True
#如果x,y运算的结果和nums中剩下的两个数组成的三个数可以算出24,那么返回True
                            newNums.pop()
'''
不然的话,在三元素序列中,把当前算的这个达不到24的x,y运算结果pop出来,
然后看下一个操作符算出来的X,Y结果,和nums中剩下的两个元素组成的三元素序列满足不满足条件要求
'''
            return False

        return solve(nums)

2.3 方法3:dfs

class Solution:
    def judgePoint24(self, cards: List[int]) -> bool:

        def dfs(nums):
            if len(nums) == 1:
                return abs(nums[0] - 24) < 0.00001
#序列中只有最后一个数了,进行判断

            for i in range(len(nums)-1):
                for j in range(i+1, len(nums)):
                    x, y = nums[i], nums[j]
#提取两个不一样的数(这里假设x在序列中的排位一定在y前面)
#所以之后考虑减法和除法的时候,需要分别考虑x和y在除/减数和被除/减数的情况

                    rst = nums[:i] + nums[i+1:j] + nums[j+1:]
#x和y元素以外的元素拼成一个序列
                    
                    a = dfs(rst + [x + y])
                    b = dfs(rst + [x - y])
                    c = dfs(rst + [y - x])
                    d = dfs(rst + [x * y])
                    e = (y != 0) and dfs(rst + [x / y])
                    f = (x != 0) and dfs(rst + [y / x])
#将x,y经过不同操作数的结果放到rst中,拼接而成的序列继续进行dfs
                    
                    if a or b or c or d or e or f:
                        return True

            return False
        
        return dfs(cards)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UQI-LIUWJ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值