24 Game
week5
难度:Hard
题目描述
You have 4 cards each containing a number from 1 to 9. You need to judge whether they could operated through *, /, +, -, (, ) to get the value of 24.
Example1:
Input: [4, 1, 8, 7] Output: True Explanation: (8-4) * (7-1) = 24
Example2:
Input: [1, 2, 1, 2] Output: False
Note:
1.The division operator / represents real division, not integer division. For example, 4 / (1 - 2/3) = 12.
2. Every operation done is between two numbers. In particular, we cannot use - as a unary operator. For example, with [1, 1, 1, 1] as input, the expression -1 - 1 - 1 - 1 is not allowed.
3. You cannot concatenate numbers together. For example, if the input is [1, 2, 1, 2], we cannot write this as 12 + 12.
题目分析
这道题目的意思很明显,就是要解决24点的问题,随机给出4个数,仅能用四则运算,若得到24点则输出正确,否则输出错误。
解题思路
解决这道题一开始是使用穷举法,将所有的可能都列举出来,然后进行判断,但每一次运算只能减少一个数,而一开始有4个数,4个运算法则,而四则运算中,乘和加是和两个数顺序无关的,那么结果有$$C2_4*6*C2_36C^2_2*6 = 3888$$
种可能,有点多,不可能用代码都列出来。
所以接下来考虑利用递归的方式,将每一种方法都遍历一遍,类似于深度搜索的方法,构成一棵树,根为4个数,每个分支代表一次运算,其子节点数的个数-1,因此树的高度为4,用深度遍历的原因是我们只需要把这个24点有无解输出就可以了,不需要输出解甚至所有的解,所以每次遍历都要达到高度4,以便最快得到一个解。
采用递归的方式能够更好的遍历,当一个解不符合时,马上退回上一个状态,寻找下一个解,这里使用vector存储得到的解,当不符合时,弹出得到的运算数,回到上一状态。
代码
1 | class Solution { |
Note
-
因为所给的数的类型是int,因此在运算时要将其转成double类型方便进行乘除运算,否则会出现较大误差,并且判断是否为24点时因计算机的运算可能存在误差,所以要根据其和24点的误差小于一定值来判断。
-
因为在加减乘除中,加和乘对于数作为被加/乘数和加/乘数的结果是无影响的,因此,可以跳过2次运算,这样相当于每个节点原本8个子节点缩减为6个子节点,大大减少其分支,一开始以为没少多少,但是由于树高为4,算出的解能少3/4,极大减少时间。
-
加减乘除的顺序可以调转,也可以是先做加运算一直做到头,再做其它运算,也是可以的,但是个人觉得运算混搭可能会加快得到解的速度,即得到解的概率会大一些,单一进行运算很难得到24点。又由于其运算结果个数并不多,所以感觉使用启发式搜索并没有太大改进,判断时间可能使搜索时间变得更多。
总结
思路主要是来源于题目写了一个tag为“depth-first search”让我有了一点思路,做这一些判断等题目,若是要进行所有结果的遍历,那么最好的方法就是进行搜索,搜索主要就是用到了树的遍历,即遍历状态。如果状态数过多,那么使用启发式搜索要比盲目搜索更好,而盲目搜索也要根据目的来确定,启发式搜索的难点就在于调参,确定一个搜索方向,而这道题因方向难以确定,而状态数不多,因此才采用深度搜索。