回溯算法-全排列

260 阅读2分钟

「这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战

Hope is a good thing, maybe the best of things. And no good thing ever dies.

前言

回溯算法是对树形或者图形结构执行一次深度优先遍历,实际上类似枚举的搜索尝试过程,在遍历的过程中寻找问题的解。

深度优先遍历有个特点:当发现已不满足求解条件时,就返回,尝试别的路径。此时对象类型变量就需要重置成为和之前一样,称为「状态重置」

题目

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列

你可以 按任意顺序 返回答案。

示例 1:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:

输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:

输入:nums = [1]
输出:[[1]]

题目分析

递归参数

  • 递归函数参数

    首先排列是有序的,也就是说[1,2] 和[2,1] 是两个集合

    可以看出元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次 1,所以处理排列问题就不用使用startIndex了。

    但排列问题需要一个used数组,标记已经选择的元素

  • 递归终止条件

    当收集元素的数组path的大小达到和nums数组一样大的时候,说明找到了一个全排列,也表示到达了叶子节点。

  • 单层搜索的逻辑

    因为排列问题,每次都要从头开始搜索,例如元素1在[1,2]中已经使用过了,但是在[2,1]中还要再使用一次1。

    used数组,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次

解题

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function(nums) {
    const res = [], path = [];
    backtracking(nums, nums.length, []);
    return res;
    
    function backtracking(n, k, used) {
        if(path.length === k) {
            res.push(Array.from(path));
            return;
        }
        for (let i = 0; i < k; i++ ) {
            if(used[i]) continue;
            path.push(n[i]);
            used[i] = true; // 同支
            backtracking(n, k, used);
            path.pop();
            used[i] = false;
        }
    }
};

附:

结语

如果这篇文章帮到了你,欢迎点赞👍和关注⭐️。

文章如有错误之处,希望在评论区指正🙏🙏

欢迎关注我的微信公众号,一起交流技术,微信搜索 🔍 :「 五十年以后