洛谷 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版)的主要内容,如果未能解决你的问题,请参考以下文章