46. 全排列(力扣LeetCode)

本文介绍了如何使用回溯算法解决全排列问题,给定一个不含重复数字的数组,找到所有可能的全排列。算法通过递归和布尔数组标记元素状态,确保不重复,时间复杂度为O(n*n!)。

46. 全排列

题目描述

给定一个不含重复数字的数组 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 <= nums.length <= 6
  • -10 <= nums[i] <= 10
  • nums 中的所有整数 互不相同

回溯算法

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<bool> used(nums.size(), false);  // 创建一个布尔数组,用来标记nums中的元素是否被使用过
        backtracking(nums, used);               // 调用回溯函数开始递归
        return result;                          // 返回最终的全排列结果
    }

private:
    vector<vector<int>> result;  // 用来存储所有的排列组合
    vector<int> path;            // 用来存储当前的排列组合
    
    // 回溯函数
    void backtracking(vector<int>& nums, vector<bool>& used) {
        // 如果当前的排列组合长度等于nums的长度,说明找到了一个完整的排列
        if (path.size() == nums.size()) {
            result.push_back(path);  // 将当前排列加入到结果列表
            return;                   // 返回上一层递归
        }

        // 遍历nums的每个元素
        for (int i = 0; i < nums.size(); i++) {
            // 如果当前元素已经被使用过,跳过
            if (used[i] == true) continue;

            // 否则,标记当前元素为已使用
            used[i] = true;
            // 将当前元素加入到当前排列组合
            path.push_back(nums[i]);
            // 继续递归填充剩下的元素
            backtracking(nums, used);
            // 回溯,即撤销前面的选择
            path.pop_back();  // 移除当前排列的最后一个元素
            used[i] = false;  // 将当前元素标记为未使用,以便于下一次循环能够使用
        }
    }
};

代码的核心逻辑是回溯算法,它通过递归来试探和回撤,在每一步尝试不同的数值,并在填满一种排列后将其加入结果集中,然后撤销最后的选择,回到上一步,再尝试其他未被选择的数值。这个过程一直持续到所有的数都尝试过为止。

  • used数组用来标记某个数字是否已经在当前的排列中被使用过,以避免产生重复的排列。
  • path用来存放当前正在构建的排列。
  • result用来存放所有可能的排列。

整个算法的时间复杂度为O(n*n!),其中n为数组nums的长度。因为有n!(阶乘)个排列,而生成每个排列需要O(n)的时间。

在解决 LeetCode 上的全排列问题时,通常使用回溯法(Backtracking)进行求解。全排列问题要求生成所有可能的排列组合,其中每个元素只能使用一次。以下是针对该问题的详细解题方法和思路。 ### 问题描述 全排列问题要求输入一个不含重复数字的数组,返回其所有可能的全排列。例如,输入 `[1, 2, 3]`,输出应包含所有可能的排列组合,如 `[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]`。 ### 解题思路 全排列问题可以通过回溯法进行递归求解。其核心思想是,从数组中选择一个元素作为排列的第一个元素,然后递归地对剩余元素进行排列,直到所有元素都被使用。具体步骤如下: - 定义一个递归函数,传入当前已选择的元素路径 `path` 和剩余可选元素。 - 如果剩余元素为空,说明当前路径已经形成一个完整的排列,将该路径加入结果列表。 - 否则,遍历剩余元素,每次选择一个元素加入当前路径,并递归处理剩余元素。 ### 代码实现 以下是使用 Python 实现的全排列问题解法: ```python def permute(nums): result = [] def backtrack(path, remaining): if not remaining: result.append(path) return for i in range(len(remaining)): backtrack(path + [remaining[i]], remaining[:i] + remaining[i+1:]) backtrack([], nums) return result ``` ### 代码说明 - `permute(nums)` 函数是主函数,负责初始化结果列表 `result` 并调用递归函数 `backtrack`。 - `backtrack(path, remaining)` 是递归函数,其中 `path` 表示当前已选择的元素路径,`remaining` 表示尚未选择的元素。 - 每次递归调用时,从 `remaining` 中选择一个元素加入 `path`,并将该元素从 `remaining` 中移除,继续递归处理剩余元素。 - 当 `remaining` 为空时,说明已经生成一个完整的排列,将其加入结果列表 `result`。 ### 优化与扩展 - **处理重复元素**:如果输入数组包含重复元素,需要在递归过程中避免生成重复的排列。可以在循环中添加判断条件,跳过已经使用过的相同元素。 - **时间复杂度**:全排列问题的时间复杂度为 O(n * n!),其中 n 是输入数组的长度。这是因为共有 n! 个排列,每个排列的生成需要 O(n) 时间。 ### 示例 对于输入 `[1, 2, 3]`,调用 `permute([1, 2, 3])` 将返回: ```python [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] ``` ### 参考 - 回溯法的基本思想是尝试所有可能的解决方案,并在发现当前选择无法达到目标时回退到上一步[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

命运从未公平

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值