LeetCode - 检查给定的4个整数可以使24个

时间:2018-05-01 04:52:06

标签: java arrays recursion permutation

我正在尝试这个LeetCode question,它要求一个布尔函数,如果4个int的给定数组可以通过基本算术运算符+-得到24,则返回true, /*。括号不重要,因为如果所有排列都正确,它们将被隐含地计算。

对于这个问题,我使用(n P k)表示从n个元素中找到所有k大小的排列,因为顺序对-/很重要。

对于第一个选择,我们有(4 P 2)= 12和4个运算符,因此12 * 4 = 48个结果。对于第二种选择,我们剩下3个元素,或者(3 P 2)= 6和4个运算符,6 * 4 = 24个结果。最后,我们有2个元素和4个运算符,总共8个结果。总的来说,我们有48 * 24 * 8 = 9216 元素和运算符的总排列。

我的解决方案适用于69/70的LeetCode测试用例(列表3,3,8,8错误地返回false)。但是,无论何时我尝试调整代码以使最后一个测试用例工作,一组新的测试用例都会失败。代码似乎是正确的,但显然它不是,经过几个小时和几个小时后,我仍然难以接受。

首先,一个帮助方法交换数组中的两个元素。

// swap indices x and y of array A
static void swap(double[] A, int x, int y) {
    double temp = A[x];
    A[x] = A[y];
    A[y] = temp;
}

核心思想是将剩余的值保留在A[0..right]中(注意包含上限)。指示ij表示为操作选择的2个元素。将此新结果放在i

现在A[j]用于该计算,需要被删除"。这是通过将jright进行交换来完成的。在递归调用中,递减right,因为您将2个值与某个运算符组合在一起,现在剩下少1个元素。所以现在j位于数组的右边分区中,不再用于将来的计算。

/**
 * Iterate through all 9216 permutations of elements and operators until a permutation
 * that can make 24 has been found.
 * 
 * @param  A     Array of doubles
 * @param  right Rightmost index of current subarray A[0..right],
                 which stores the remaining elements
 * @return       True if the original given array can produce 24
 */
static boolean permute(double[] A, int right) {
    // base case, array of size 1
    if (right == 0) { return A[0] == 24; }

    // choose 2 distinct elements and apply all 4 operators
    for (int i = 0; i <= right; i++) {
        double temp = A[i];  // used for restoring value later

        for (int j = 0; j <= right; j++) {
            if (i==j) continue;

            for (int op = 0; op < 4; op++) {
                switch(op) {
                    case 0: A[i] += A[j]; break;
                    case 1: A[i] *= A[j]; break;
                    case 2: { if(A[j] <= 0) return false;
                                A[i] /= A[j]; break; }
                    case 3: A[i] -= A[j]; break;
                }

                swap(A,j,right);
                if(permute(A,right-1)) return true;

                // restore values
                swap(A,j,right);
                A[i] = temp;
            }
        }
    }
    return false;
}

在调试时,我添加了print语句,对于每一种情况,无论实际的布尔值是对还是错,都打印了9216个数组,所以我知道迭代次数是正确的。我怀疑在内部for循环中的递归调用后恢复值时发生错误。

允许与int[]

兼容的其他方法
static boolean make24(int[] A) {
    return permute(IntStream.of(A).mapToDouble(num -> num).toArray(), A.length-1);
}

最后,驱动方法:

public static void main(String[] args) {
    int[] a = new int[] {8,8,3,3};  
    System.out.println(make24(a));  // incorrectly returns false
}

可能有用的其他测试用例:

1,3,4,6 --> true
3,3,8,8 --> true
1,2,1,2 --> false
3,4,6,7 --> false
1,5,9,1 --> false

我尽可能地尝试评论和解释而不会过度。我在这里要求很多,所以我不期待很多回复,但是感谢你阅读这篇文章!

编辑:从此solution I found开始,任意精度算术似乎都会导致一些错误。例如,代替return A[0] == 24;,执行return Math.abs(A[0]-24) < 1e-8;。进行这些更改会修复程序,因此实际的算法逻辑是正确的:)

0 个答案:

没有答案