前言
通过对字符串的全排列,来理解回溯。
一、全排列
1、例题
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
示例:
输入:s = “abc”
输出:[“abc”,“acb”,“bac”,“bca”,“cab”,“cba”]
2、题解
A.回溯
通过StringBuilder来回溯拼接字符,通过HashSet来去重。
class Solution {
int[] visited;
Set<String> list = new HashSet<>();
StringBuilder sb = new StringBuilder();
public String[] permutation(String s) {
int len = s.length();
visited = new int[len];
//每一个字符都作为起点
for (int i = 0; i < len; i++) {
dfs(s, i);
visited[i] = 0;
sb.delete(0, sb.length());
}
//得到set中的元素
String[] res = new String[list.size()];
int count = 0;
for (String str : list) {
res[count++] = str;
}
return res;
}
//递归组合字符
private void dfs(String s, int i) {
sb.append(s.charAt(i));
visited[i] = 1;
//递归出口,拼接完毕
if (sb.length() == s.length()) {
list.add(sb.toString());
return;
}
//循环递归
for (int j = 0; j < s.length(); j++) {
if (visited[j] == 0) {
dfs(s, j);
visited[j] = 0;
sb.delete(sb.length() - 1, sb.length());
}
}
return;
}
}
B.递归排列
class solutionForSearch {
List<String> res = new LinkedList<>();
char[] chs;
public String[] permutation(String s) {
chs = s.toCharArray();
dfs(0);
return res.toArray(new String[res.size()]);
}
/**
* 私有递归去全排列
* @param x,当前在那一层排列
*/
private void dfs(int x) {
if (x == chs.length - 1) {
//如果要把数组里的元素连接成字符串,还是得String.valueOf();Arrays.toString(T[] t)是将元素按照数组的原样变成字符串。
res.add(String.valueOf(chs));
return;
}
//是否重复判断,用于后面的剪枝。
Set<Character> set = new HashSet<>();
for (int i = x; i < chs.length; i++) {
//在此层,已经有该元素开头的,需剪枝。
if (set.contains(chs[i])) continue;
set.add(chs[i]);
//递归前的变形
swap(x, i);
//开始递归
dfs(x + 1);
//递归完毕,恢复原样,毕竟这里时类属性,而不是局部变量。
swap(i, x);
}
}
/**
* 私有交换方法
* @param index1,需交换元素位置之一
* @param index2,需交换元素位置之一
*/
private void swap(int index1, int index2) {
char temp = chs[index1];
chs[index1] = chs[index2];
chs[index2] = temp;
}
}
总结
1)回溯、剪枝
参考文献
[1] Leetcode 原题
[2] Leetcode 解答1
[3] Leetcode 解答2