这个题考虑用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)
PREVIOUSmq064.整数反转
NEXTlc005.最长回文子串