有重复全排列解题思路:
整体思路:可以把一个字符串看成两部分组成,第一部分为第一个字符,第二部分是后面的所有字符。这是典型的分治思想,可以用递归实现。
整体思路:可以把一个字符串看成两部分组成,第一部分为第一个字符,第二部分是后面的所有字符。这是典型的分治思想,可以用递归实现。
具体来说:第一步首先求所有可能出现在第一个位置上的字符,即把第一个字符和后面的所有的字符(包括第一个字符)进行交换。因字符串中可能有重复的字符,因此在交换前,需要判断从当前字符串的开始位置start到待交换位置end之前,是否有字符和end指向的字符相等,若有,则不进行交换,等到递归到那个字串的时候在进行交换,否则在结果中会出现重复元素。第二步固定第一个字符,求后面所有字符的全排列,过程同上。
import java.util.ArrayList;
import java.util.Collections;
public class Solution {
public static ArrayList<String> Permutation(String str) {
ArrayList<String> arrayList = new ArrayList<>();
if (str == null || str.length() == 0) {
return arrayList;
}
char[] charArray = str.toCharArray();
int start = 0;
int end = charArray.length - 1;
arrayList = Permutation(charArray,start,end,arrayList);
Collections.sort(arrayList);
return arrayList;
}
/**
* 从start到end-1之间有没有元素和end指向元素相同,若有,则不进行交换,因为在此之前肯定进行了交换
*/
private static boolean isSwap(char[] charArray, int start, int end) {
for (int i = start; i < end; i++) {
if (charArray[i] == charArray[end]) {
return false;
}
}
return true;
}
private static ArrayList<String> Permutation(char[] charArray,int start, int end, ArrayList<String> arrayList) {
if (start == charArray.length - 1) {
//递归地结束条件
String str = String.valueOf(charArray);
arrayList.add(str);
return arrayList;
}
for (int i = start; i < charArray.length; i++) {
//如果在start到i-1之间,i元素已经出现过,则此时无需交换,因为在此之前已经交换了,避免重复
if (!isSwap(charArray, start, i)) {
continue;
}
swap(charArray, start, i);
Permutation(charArray, start + 1, end,arrayList);
swap(charArray, start, i);
}
return arrayList;
}
private static void swap(char[] charArray, int i, int j) {
char temp = charArray[i];
charArray[i] = charArray[j];
charArray[j] = temp;
}
public static void main(String[] args) {
String s = "abab";
ArrayList<String> list = Permutation(s);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}