Leetcode46:全排列——交换、回溯

这篇文章发布已经超过两年,部分工具、版本或观点可能已经变化,请结合最新信息判断。

题目

https://leetcode-cn.com/problems/permutations/

2025.03.09 又重新做了一次

题解

纯dfs

首先想到的办法,cur_path 记录当前路径,left_path 记录剩下可选择的元素。不用回溯,每次递归传参都是数组的复制,空间复杂度很大,但是时间复杂度和回溯法是相同的(应该)。

class Solution:
    def recursion(self, left_path, cur_path):
        if len(cur_path) == self.size:
            self.res.append(cur_path)
            return
        else:
            for num in left_path:
                new_cur_path = cur_path.copy()
                new_cur_path.append(num)
                new_left_path = left_path.copy()
                new_left_path.remove(num)
                self.recursion(new_left_path, new_cur_path)
                
    def permute(self, nums: List[int]) -> List[List[int]]:
        self.size = len(nums)
        self.res = []
        self.recursion(nums, [])
        return self.res

回溯

直接在原有变量上操作,每次递归结束之后复原。可以节省空间。

class Solution:
    def recursion(self):
        if len(self.cur_path) == self.size:
            self.res.append(self.cur_path.copy())
            return
        else:
            for i in range(len(self.left_path)):
                deal_num = self.left_path[i]
                self.cur_path.append(deal_num)
                self.left_path.pop(i)
                self.recursion()
                self.cur_path.pop()
                self.left_path.insert(i, deal_num)
                
    def permute(self, nums: List[int]) -> List[List[int]]:
        self.size = len(nums)
        self.res = []
        self.cur_path = []
        self.left_path = nums
        self.recursion()
        return self.res

注意添加答案的时候要添加数组的复制,否则如果添加的是引用后续操作会影响前面添加的结果:self.res.append(self.cur_path.copy())

回溯模板

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }
    for (选择 : 本层集合中的元素) {
        处理节点;
        backtracking(路径, 选择列表); // 递归
        撤销处理; // 回溯
    }
}

交换、回溯

在前面做过的回溯题中,比如Leetcode17:电话号码的字母组合、Leetcode113:路径总和,我们都是用栈来维护储存路径的数组,但是在这题当中我们用交换的方法来维护,很巧妙啊!

有两个变量first和i。在每一次递归当中,0~first是已确定的路径,i是与first交换的数的位置。看下图:

代码(c++的stl里有swap函数,写出的代码更简洁)

class Solution {
public:
    void backtrack(vector<vector<int>>& res, vector<int>& output, int first, int len){
        if(first==len){
            res.emplace_back(output);
            return;
        }
        for(int i=first;i<len;i++){
            // 动态维护数组
            swap(output[i], output[first]);
            // 继续递归填下一个数
            backtrack(res, output, first+1, len);
            // 撤销操作
            swap(output[i], output[first]);
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> res;
        backtrack(res, nums, 0, (int)nums.size());
        return res;
    }
};
评论区已延迟加载滑到评论区附近时会自动加载,也可以现在手动打开。