题目描述:将一个数组全排列后输出。
eg1:{“a”,“b”,“c”} ——>[a, b, c]、[a, c, b]、[b, a, c]、[b, c, a]、[c, a, b]、[c, b, a]
eg2:{"a", "c", "c", "d",} ——> 如下所示:
[a, c, c, d][a, c, d, c]
[a, d, c, c]
[c, c, a, d]
[c, c, d, a]
[c, a, c, d]
[c, a, d, c]
[c, d, a, c]
[c, d, c, a]
[d, c, c, a]
[d, c, a, c]
[d, a, c, c]
说明:当数组中有元素重复的时候,需要将排序后重复的数组给去除。
前言:关于数组的全排列网上的教程很多,可是大部分都没有处理重复元素的问题,这里我将我的思路及实现分享出来,望多多指教。
分析:当我们实现数组的全排列时,我们
1、将第一个元素和最后一个元素做交换,就可以得到一种数组排列。
2、将第二个元素和最后一个元素做交换,就可以得到一种数组排列。
…………………………
n、将第n个元素和最后一个元素做交换,即可得到一种数组排列。
通过以上分析,我们可以使用递归的思想来进行全排列,递归出口为:当 n==array.length 时递归结束。
方案一:
1、FullArangement类:核心类,主要实现数组的全排列等功能。
package stu.kx.test1_FullArrangement; import java.util.Arrays; /** * * @author 康茜 *全排列: *将数组中的元素全排列(不能去除重复的元素) * *需要去除重复的元素;既然元素值是重复的,那么我们可以将问题简化,将问题分解成去除数组中重复元素和全排列数组两部分; */ public class FullArrangement { public static void doFullArrangement(String[] array) { getAllOrder(array, 0, array.length); } /** * * @param start 从start开始,到end结束来全排列数组 * @param end */ private static void getAllOrder(Object[] array, int start, int end) { if(start == end) { System.out.println(Arrays.toString(array));//使用Arrays工具类遍历输出数组元素 } else { for(int i = start; i < end; i++) { swap(array, start, i); getAllOrder(array, start + 1, end); swap(array, i, start); } } } //数组中的两个元素交换位置 private static void swap(Object[] array, int i, int j) { if(i == j) { return; } Object temp = array[i]; array[i] = array[j]; array[j] = temp; } }
2、测试类:
package stu.kx.test1_FullArrangement; public class Test { public static void main(String[] args) { String[] array = {"a","c","c","d"}; FullArrangement.doFullArrangement(array); } }
3、测试结果:
从以上输出结果来看,如果数组中含有重复的元素,则输出结果中会有重复的输出结果,可是我们所预期的结果并不是这样,那么我们来看看方案二。
方案二:
思路:在原先的解题思路上,增加了一个静态list<String> 该list中存储着本次全排列每次输出的数组排列的字符串形式,在每次输出之前判断该list中是否包含该数组的字符串形式,来判断结果是否重复,若重复,则不进行输出,否则,则输出。
1、FullArrangement类(核心类):处理全排列问题及结果重复问题。
package stu.kx.test1_FullArrangement; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * * @author 康茜 *全排列(去除重复排序数组的全排序):——全排列的java实现(无重复元素) * *需要去除重复的元素;既然元素值是重复的,那么我们可以将问题简化,将问题分解成去除数组中重复元素和全排列数组两部分; */ public class FullArrangement1 { private static List<String> list = new ArrayList<>(); public static void doFullArrangement(String[] array) { /* * 清空list,因为此list是静态的,因此每次排序时都需要清空,否则的话若重复调用排序的方法的话将不会去除重复的排序 */ list.removeAll(list); getAllOrder(array, 0, array.length); } /** * * @param start 从start开始,到end结束来全排列数组 * @param end */ private static void getAllOrder(Object[] array, int start, int end) { if(start == end) { //将数组转换成字符串,通过判断list中是否包含该字符串(数组的字符串形式) 来 判断该数组有没有被输出过,从而 //去除重复的数组排序。 String arrayStr = Arrays.toString(array); if(!list.contains(arrayStr)) { list.add(arrayStr); } else { System.out.println(arrayStr); } return; //System.out.println(Arrays.toString(array));//使用Arrays工具类遍历输出数组元素 } else { for(int i = start; i < end; i++) { swap(array, start, i); getAllOrder(array, start + 1, end); swap(array, i, start); } } } //数组中的两个元素交换位置 private static void swap(Object[] array, int i, int j) { if(i == j) { return; } Object temp = array[i]; array[i] = array[j]; array[j] = temp; } }
2、测试类。
package stu.kx.test1_FullArrangement; public class Test { public static void main(String[] args) { String[] array = {"a","c","c","d"}; FullArrangement1.doFullArrangement(array); } }
3、测试结果。
结果:从测试结果可以看出,全排列的结果不存在重复的结果。