[leetCode]679. 24 点游戏

在这里插入图片描述

回溯法

一共4个数字4种运算,可以通过回溯法遍历不同的可能性。

  • 从4个数字中取出两个数字,并选择一种运算有 4*3=12种,将运算结果取代取出的两个数字等到3个数字
  • 在剩下三个数字种取出两个数字并选择一种运算有 3*2 = 6种, 将运算结果取代取出的两个数字还剩2数字
  • 剩下两个数字有两种不同的顺序,可选择一种运算
    因此,一共有:124+64+2*4=9216种可能性。

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

  • 需要注意浮点运算的精度与除数为0的情况
  • 由于加法与乘法符合交换律因此可以进行优化,跳过一种顺序
class Solution {
    // 目标值
    static final int TARGET = 24;
    // 浮点运算允许的误差
    static final double EPSILON = 1e-6;
    // 加减乘除
    static final int ADD = 0, MULTIPLY = 1, SUBTRACT = 2, DIVIDE = 3;

    public boolean judgePoint24(int[] nums) {
        // 将四个数字加入链表
        List<Double> list = new ArrayList<>();
        for (int num : nums) 
            list.add((double)num);
        return solve(list);
    }

    private boolean solve(List<Double> list) {
        if (list.size() == 0) return false;
        if (list.size() == 1)
            return Math.abs(list.get(0) - TARGET) < EPSILON;
        int size = list.size();
        // i,j为取出两个数字的下标
        for (int i = 0; i < size; i++) 
            for (int j = 0; j < size; j++) {
                if (i != j) {
                    List<Double> list2 = new ArrayList<>();
                    // 添加 i, j以外的另外两个数字
                    for (int k = 0; k < size; k++) {
                        if (k != i && k != j) {
                            list2.add(list.get(k));
                        }
                    }
                    for (int k = 0; k < 4; k++) {
                        // 加法和乘法符合交换律,对于取出的两个数字其中一种顺序不用考虑
                        if (k < 2 && i > j)
                            continue;
                        if (k == ADD) {
                            list2.add(list.get(i) + list.get(j));
                        } else if (k == MULTIPLY) {
                            list2.add(list.get(i) * list.get(j));
                        } else if (k == SUBTRACT) {
                            list2.add(list.get(i) - list.get(j));
                        }else if (k == DIVIDE) {
                            if (Math.abs(list.get(j)) < EPSILON)
                                continue;
                            else 
                                list2.add(list.get(i) / list.get(j));
                        }
                        if (solve(list2))
                            return true;
                        list2.remove(list2.size() - 1);
                    }
                }
            }
        return false;
    }
}
原文地址:https://www.cnblogs.com/PythonFCG/p/13859889.html