全排列 --- 回溯

你这道「全排列」的问题,不是不会思路,而是回溯代码的顺序和细节容易写乱

你主要有这几个问题:


1. 结束条件位置放错了

你把:

复制代码
复制代码
if (result.size() == n) {
    list.add(result);
    return;
}

写在了 for 循环里面。

但正确习惯是:递归函数一进来,先判断是否已经完成。

应该写在 for 前面:

复制代码
复制代码
if (result.size() == nums.length) {
    list.add(new ArrayList<>(result));
    return;
}

原因是:

每次进入 dfs,都先判断当前路径是不是已经凑够长度了。

凑够了就保存答案,不需要再进入 for 循环。


2. 没有复制 result

你写的是:

复制代码
复制代码
list.add(result);

这是错的。

因为 result 是一个会不断变化的列表,后面还会添加、删除。

正确写法:

复制代码
复制代码
list.add(new ArrayList<>(result));

意思是:

把当前 result 复制一份保存起来。

否则最后答案可能全都变成空数组,或者内容混乱。


3. 递归调用的位置不严谨

你原来写的是:

复制代码
复制代码
if (!used[i]) {
    result.add(nums[i]);
    used[i] = true;
}

dfs(nums);

result.remove(nums[i]);
used[i] = false;

问题是:

即使 used[i] == true,没有选择这个数,你还是会执行:

复制代码
复制代码
dfs(nums);

这会导致逻辑混乱。

正确写法是:

复制代码
复制代码
if (used[i]) {
    continue;
}

result.add(nums[i]);
used[i] = true;

dfs(nums);

result.remove(result.size() - 1);
used[i] = false;

也就是说:

用过的数字直接跳过。

没用过的数字,才执行:选择 → 递归 → 撤销。


4. 删除元素写错了

你写的是:

复制代码
复制代码
result.remove(nums[i]);

这个很容易出错。

因为在 Java 的 List<Integer> 里:

复制代码
复制代码
remove(数字)

会优先理解成:

删除这个下标位置的元素

而不是删除这个值。

比如:

复制代码
复制代码
result.remove(2);

它的意思可能是:

删除下标为 2 的元素

不是删除数字 2

正确写法:

复制代码
复制代码
result.remove(result.size() - 1);

因为回溯时,我们一定是删除刚刚加入的最后一个数字


5. 回溯模板顺序还不熟

你现在最大的问题是:知道要递归,但不知道代码应该按什么顺序摆。

全排列的固定顺序是:

复制代码
复制代码
1. 判断是否完成
2. for 循环枚举每个数字
3. 如果用过,跳过
4. 做选择
5. 递归
6. 撤销选择

对应代码:

复制代码
复制代码
public void dfs(int[] nums) {
    if (result.size() == nums.length) {
        list.add(new ArrayList<>(result));
        return;
    }

    for (int i = 0; i < nums.length; i++) {
        if (used[i]) {
            continue;
        }

        result.add(nums[i]);
        used[i] = true;

        dfs(nums);

        result.remove(result.size() - 1);
        used[i] = false;
    }
}

一句话总结你的问题

你已经知道要用:

复制代码
复制代码
result
used
dfs

说明大方向是对的。

你卡住的是:

回溯不是随便递归,而是必须严格按照

判断结束 → 枚举选择 → 做选择 → 递归 → 撤销选择

这个顺序写。

以后你写全排列,先默写这个模板:

复制代码
复制代码
if (路径长度够了) {
    保存路径的拷贝;
    return;
}

for (每一个选择) {
    if (这个选择不能用) {
        continue;
    }

    做选择;
    dfs();
    撤销选择;
}

你这次的核心错误可以记成四句话:

复制代码
复制代码
结束条件放 for 前面
保存答案要 new ArrayList
用过的数字直接 continue
撤销时删除最后一个元素
相关推荐
pen-ai36 分钟前
【优化方法】最小二乘:从误差平方到线性与非线性拟合
人工智能·算法·机器学习
Q26433650231 小时前
【有源码】基于机器学习的电信网络诈骗话术语义识别与可视化分析系统 XGBoost算法+Hadoop+Spark
大数据·hadoop·算法·机器学习·spark·毕业设计·课程设计
不会就选b2 小时前
算法日常・每日刷题--贪心<11>
算法·leetcode·职场和发展
千里码aicood2 小时前
面向电商冷启动与数据稀疏性的协同过滤算法优化研究
大数据·算法·协同过滤
xxxiugou1232 小时前
双指针解题秘籍:从入门到精通
c语言·数据结构·c++·算法
能源革命2 小时前
TimesFM(Time Series Foundation Model)介绍
算法·能源
猎嘤一号2 小时前
学术训练(一)文献检索与阅读
人工智能·算法·机器学习·科研入门
Doubbbbbbble云2 小时前
多路归并算法在外部排序中的实现与优化
算法
沉淀的.晴天2 小时前
FreeRTOS信号量
数据结构·算法
青山木3 小时前
Hot 100 --- 打家劫舍
java·数据结构·算法·leetcode·动态规划