解题思路
我们先说说如果没有重复字母该怎么做
以"abc"为例
1.先将a固定住abc; 求bc的全排列 得 abc,acb
2.a和b交换:bac; 求ac的全排列 得bac,bca
3.a和c交换不过先要把b和a交换回来 cba 求ba的全排列得cba,cab
整个过程我们可以递归求解
递归思路
假设求以i为开头的全排列
遍历字符串数组 以当前i为首 依次与后面的元素交换 然后求i+1为开头的全排列 最后还要交换回来。
递归终止条件就是 当遍历到chs.length-1时 只有一个元素 我们得到一个全排列结果
如果有重复元素该怎么做呢
假设字符串“abb”
我们先以a为开头 依次和b,b交换 求全排列 这样就会有重复现象
当a与b交换后 再次遇到b 就不用交换了
我们可以用hash表 交换一个元素后放进hash表
每次交换前判断hash表有没有该元素 如果没有才交换
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @Description:
* @Author: heart
* @Date: 2020/7/20
*/
public class Permutation {
public ArrayList<String> Permutation(String str) {
ArrayList<String> res = new ArrayList();
if (str == null || str.length() == 0) {
return res;
}
PermutationHelper(str.toCharArray(), 0, res);
Collections.sort(res);
// System.out.println(res);
return res;
}
private void PermutationHelper(char[] str, int n, List<String> res) {
if (n == str.length) {
res.add(String.valueOf(str));
}
int i = n;
//第一次循环i与j相等,相当于第一个位置自身交换,关键在于之后的循环,
// 之后i != j,则会交换两个不同位置上的字符,直到j==str.length-1,进行输出;
for (int j = i; j < str.length; j++) {
if (i != j && str[i] == str[j]) {
continue;
}
swap(str, i, j);
PermutationHelper(str, i + 1, res);
// 复位,用以恢复之前字符串顺序,达到第一位依次跟其他位交换的目的
swap(str, i, j);
}
}
/**
* 交换字符串中的两个字符
*/
private void swap(char[] str, int i, int j) {
char temp = str[i];
str[i] = str[j];
str[j] = temp;
}
public static void main(String[] args) {
String str="abc";
Permutation permutation = new Permutation();
permutation.Permutation(str);
System.out.println(permutation.Permutation(str));
}
}
收获
1.要对字符串进行修改,可以将字符串转化为字符数组进行修改,也可以考虑使用StringBuilder类。
2.list.contains()方法可以直接判断是否有重复字符串;Collections.sort(list)可以将list中的字符串进行排序。
3.字符串和字符数组间的转化:str.toCharArray() String.valueOf(strArray)
4.数组在递归过程中进行了交换后,最终要记得交换回来(代码最后几行)