题目
你有 4 张写有 1 到 9 数字的牌。你需要判断是否能通过 *,/,+,-,(,) 的运算得到 24。
示例 1:
输入: [4, 1, 8, 7]输出: True解释: (8-4) * (7-1) = 24
示例 2:
输入: [1, 2, 1, 2]
输出: False
注意:
- 除法运算符
/表示实数除法,而不是整数除法。例如 4 / (1 - 2/3) = 12 。 - 每个运算符对两个数进行运算。特别是我们不能用
-作为一元运算符。例如,[1, 1, 1, 1]作为输入时,表达式-1 - 1 - 1 - 1是不允许的。 - 你不能将数字连接在一起。例如,输入为
[1, 2, 1, 2]时,不能写成 12 + 12 。
题解
没有很好的想法,就是纯粹地暴力搜索4个数能计算出的所有结果。
- 首先考虑1个数的情况,就是返回本身
- 对于2个数的情况,搜索所有结果
- 对于3个数的情况:
- 先取出两个数,利用第2步得到所有结果
- 然后将该结果与剩下的一个数合并,继续利用第2步搜索结果
- 重新取两个数,直到遍历所有情况
- 对于4个数的情况:
- 取1个数,对剩下的数用第3步
- 取2个数,对两组数都用第2步
然后为了减少重复计算,我们用字典储存搜索结果,注意由于列表是可变对象,因此不能作为字典的key,需要将其转化为tuple,同时记得保持列表为有序状态。
然后为了减少情况数,我们把字典中的value设为set,这样就能去除重复值。
然后比较坑的一点是,LeetCode 的 Python 解释器中, / 默认是返回整型的,所以还得先把列表浮点化。
发现自己又犯蠢了,编译器选的Python而不是Python3,怪不得经常结果不对。。。
class Solution(object):
def __init__(self):
self.D = dict()
def Search(self, nums):
n = len(nums)
if n == 1:
return nums
tuple_nums = tuple(nums)
if tuple_nums in self.D:
return self.D[tuple_nums]
L = []
for i in range(0, n):
val = nums[i]
A = self.Search(nums[:i]+nums[i+1:])
for s in A:
L.append(s+val)
L.append(s-val)
L.append(s*val)
L.append(val-s)
if val != 0:
L.append(s/val)
if s != 0:
L.append(val/s)
if n == 4:
for i in range(0, n-1):
for j in range(i+1, n):
a, b = nums[i], nums[j]
print(a, b)
A1 = self.Search([a, b])
nums.remove(a)
nums.remove(b)
A2 = self.Search(nums)
nums += [a, b]
nums.sort()
for s1 in A1:
for s2 in A2:
L.append(s1+s2)
L.append(s1-s2)
L.append(s1*s2)
L.append(s2-s1)
if s1 != 0:
L.append(s2/s1)
if s2 != 0:
L.append(s1/s2)
self.D[tuple_nums] = set(L)
return set(L)
def judgePoint24(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
nums.sort()
S=[float(i) for i in nums]
L = self.Search(S)
for i in L:
if abs(i-24)<0.01:
return True
return False
so = Solution()
s = [1,6,6,8]
L1 = so.Search(s)
print(L1)
so.judgePoint24(s)
执行用时:44 ms, 在所有 Python 提交中击败了86.84%的用户 内存消耗:12.9 MB, 在所有 Python 提交中击败了92.11%的用户
居然速度和内存消耗都还控制得挺好,让人吃惊。
官方题解
- 先取2个数,计算可能结果,再把结果和剩下的2个数组合(此时还剩3个数)
- 重复第1步
如此简洁的想法,我居然一时没有想到。
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 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 == SUBTRACT:
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)
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/24-game/solution/24-dian-you-xi-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
他人题解
官方的思路很简单,但代码写得比较冗杂,看到一位大佬的题解,顿时惊为天人。
import functools
import itertools
import math
class Solution:
def judgePoint24(self, nums):
@functools.lru_cache(None)
def helper(nums):
if len(nums) == 1:
return math.isclose(nums[0], 24)
return any(helper((x,)+tuple(rest)) for a, b, *rest in itertools.permutations(nums) for x in {a+b, a-b, a*b, b and a/b})
return helper(tuple(nums))
他人题解2
把式子转换为表达式树,即可不用计算括号。 表达式树中叶子结点为操作数,非叶子结点为运算符。> 则可枚举出4个操作数有5种表达式树:

其中a,b,c,d为操作数,f,g,h为运算符
写成代码,则为:
f(g(h(a,b),c),d)
f(g(a,h(b,c)),d)
f(g(a,b),h(c,d))
f(a,g(h(b,c),d))
f(a,g(b,h(c,d)))
利用Python的Lambda表达式和itertools,即可6行解出答案
class Solution:
def judgePoint24(self, nums: List[int]) -> bool:
op=[lambda x,y:x+y,lambda x,y:x-y,lambda x,y:x*y,lambda x,y:x/y if y!=0 else float('inf')]
for a,b,c,d in itertools.permutations(nums):
for f,g,h in itertools.product(op,repeat=3):
if -1e-5<f(g(h(a,b),c),d)-24<1e-5 or \
-1e-5<f(g(a,h(b,c)),d)-24<1e-5 or \
-1e-5<f(g(a,b),h(c,d))-24<1e-5 or \
-1e-5<f(a,g(h(b,c),d))-24<1e-5 or \
-1e-5<f(a,g(b,h(c,d)))-24<1e-5: #(这段if算一行
return True
return False
作者:azusatsang
链接:https://leetcode-cn.com/problems/24-game/solution/python-6xing-biao-da-shi-shu-by-azusatsang/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
