0

我遇到了一个需要建议的分区问题。我得到一个长度为偶数的一维数组。我需要编写一个布尔方法来确定数组是否可以分成 2 个大小相等且总和相等的子数组,不允许循环。

例如,数组 #1 {-3,5,-12,14,-9,13} 将返回 false,因为 -3 + 5 -12 + 14 = -9 + 13,但左侧有 4 个元素而在另一边 2。

数组 #2 将返回 true:{-3,14,12,5,-9,13}:-3 + 5 + 14 = 12 - 9 + 13

这是我到目前为止所做的:

public static boolean canBeDividedEqually(int[] arr)
{
    if (arr.length %2 ==0){
        return canBeDividedEquallyHelper(arr, 0, 0, 0);
    }
    return false;
}

public static boolean canBeDividedEquallyHelper(int[] arr, int i, int sum1, int sum2)
{
    if (i == arr.length){
        return sum1 == sum2;}
    
    return canBeDividedEquallyHelper(arr, i+1, sum1 + arr[i], sum2) ||
           canBeDividedEquallyHelper(arr, i+1, sum1, sum2 + arr[i]);
}

对于案例 #2,它将按预期返回 true,但对于案例 #1,它也将返回 true。我需要添加一个条件,该条件将取消案例 #1 类型的数组的资格。

4

4 回答 4

1

你快到了。除了总和,传递元素的数量:

public class Solver
{
    public static boolean canBeDividedEqually(int[] arr)
    {
        return canBeDividedEquallyHelper(arr, 0, 0, 0, 0, 0);
    }

    public static boolean canBeDividedEquallyHelper(int[] arr, int i, int nb1, int sum1, int nb2, int sum2)
    {
        if (i == arr.length)
            return nb1 == nb2 && sum1 == sum2;
        return canBeDividedEquallyHelper(arr, i+1, nb1+1, sum1 + arr[i], nb2, sum2) ||
               canBeDividedEquallyHelper(arr, i+1, nb1, sum1, nb2+1, sum2 + arr[i]);
    }

    public static void main(String[] args)
    {
        System.out.println(canBeDividedEqually(new int[]{-3, 5, -12, 14, -9, 13})); // false
        System.out.println(canBeDividedEqually(new int[]{-3, 14, 12, 5, -9, 13})); // true
    }
}
于 2021-12-24T12:04:07.950 回答
1

尝试这个。

static boolean canPartitioning(int[] arr) {
    return new Object() {
        int length = arr.length, half = length / 2;

        boolean partition(int i, int selected, int sum, int rest) {
            if (i >= length)
                return selected == half && sum == rest;
            return selected < half && partition(i + 1, selected + 1, sum + arr[i], rest)
                || partition(i + 1, selected, sum, rest + arr[i]);
        }
    }.partition(0, 0, 0, 0);
}


public static void main(String[] args) {
    System.out.println(canPartitioning(new int[] {-3, 5, -12, 14, -9, 13}));
    System.out.println(canPartitioning(new int[] {-3, 14, 12, 5, -9, 13}));
}

输出:

false
true
于 2021-12-24T12:36:33.910 回答
0

这是一个不使用循环的解决方案,

static int[] arrA, arrB;
    public static boolean equalSplit(int[] arr) {
        //Step 1
        if (arr.length % 2 == 0) {
            int sumA = 0, sumB = 0; // Two int variables to store the value of sum.

            // Initializing the two new arrays with equal length.
            arrA = new int[arr.length / 2]; 
            arrB = new int[arr.length / 2];

            // Copying the elements from the given array to the new arrays.
            arrA = createArray(arrA, 0, arr, 0);
            arrB = createArray(arrB, 0, arr, arr.length / 2);

            //Calculating and storing the sum in the variables.
            sumA = arraySum(arrA, arrA.length);
            sumB = arraySum(arrB, arrB.length);

            return sumA == sumB; // Checking the codition

        } else {
            return false;
        }
    }

    private static int[] createArray(int[] arr, int index, int[] copyFrom, int copyFromIndex) {
        if(index == arr.length) return arr;
        arr[index] = copyFrom[copyFromIndex];
        index++;
        copyFromIndex++;
        return createArray(arr, index, copyFrom, copyFromIndex);
    }

    private static int arraySum(int[] arr, int N) {
        if (N <= 0) return 0;
        return (arraySum(arr, N - 1) + arr[N - 1]);
    }

