下面是一些简单的(但可怕的低效率)代码来解决这个问题。
这个“回溯”部分是通过递归实现的。每当从Java中的方法返回时,您都会“通过堆栈”回溯到从何处调用它。这使得使用调用堆栈来跟踪你的“回溯”状态非常简单。
这里的基本思想。假设我正在寻找一些数组A的总和n。我们在索引i = 0开始我们的搜索。然后,我们要做两件事情:
- 尝试包括元素A [1]在运行总和。我们通过从索引i + 1中搜索n-A [i]来完成此操作。我们需要在包含的元素的运行列表中记录这个元素。我们会将此列表包含在我们的运行金额xs中。
- 尝试不是包括运行总和中的元素A [i]。我们通过从索引i + 1中搜索当前值n来完成此操作。由于我们不包括A [i]我们不需要更新xs。
看看我们如何搜索整个阵列对于第一种情况,走回头路然后第二种情况做搜索一遍?
请注意,在第二次搜索中使用“backtracking”后,您需要保留一份xs。我认为使用标准Java库完成此操作的最简单方法是在回溯时撤销对xs的更改。因此,如果您在xs的末尾添加一些元素x以执行“with”搜索,那么只需在执行“without”搜索之前从xs中删除最后一个元素即可。
与其试图在数据结构中存储所有答案,我只是在找到答案后立即打印答案。这也是为了简化此解决方案的逻辑。
import java.util.Deque;
import java.util.ArrayDeque;
public class SubarraySums {
/** Program entry point */
public static void main(String[] args) {
int[] array = { 1, 8, 7, 9, 5, 2 };
findSubarraySums(12, array);
}
/** Wrapper function for the search */
public static void findSubarraySums(int goal, int[] array) {
// Search the whole array with an empty starting set
search(goal, new ArrayDeque<Integer>(), array, 0);
}
/** Helper for printing an answer */
private static void printAnswer(Deque<Integer> xs) {
// Print the sum
int sum = 0;
for (int x : xs) sum += x;
System.out.printf("%d =", sum);
// Print the elements
for (int x : xs) {
System.out.printf(" %d", x);
}
System.out.println();
}
/**
* Search the array, starting from index i,
* for a subset summing to n.
* The list xs includes all of the elements that are already
* assumed to be included in this answer
*/
private static void search(int n, Deque<Integer> xs, int[] array, int i) {
// Base case: we've reached zero!
if (n == 0) {
printAnswer(xs);
return;
}
// Base case: solution not found
if (n < 0 || i >= array.length) return;
// Recursive case: try searching with and without current element
// with:
xs.addLast(array[i]);
search(n-array[i], xs, array, i+1);
// without:
xs.removeLast();
search(n, xs, array, i+1);
}
}
上面的代码具有阵列中的6个元素,所以它将会使2 = 64递归调用search
。这就是为什么它“超低效率”。但它也非常简单,所以应该帮助你理解它。您应该使用调试器逐步完成代码以查看会发生什么,或者只是在一张纸上查找执行情况。在搜索过程中,执行“回溯”调用堆栈以尝试两种选项(包括/不包含)应该是非常明显的。
我在代码中使用ArrayDeque
上面来存储我XS名单仅仅是因为Deque
接口具有addLast
和removeLast
方法。 A LinkedList
也可以工作(因为它也实现了Deque
接口)。一个ArrayList
也可以工作,但你需要使用add
和remove(list.size()-1)
,这有点冗长。
因此,在这种情况下,它会是4 + 1和2 + 3,对吗?不需要数组中的值是连续的,对吗? – Mitvailer 2014-09-12 23:12:37
@Mitvailer是的。对于这种情况,1 + 4和2 + 3将是正确的输出 – user1010101 2014-09-12 23:17:01
@Mitvailer如果你能分解问题,我将不胜感激 – user1010101 2014-09-12 23:18:46