DFS + 剪枝 解决 全排列系列问题 (所有题型)

DFS + 剪枝 解决 全排列系列问题


文章目录

  • [DFS + 剪枝 解决 全排列系列问题](#DFS + 剪枝 解决 全排列系列问题)
  • 一、46.全排列
  • [二、47. 全排列 II](#二、47. 全排列 II)
  • [三、60. 排列序列](#三、60. 排列序列)
  • [四、31. 下一个排列](#四、31. 下一个排列)
  • 总结

一、46.全排列

代码如下(示例):

c 复制代码
class Solution 
{
    vector<vector<int>> ret;
    vector<int> path;
    bool check[7];

public:
    vector<vector<int>> permute(vector<int>& nums) 
    {
        dfs(nums);
        return ret;
    }
    void dfs(vector<int>& nums) 
    {
        if (path.size() == nums.size())
        {
            ret.push_back(path);
            return;
        }
        for (int i = 0; i < nums.size(); i++) 
        {
            if (!check[i]) 
            {
                path.push_back(nums[i]);
                check[i] = true;
                dfs(nums);
                // 回溯 -> 恢复现场
                path.pop_back();
                check[i] = false;
            }
        }
    }
};

二、47. 全排列 II

代码如下(示例):

c 复制代码
class Solution {
    vector<int> path;
    vector<vector<int>> ret;
    bool check[9];
    // bfs is so easy
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        dfs(nums, 0);
        return ret;
    }
    void dfs(vector<int>& nums, int pos) 
    {
        if (pos == nums.size()) {
            ret.push_back(path);
            return;
        }
        for (int i = 0; i < nums.size(); i++) 
        {
            // 剪枝
            if (check[i] == false &&
                (i == 0 || nums[i] != nums[i - 1] || check[i - 1] != false)) {
                path.push_back(nums[i]);
                check[i] = true;
                dfs(nums, pos + 1);
                path.pop_back(); // 恢复现场
                check[i] = false;
            }
        }
    }
};

三、60. 排列序列


在全排列的基础上面加上计数功能即可!

代码如下(示例):

c 复制代码
class Solution 
{
    vector<int> path;       // 存储当前排列路径
    string res;             // 最终结果:第k个排列的字符串
    bool check[9];          // 标记数字是否被使用(数字范围1~9)
    int count = 0;          // 计数:当前生成了第几个排列
public:
    string getPermutation(int n, int k) 
    {
        memset(check, false, sizeof(check)); // 初始化标记数组
        vector<int> nums;
        for (int i = 1; i <= n; i++) 
        {
            nums.push_back(i); // 构造 1~n 的数字数组
        }
        dfs(nums, k);
        return res;
    }

    void dfs(vector<int>& nums, int k) 
    {
        // 剪枝:找到结果后直接返回,不再递归
        if (!res.empty()) 
        {
            return;
        }
        // 递归终止条件:路径长度等于数字个数,生成一个完整排列
        if (path.size() == nums.size()) 
        {
            count++; // 排列计数+1
            // 找到第k个排列,转为字符串存储
            if (count == k) 
            {
                for (int num : path) 
                {
                    res += to_string(num);
                }
            }
            return;
        }

        for (int i = 0; i < nums.size(); i++) 
        {
            // 只选未使用的数字(本题无重复,无需去重剪枝)
            if (!check[i]) 
            {
                check[i] = true;
                path.push_back(nums[i]);
                dfs(nums, k);
                path.pop_back(); // 回溯:恢复路径
                check[i] = false; // 回溯:恢复标记
            }
        }
    }
};

四、31. 下一个排列


这道题有录音!

代码如下(示例):

c 复制代码
class Solution {
public:
    void nextPermutation(vector<int>& nums) 
    {
        int n = nums.size();
        // 步骤1:从后往前找第一个升序对 nums[i] < nums[i+1]
        int i = n - 2;
        while (i >= 0 && nums[i] >= nums[i + 1]) 
        {
            i--;
        }
        // 步骤2:从后往前找第一个比 nums[i] 大的数 nums[j]
        if (i >= 0) 
        {
            int j = n - 1;
            while (nums[j] <= nums[i]) 
            {
                j--;
            }
            swap(nums[i], nums[j]); // 交换,增大排列
        }
        // 步骤3:反转 i+1 到末尾,得到最小升序后缀
        reverse(nums.begin() + i + 1, nums.end());
    }
};


总结

这篇文章是作者搜集大量面经和资料这里出来的。感谢你的支持
作者wkm是一名中国矿业大学(北京) 大一的新生,希望得到你的关注
如果可以的话,记得一键三联!

相关推荐
云里雾里!8 分钟前
LeetCode 744. 寻找比目标字母大的最小字母 | 从低效到最优的二分解法优化
算法·leetcode
一条大祥脚23 分钟前
26.1.3 快速幂+容斥 树上dp+快速幂 带前缀和的快速幂 正序转倒序 子序列自动机 线段树维护滑窗
数据结构·算法
二狗哈27 分钟前
czsc入门5: Tick RawBar(原始k线) NewBar (新K线)
算法·czsc
Tisfy33 分钟前
LeetCode 0865.具有所有最深节点的最小子树:深度优先搜索(一次DFS + Python5行)
算法·leetcode·深度优先·dfs·题解
Q741_14737 分钟前
C++ 队列 宽度优先搜索 BFS 力扣 429. N 叉树的层序遍历 C++ 每日一题
c++·算法·leetcode·bfs·宽度优先
Yzzz-F38 分钟前
P4145 上帝造题的七分钟 2 / 花神游历各国[线段树 区间开方(剪枝) + 区间求和]
算法·机器学习·剪枝
Zzz不能停40 分钟前
堆排序算法及大小堆区别
数据结构·算法
zd8451015001 小时前
stm32f407 电机多轴联动算法
stm32·单片机·算法
代码游侠1 小时前
应用——Linux FrameBuffer图形显示与多线程消息系统项目
linux·运维·服务器·开发语言·前端·算法
Eloudy1 小时前
矩阵张量积(Kronecker积)的代数性质与定理
算法·量子计算