zoukankan      html  css  js  c++  java
  • b_lc_第k个排列(暴搜 / 数学剪枝)

    给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
    按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:

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

    给定 n 和 k,返回第 k 个排列。
    说明:
    给定 n 的范围是 [1, 9]。
    给定 k 的范围是[1, n!]。

    输入: n = 4, k = 9
    输出: "2314"
    

    方法一:暴搜

    思路
    利用位掩码来记录数字的选择状态

    class Solution {
    public:
        string ans;
        int vis[10];
        void dfs(string& cur, int mask, int n, int& k) {
            if (cur.size() == n) {
                k--;
                if (!k) ans=cur;
                return;
            }
            for (int j=1; j<=n; j++) if ((mask & (1 << j-1)) == 0) {
                cur += to_string(j);
                dfs(cur, mask | (1<<j-1), n, k);
                cur.pop_back();
                if (!k) return;
            }
        }
        string getPermutation(int n, int k) {
            string cur="";
            memset(vis, 0, sizeof vis);
            dfs(cur, 0, n, k);
            return ans;
        }
    };
    

    复杂度分析

    • 时间复杂度:\(O(n!)\)
    • 空间复杂度:\(O(k)\)

    方法二:数学剪枝

    比如 n=4,k=9 时:

    • 假设第一位选择 1,则后面由 2、3、4 组成的排列共 3! 种,9 > 6 故 1 不可取
    • cur = "2",假设第一位选择 2,则后面由 1、3、4 组成的排列共 3! 种,但经过上面一层的过滤,此时剩下排列只有 9-6=3 种,而 3! > 3,故,k=9 时的全排列一定在以 2 为开头的排列中(k=3)
      • cur = "21" 由于 1 没有选,接下来如果选 1 的话,后面的 3、4 可以组成的排列则有 2! 个,但 \(3-2 > 1\) 故,1 也不可选,这里继续删除以 "21" 为开头的两个排列 "2134"、"2143"(k=1)
        • cur = "213" ,由于 3 没有选,接下来如果选 3 的话,此时只剩下的 4 组成的排列有 1 种,而 1-1 = 0,也就是 k=0 啦

    注:假设从 n+1 层回退到上一层 n 的时候,由于第 n 层的选择是无效的,所以 vis 数组对 n+1 层选择的数字不会做出撤销

    class Solution {
    public:
        string s;
        int n,st[10],fac[10];
        void dfs(int& k) {
            if(s.size()==n){
                return; 
            }
            int c=fac[n-s.size()-1];
            for (int j=1; j<=n; j++) if (!st[j]) {
                if (k>c) {
                    k-=c;
                } else {
                    st[j]=1, s+=to_string(j);
                    dfs(k);
                }
            }
        }
        string getPermutation(int n, int k) {
            fac[0]=1;
            for (int i=1; i<=n; i++) fac[i]=fac[i-1]*i;
            this->n=n;
            dfs(k);
            return s;
        }
    };
    

    复杂度分析

    • 时间复杂度:\(O(k)\)
    • 空间复杂度:\(O(n)\)
  • 相关阅读:
    各种web页面中的绘图技术对比
    32位和64位操作系统
    mysql新建用户本地无法登录
    ruby libmysqlclient.18.dylib
    jenkins创建git任务连接时遇到的问题
    mybatis 打印日志log4j.properties
    使用shell统计出出现次数排名top10的网址(在博客园中没找到,特转一下)
    ActiveMQ和Tomcat的整合应用(转)
    java 哪些情况下会使对象锁释放
    Web容器与Servlet
  • 原文地址:https://www.cnblogs.com/wdt1/p/13619439.html
Copyright © 2011-2022 走看看