【发布时间】:2016-08-02 22:04:21
【问题描述】:
我得到了这样的等式:
n = 7
1 + 1 - 4 - 4 - 4 - 2 - 2
如何以最佳方式替换运算符,使等式之和为零,或打印 -1。
我想到了一种算法,但它不是最优的。我有一个想法来暴力破解所有复杂的情况O(n*2^n),但(n < 300)。
【问题讨论】:
标签: algorithm dynamic-programming brute-force
我得到了这样的等式:
n = 7
1 + 1 - 4 - 4 - 4 - 2 - 2
如何以最佳方式替换运算符,使等式之和为零,或打印 -1。
我想到了一种算法,但它不是最优的。我有一个想法来暴力破解所有复杂的情况O(n*2^n),但(n < 300)。
【问题讨论】:
标签: algorithm dynamic-programming brute-force
您正在尝试解决Partition Problem;即将整数分成两个子集,它们的总和相同,并为一个子集中的整数分配正号,为另一个子集中的整数分配负号。
在您的特定问题中,您对整数的数量和这些整数的值都有一个下限。您可以使用包含/排除方法的标准动态算法方法;即通过考虑不使用最后一个整数的情况,找到总和为i的第一个n整数的子集(因此您需要第一个n-1整数的子集总和为i)以及它的使用位置(第一个 n-1 整数的子集总和为 i - val(n))。
【讨论】:
这是一个想法:
在 Java 中:
// assuming the numbers are positive
// (ignore operator when parsing, line.split("[ +-]+") will do)
public static int canReach0(int[] numbers) {
sort(numbers, 1); // sort(array, offset) doesn't matter what algorithm
// for 300 elements and compared to the complexity of the rest
int[] revSum = new int[numbers.length];
revSum[numbers.length - 1] = numbers[numbers.length - 1];
for (int i = numbers.length - 2; i >= 0; i--)
revSum[i] = revSum[i + 1] + numbers[i];
int sum = numbers[0];
if (sum == revSum[1])
return 0;
return solve(numbers, 1, sum, revSum);
}
private static int solve(int[] numbers, int index, int sum, int[] revSum) {
if (index == numbers.length - 1)
return -1;
int high = sum + numbers[index];
if (high == revSum[index + 1] ||
(high < revSum[index + 1] && solve(numbers, index + 1, high, revSum) == 0))
return 0;
int low = sum - numbers[index];
if (low == -revSum[index + 1] ||
(low > -revSum[index + 1] && solve(numbers, index + 1, low, revSum) == 0))
return 0;
return -1;
}
【讨论】: