leetcode 60. 第k个排列 dfs剪枝 O(n^2)

  1. 第k个排列

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

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

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

给定 n 和 k,返回第 k 个排列。

说明:

给定 n 的范围是 [1, 9]。
给定 k 的范围是[1,  n!]。

示例 1:

输入: n = 3, k = 3
输出: “213”

示例 2:

输入: n = 4, k = 9
输出: “2314”


观察全排列性质

  • n的全排列有n!种方案
  • n的全排列 是由1 xxx2 xxx3 xxx等等一直到n xxx组成的
    在这里插入图片描述
    n=3的解空间树和第k=4个排列如下图
    在这里插入图片描述

因此我们可以dfs加上剪枝,直接找到第k个全排列路径
每次累加节点子树的个数,步步逼近叶子节点即可,可用循环实现 O(n^2)

c++代码实现


    int n;

    void dfs(string& ans, int k) { //dfs枚举每一位数字
        if(ans.size() >= n) return ;
        int sum = 0, i = 0;
        for(i=1; i<=n; i++) {
            if(vis[i]) continue ;
            if(sum+a[n-ans.size()-1] >= k) break;
            sum += a[n-ans.size()-1];
        }
        vis[i] = true;
        ans.push_back('0'+i);
        dfs(ans, k-sum);
    }

    string getPermutation(int n, int k) {
        memset(vis, false, sizeof(vis));
        this->n = n;
        a[1] = a[0] = 1;
        for(int i=2; i<=9; i++) //递推N阶
            a[i] = a[i-1] * i;
        string ans;
        dfs(ans, k);
        return ans;
    }

java代码

import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Scanner;

class Solution {
    static int a[] = new int[16];
    static boolean vis[] = new boolean[16];
    int n = 0;

    void dfs(StringBuilder ans, int k) {
        if(ans.length() >= n) return ;
        int i = 0, sum = 0;
        for(i=1; i<=n; i++) {
            if(vis[i]) continue ;
            if(sum+a[n-ans.length()-1] >= k) break;
            sum += a[n-ans.length()-1];
        }
        vis[i] = true;
        ans.append(i);
        dfs(ans, k-sum);
    }

    public String getPermutation(int n, int k) {
        this.n = n;
        Arrays.fill(vis, false);
        a[0] = a[1] = 1;
        for(int i=2; i<=9; i++) a[i] = a[i-1]*i;
        StringBuilder ans = new StringBuilder();
        dfs(ans, k);
        return ans.toString();
    }
}

public class Main {
    public static final boolean debug = true;
    public static String INPATH = "C:\\Users\\majiao\\Desktop\\test.txt",
            OUTPATH = "C:\\Users\\majiao\\Desktop\\out.txt";
    public static StreamTokenizer tok;
    public static BufferedReader cin;
    public static PrintWriter cout;

    public static long start_time = 0, out_time = 0;
    public static int n, m, K, Q, MAXN = (int)1e5+7, INF = 0x3f3f3f3f;
    public static byte buf[] = new byte[MAXN];

    public static void main(String[] args) throws IOException {
        main_init();
        if(debug) { start_time = System.currentTimeMillis(); }
        if(false) { System.setOut(new PrintStream(OUTPATH)); }

        Solution s = new Solution();
        cout.printf("%s\n", s.getPermutation(4, 9));

        if(debug) {
            out_time = System.currentTimeMillis();
            cout.printf("run time : %d ms\n", out_time-start_time);
        }
        cout.flush();
    }

    public static void main_init() {
        try {
            if (debug) {
                cin = new BufferedReader(new InputStreamReader(
                        new FileInputStream(INPATH)));
            } else {
                cin = new BufferedReader(new InputStreamReader(System.in));
            }
            cout = new PrintWriter(new OutputStreamWriter(System.out));
//            cout = new PrintWriter(OUTPATH);
            tok = new StreamTokenizer(cin);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String next_str() {
        try {
            tok.nextToken();
            if (tok.ttype == StreamTokenizer.TT_EOF)
                return null;
            else if (tok.ttype == StreamTokenizer.TT_NUMBER) {
                return String.valueOf((int)tok.nval);
            } else if (tok.ttype == StreamTokenizer.TT_WORD) {
                return tok.sval;
            } else return null;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static int read_int() {
        String tmp_next_str = next_str();
        return null==tmp_next_str ? -1 : Integer.parseInt(tmp_next_str);
    }
    public static long read_long() { return Long.parseLong(next_str()); }
    public static double read_double() { return Double.parseDouble(next_str()); }
    public static BigInteger read_big() { return new BigInteger(next_str()); }
    public static BigDecimal read_dec() { return new BigDecimal(next_str()); }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值