1、题目描述
输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组。
例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。
2、算法分析
回溯算法有组合,排序,子集,棋盘如N皇后等等。其实基本上理解就是递归的应用。本题属于排序。而且是字符串中字符的排序,还有数字的排序,其实都是一样的。序列中的是否重复元素看清楚题目。
这是一道排序算法题,回溯算法中的一种。
回溯算法其实是基于递归算法的,在递归的基础上回溯。注意,子结点向父节点进行回溯。
模板:
void backtracking(参数) { if (终止条件) { 存放结果; return; } for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) { 处理节点; backtracking(路径,选择列表); // 递归 回溯,撤销处理结果 } }
回溯算法可以看成一个树型的结构。
①首先创建结果集合ArrayList,和StringBuilder存储每一个符合条件的路径。
②因为序列是经过拍过序的,所以比较每一层的ch[i] == ch[i-1],且used[i-1] == false说明元素在该层没有出现过。已经出现过的元素直接跳过,比如1,2,1,第一个1和第二个1都是重复的。
③重点来了:
// 如果元素没有出现过 if(used[i] == false){ // 设置为true代表已出现 used[i] = true; // 集合中的path sb.append(String.valueOf(ch[i])); // 递归 backTracking(ch,used); // 回溯,子结点向父节点回溯 sb.deleteCharAt(sb.length()-1); // 因为是排序,后面的序列还要用,设置成false; used[i] = false; }
直接看代码:
3、代码实现
import java.util.*;
public class Solution {
// 定义结果集
ArrayList<String> result = new ArrayList<>();
// 定义路径
StringBuilder sb = new StringBuilder();
public ArrayList<String> Permutation(String str) {
char[] ch = str.toCharArray();
// 对字符进行排序
Arrays.sort(ch);
// 定义元素是否使用过,used数组中默认值是false;
boolean[] used = new boolean[ch.length];
backTracking(ch,used);
return result;
}
// 回溯函数
public void backTracking(char[] ch,boolean[] used){
if(sb.toString().length() == ch.length){
result.add(sb.toString());
}
for(int i = 0;i < ch.length;i++){
// 遍历每一层
if(i > 0 && ch[i] == ch[i-1] && used[i - 1] == false){
continue;
}
// 如果元素没有出现过
if(used[i] == false){
// 设置为true代表已出现
used[i] = true;
// 集合中的path
sb.append(String.valueOf(ch[i]));
// 递归
backTracking(ch,used);
// 回溯,子结点向父节点回溯
sb.deleteCharAt(sb.length()-1);
// 因为是排序,后面的序列还要用,设置成false;
used[i] = false;
}
}
}
}