• leetcode 60. 第k个排列,回溯以及剪枝


    给出集合 ([1,2,3,…,n]),其所有元素共有 (n!) 种排列。

    按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:

    "123"
    "132"
    "213"
    "231"
    "312"
    "321"
    

    给定 (n) 和 (k),返回第 (k) 个排列。
    说明:

    • 给定 (n) 的范围是 ([1, 9])
    • 给定 (k) 的范围是 ([1, n!])

    思路讲解

    本体是典型的回溯模型,全排列问题经常使用到回溯的技巧。但是本题仅仅让我们返回第k个序列,而不是全排列的全体,这样的话,我们就得在回溯模型的基础上,进行剪枝,得到所需要的那个答案。

    根据回溯的思想,我们每次都要进行一次选择,然后递归下去。起初我们构建我们的选择数组,我们用一个vector 容器承接我们所有的选择,vector push 进去(1)(n)。这个数组跟随我们的递归不断深入下去,我们在每一层的递归中从这个vector 选择容器中,选出我们应该选的那个元素,然后再将这个元素利用erase 接口消除掉。等到这个容器没有可供选择的选项时候,那么我们就return 函数返回。

    那么问题就来了,我们应该怎样选择我们需要的那个数组呢。

    • 我们面对一个选择数组,数组大小为(n),那么这个选择数组一共有 (n!)排列的结果,我们也明白我们需要选择第(k)大的排列结果。
    • 因为我们的选择数组的选项的大小是从小到大的,所以如果我们选了第一个选项,那么我们在此基础上所做的结果,最大也就 (n-1)!大的序列,利用这个特性我们进行剪枝

    剪枝的逻辑

          for(int i = 0; i < choose.size(); i++){
                if ( k > Factorial(choose.size()-1)){
                      k = k - Factorial(choose.size()-1); 
                      # 我们不在做个选择了,那么我们在下一个选择中看寻找 第 k - Factorial(choose.size()-1)大小的选项
                      continue;
                }else{
                      break;
                      # 找到这个选项,这个选项为第i项,我们break, 跳出for 循环
                }
          }
    

    具体代码

    class Solution {
    private:    
        long jiecheng(int n){
            if (n == 0 || n == 1)
                return 1;
            long res = 1;
            for(int i = 1; i <= n; i++){
                res = res * i;
            }
            return res;
        }
    private:
        string res;
    public:
        string getPermutation(int n, int k) {
            vector<int> choose;
            for(int i  = 1; i <= n; i++){
                choose.push_back(i);
            }
            dfs(choose, k);
            return res;
        }
        void dfs(vector<int>& choose, int& k){
            if (choose.empty()){
                return;
            }
            int choose_size = choose.size();
            int i; 
            for(i = 0; i < choose.size(); i++){
                if ( k > jiecheng(choose_size -1)){
                    k = k - jiecheng(choose_size -1);
                    continue;
                }
                break;
            }
            int make_choose = choose[i];
            res = res + to_string(make_choose);
            choose.erase(choose.begin() + i);
            dfs(choose, k);
        }
    };
    
  • 相关阅读:
    总体设计
    需求分析概述
    毕业论文管理系统(面向对象方法)
    结构化与面向对象项目前期
    各人博客园地址链接
    软件测试
    读后感作业
    运行及总结
    图书馆管理系统面向对象编程
    图书管理系统设计类图
  • 原文地址:https://www.cnblogs.com/wsl-hitsz/p/13618152.html
Copyright © 2020-2023  润新知