以前遇到的全排列,清一色的dfs回溯,自己知道时间复杂度挺高的,最近遇到poj2718认真总结了下全排列。
全排列:给定几个数,要求找出所有的排列方式。
详细代码为
import java.util.Scanner;
public class quanpailie1 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String s[]=sc.nextLine().split(" ");
int a[]=new int[s.length];
for(int i=0;i<s.length;i++)
{
a[i]=Integer.parseInt(s[i]);
}
int b[]=new int[a.length];
boolean b1[]=new boolean[a.length];//判断是否被用
long startTime = System.currentTimeMillis();
dfs(b1,a,b,0);
long endTime = System.currentTimeMillis();
System.out.println("运行时间:" + (endTime - startTime) + "ms");
}
private static void dfs(boolean[] b1, int[] a, int b[], int index) {
// TODO Auto-generated method stub
int len=a.length;
if(index==a.length)//停止
{
if(b[0]==0) {}
else {
for(int j:b)
{
System.out.print(j+" ");
}
System.out.println();
}
}
else
for(int i=0;i<len;i++)
{
if(!b1[i]) {
b[index]=a[i];
b1[i]=true;//下层不能在用
dfs(b1, a, b,index+1);
b1[i]=false;//还原
}
}
}
}
输出打印结果为:
输入: 1 2 3 4 1 2 3 4 1 2 4 3 1 3 2 4 1 3 4 2 1 4 2 3 1 4 3 2 2 1 3 4 2 1 4 3 2 3 1 4 2 3 4 1 2 4 1 3 2 4 3 1 3 1 2 4 3 1 4 2 3 2 1 4 3 2 4 1 3 4 1 2 3 4 2 1 4 1 2 3 4 1 3 2 4 2 1 3 4 2 3 1 4 3 1 2 4 3 2 1 运行时间:2ms
上述方法虽然能够实现全排列,但是方法的复杂度还是很高。指数级别增长。因为要遍历很多没用的情况。所以当数据较大并不能高速处理。所以换一种思路处理。 设[a,b,c,d]为abcd的全排列 那么,该全排列就是 [1,2,3,4](四个数的全排列)=
对于全排列递归的模式为:(和dfs很像)
根据上面的数据找点规律吧:
import java.util.Scanner;
public class quanpailie2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
String s[] = sc.nextLine().split(" ");
int a[] = new int[s.length];
for (int i = 0; i < s.length; i++) {
a[i] = Integer.parseInt(s[i]);
}
long startTime = System.currentTimeMillis();
arrange(a, 0, a.length - 1);
long endTime = System.currentTimeMillis();
System.out.println("运行时间:" + (endTime - startTime) + "ms");
}
static void arrange(int a[], int start, int end) {
if (start == end) {
for (int i : a) {
System.out.print(i);
}
System.out.println();
return;
}
for (int i = start; i <= end; i++) {
swap(a, i, start);
arrange(a, start + 1, end);
swap(a, i, start);
}
}
static void swap(int arr[], int i, int j) {
int te = arr[i];
arr[i] = arr[j];
arr[j] = te;
}
}
输入输出结果为:
1 2 3 4 1234 1243 1324 1342 1432 1423 2134 2143 2314 2341 2431 2413 3214 3241 3124 3142 3412 3421 4231 4213 4321 4312 4132 4123 运行时间:1ms
你可以发现两者采用的规则不同,输出的数据到后面是不一样的。但是你可能还没体验到大数据对程序运行的影响。我把输出的结果注释掉。用0 1 2 3 4 5 6 7 8 9进行全排序:
对于全排列,建议能采用递归还是递归。因为递归没有额外数组开销。并且计算的每一次都有用。而回溯会有很多无用计算。数只越大越明显。
题意就是给几个不重复的数字,让你找出其中所有排列方式中组成的两个数的差值最小。除了大小为0否则0不做开头。
思路:全排列所有情况。最小的一定是该全排列从中间分成2半的数组差。要注意的就是0的处理,不日3个长度的0开头/其他长度的0开头等等。还有的人采用贪心剪枝。个人感觉数据并没有那么有规律贪心不一定好处理,但是你可以适当剪枝减少时间也是可以的。比如根据两个数据的首位 相应剪枝。但这题全排列就可以过。
还有一点就是:数据加减乘除转换,能用int就别用String,string转起来很慢会超时。
附上ac代码,代码可能并不漂亮,前面的介绍也可能有疏漏,还请大佬指出!
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
public class poj2718 {
static int min = Integer.MAX_VALUE;
static int mid = 0;
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int t = Integer.parseInt(in.readLine());
for (int q = 0; q < t; q++) {
String s[] = in.readLine().split(" ");
int a[] = new int[s.length];
for (int i = 0; i < s.length; i++) {
a[i] = Integer.parseInt(s[i]);
}
min = Integer.MAX_VALUE;
mid = (a.length) / 2;
arrange(a, 0, a.length - 1);
out.println(min);
out.flush();
}
}
static void arrange(int a[], int start, int end) {
if (start == end) {
// for(int i:a)
// {
// System.out.print(i);
// }
// System.out.println();
if ((a[0] == 0 && mid == 1) || (a[mid] == 0 && a.length - mid == 0) || (a[0] != 0 && a[mid] != 0)) {
int va1 = 0;
int va2 = 0;
for (int i = 0; i < mid; i++) {
va1 = va1 * 10 + a[i];
}
for (int i = mid; i < a.length; i++) {
va2 = va2 * 10 + a[i];
}
min = min < Math.abs(va1 - va2) ? min : Math.abs(va1 - va2);
}
return;
}
for (int i = start; i <= end; i++) {
swap(a, start, i);
arrange(a, start + 1, end);
swap(a, start, i);
}
}
static void swap(int arr[], int i, int j) {
int te = arr[i];
arr[i] = arr[j];
arr[j] = te;
}
}
dfs回溯法github链接https://github.com/javasmall/oj-problem-java/blob/master/%E6%A8%A1%E6%9D%BF/src/%E5%85%A8%E6%8E%92%E5%88%97/quanpailie1.java
递归法全排列github链接 https://github.com/javasmall/oj-problem-java/blob/master/%E6%A8%A1%E6%9D%BF/src/%E5%85%A8%E6%8E%92%E5%88%97/quanpailie2.java
poj2718代码github链接 https://github.com/javasmall/oj-problem-java/blob/master/poj/src/%E6%90%9C%E7%B4%A2/poj2718.java
如有错误还请大佬指正。