洛谷 P1706 全排列问题(Java版)

Posted ZSYL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P1706 全排列问题(Java版)相关的知识,希望对你有一定的参考价值。

题目描述

按照字典序输出自然数 1 到 n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式

一个整数 n。

输出格式

由 1∼n 组成的所有不重复的数字序列,每行一个序列。

每个数字保留 5 个场宽。

输入

3

输出

    1    2    3
    1    3    2
    2    1    3
    2    3    1
    3    1    2
    3    2    1

思路分析

请参考Java 全排列与组合

递归调用,对于每一种排列,可以类似于二叉树的构造,每一个元素都可以做根结点,因此我们交换位置,改变每一个元素位置。

借鉴思考

import java.util.Scanner;

public class 全排列 {
    static int n;
    static int[] x;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        x = new int[n+1];
        for (int i = 1; i <= n; i++) {
            x[i] = i;
        }
        permutationAll(1, n);
    }
    public static void permutationAll(int s, int e) {
        if (s == e) {
            for (int i = 1; i <= n; i++) {
                System.out.printf("%5d", x[i]);
            }
            System.out.println();
            return;
        }
        for (int i = s; i <= e; i++) {
            swap(s, i);
            permutationAll(s+1, e);
            swap(s, i);
        }
    }
    // 交换元素函数
    public static void swap(int i, int j) {
        int temp = x[i];
        x[i] = x[j];
        x[j] = temp;
    }
}

不幸的是:

在这里插入图片描述
题目所要答案:

    1    2    3
    1    3    2
    2    1    3
    2    3    1
    3    1    2
    3    2    1

而我们的是:

在这里插入图片描述
因此需要更改递归策略,得到正确结果的顺序。

参考代码

考虑使用递归,但不交换,对于当前元素我们可以要,也可以不要,注意回溯时需要还原现场,使用List数据结构,存储排列结果。

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
    static int n;
    static int[] x;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        x = new int[n+1];
        for (int i = 1; i <= n; i++) {
            x[i] = i;
        }
        permutationAll(new ArrayList<>());
    }
    public static void permutationAll(List<Integer> res) {
        if (res.size() == n) {
            for (int i : res) {
                System.out.printf("%5d", x[i]);
            }
            System.out.println();
            return;
        }
        for (int i = 1; i <= n; i++) {
           if (!res.contains(x[i])) {
           	   // 选择该元素
               res.add(x[i]);
               permutationAll(res);
               // 回溯
               res.remove(res.size()-1);  
           }
        }
    }
}

在这里插入图片描述
我们离结果更进一步,可惜比赛对Java的要求太高了o(╥﹏╥)o,栈溢出了。

“’因为Java没有办法直接跟机器交互,所有数据输出的时候会转化为流对象,在一些极限题目里输出流本身大小会超出内存限制,如 单调栈,
还有一些题目输入输出时间就已经超出时间限制。
所有要是通过了除了最后一个数据范围以外的数据,并且本题全站java无正确通过记录,可视为通过
(一般除了洛谷跟早期POJ和早期pta等平台,不会遇到这样的问题,我以后在c++验题的基础上,会用尽量java验题)”
-------大佬 sqy

优化代码,优化数据结构

  • x[i]:上面中x[i]数组起了交换首结点的作用,我能不能把它作为标记,记录第i个数是否已经被选择。
  • List:使用list超限,换String作为参数记录选择的数,发现仍然不行,后来考虑StringBuilder(效率高,线程不安全)管它安不安全,用了再说。

参考代码2

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
    static int n;
    static int[] x;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        x = new int[n+1];
        permutationAll(new StringBuilder());
    }
    public static void permutationAll(StringBuilder res) {
        if (res.length() == n) {
            for (int i = 0; i < n; i++) {
                System.out.printf("%5s", res.charAt(i));
            }
            System.out.println();
            return;
        }
        for (int i = 1; i <= n; i++) {
           if (x[i] == 0) {
               x[i] = 1;
               res.append(i);
               permutationAll(res);
               res.deleteCharAt(res.length()-1);
               x[i] = 0;
           }
        }
    }
}

在这里插入图片描述
整体来说这道题算是模板题,但需要考虑细节,对Java要求高点。

C++:

在这里插入图片描述
Java:

在这里插入图片描述
加油!

感谢!

努力!

以上是关于洛谷 P1706 全排列问题(Java版)的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P1706 全排列问题

洛谷P1706全排列问题

洛谷 P1706 全排列问题

题解 P1706 全排列问题

P1706 全排列问题

luogu P1706全排列问题