我对这个问题的态度是,

第 1 步 -> 检查是否可以将给定数组拆分为两个相等的数组。如果是,接下来是第 2 步,或者返回 false 而不进行任何进一步的步骤。

第 2 步 -> 使用递归将给定的数组元素复制到两个不同但相等的数组中。

第 3 步 -> 对新填充的两个数组求和并将其存储在两个不同的变量中。

第 4 步 -> 如果两个新填充的数组的总和相等,则函数返回 true,否则返回 false。

解释 :

创建两个新的整数数组,只有当给定的数组可以分成两个相等的部分时才会填充它们。这里是 arrA 和 arrB。

检查给定数组的长度是否可以被 2 整除并且余数为 0,因为这可以回答“这个数组可以分成两个相等的部分吗?”的问题。此答案中的代码是 arr.length % 2 == 0。如果给定的数组仅满足此条件,则将执行下面给出的步骤,否则它将返回 false。

初始化两个整数变量以存储两个等分数组的 Sum 的值。

初始化两个新创建的数组,数组长度为给定数组的一半,即arr.length / 2.

然后将给定数组元素的前半部分复制到第一个新初始化的数组,然后将后半部分复制到第二个数组。实现这个createArray(int[] arr, int index, int[] copyFrom, int copyFromIndex)方法是用的。arr 是传递要复制到的数组的参数,index 应该为 0,因为它用作新创建的数组的索引,copyFrom 是给定数组的参数,其中包含所有元素,copyFromIndex 用于开始复制给定索引中的元素。

然后使用递归函数计算总和并将其存储在之前创建的单独变量中。这里使用的函数是arraySum(int[] arr, int N).

返回两个总和变量是否相等。

于 2021-12-24T11:06:08.777 回答
0

如果允许更改元素顺序,则必须检查数组的所有可能排列:

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        int[] a =  {-3, 5, -12,14,-9,13};
        int[] b =  {-3,14, 12, 5,-9,13};

        System.out.println(isEquallySplittable(a));
        System.out.println(isEquallySplittable(b));
    }

    public static boolean isEquallySplittable(int[] array){
        long arraySum = arraySum(array);
        if(arraySum % 2 != 0) return false;  //can not split an even sum by half
        return isEquallySplittable(array, 0, 0, arraySum);
    }

    public static boolean isEquallySplittable(int[] array, int indexFrom, int indexTo, long sumArray){

        if(indexTo == indexFrom) {
            indexTo++;
        }

        if(indexTo >= array.length) {
            indexTo = 0;
            indexFrom++;
        }

        if(indexFrom >= array.length)  return false;

        long sumHalfArray = arraySum(Arrays.copyOf(array, array.length/2)); //sum first half of the array
        if(sumArray  == sumHalfArray * 2 ){
            System.out.println(Arrays.toString(array) + " can be split into 2 equal arrays");
            return true;
        }
        //next permutation
        int temp = array[indexTo];
        array[indexTo] = array[indexFrom];
        array[indexFrom] = temp;
        return isEquallySplittable(array, indexFrom, ++indexTo, sumArray);
    }

    public static long arraySum(int[] arr) {
        return arraySum(arr, 0, 0);
    }

    private static long arraySum(int[] arr, int index, long sum) {
        if (index  >= arr.length ) return sum;
        sum += arr[index++];
        return arraySum(arr,index,sum);
    }
}
于 2021-12-24T16:00:36.683 回答