回溯时current.remove被执行了两次
我对编程中的回溯概念有很多问题,但主要是想弄清为什么current.remove会执行两次。于是我在练习一个LeetCode的题目,需要找出数组 {1,2,3} 的所有可能子集。看起来最直接、也最常用的方法就是回溯。
下面是LeetCode上某人给出的解法
package CodingPractice;
import java.util.*;
public class BackTrackingExample {
/**
* Backtracking function to find all subsets of an array.
*/
private static void backtrack(int[] nums, int start, List<Integer> current, List<List<Integer>> result) {
// Add the current path to our list of results
result.add(new ArrayList<>(current));
// Iterate through the options starting from the current index
for (int i = start; i < nums.length; i++) {
// 1. Make a choice: add element to the current subset
current.add(nums[i]);
// 2. Explore: move deeper into the decision tree
backtrack(nums, i + 1, current, result);
// 3. Backtrack: remove the last choice to explore other possibilities
current.remove(current.size() - 1);
}
}
/**
* Entry point for the Java Virtual Machine (JVM).
*/
public static void main(String[] args) {
int[] nums = {1, 2, 3};
List<List<Integer>> result = new ArrayList<>();
// Start the backtracking process
backtrack(nums, 0, new ArrayList<>(), result);
// Print the findings
System.out.println("All possible subsets:");
for (List<Integer> subset : result) {
System.out.println(subset);
}
}
}
我运行了代码,它确实给出了所有正确的子集。
但在调试过程中有些事情我不太理解。我只是想确保自己完全理解。
我整理了一份让我困惑、为什么会这样的点的清单,希望有人能为我解答。
- 为什么在执行current.remove之后,变量i 会从2 变成1?
- 为什么在第一次退出循环时,当i 变为3 时,current.remove会紧接着执行两次?
- 为什么在第二次执行current.remove之后(把 {1,2,3} 加入结果后),i会从1 变为2?
解决方案
current.remove() 实际上并不是在同一个地方执行两次。发生的情况是,递归调用会返回到调用栈的上一层级,在继续循环之前,每一层都会移除它添加的那个值。
这部分是关键的:
current.add(nums[i]);
backtrack(nums, i + 1, current, result);
current.remove(current.size() - 1);
流程基本如下:
- 添加一个值
- 进入更深的递归
- 从递归返回
- 移除最后一个值
- 继续测试其他可能性
因此在调试时看到多次 remove() 调用,通常是在不同的递归调用中发生的,而不是在同一个执行层级。
同样的情况也出现在 i。每个递归调用都有自己的循环状态,因此当递归结束时,执行会从它离开的上一层继续。
例如,在探索:
[1,2,3]
之后,算法会回到:
[1,2]
移除 3,然后继续检查其他分支。
帮助我更好理解回溯的一点,是把它想象成在一棵树上进行探索,完成每个分支后再向后退步:
[]
├── [1]
│ ├── [1,2]
│ │ └── [1,2,3]
│ └── [1,3]
├── [2]
│ └── [2,3]
└── [3]
完成一个分支后,算法会“撤销”上一次的选择,以便继续探索下一个分支。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。