目录
题目地址:
难度:中高难度
今天刷套餐内商品的排列顺序(字符串的排列),大家有兴趣可以点上看看题目要求,试着做一下。
我们直接看题解吧:
解题方法:
这里主要用递归算法(回溯)
难度分析:
虽然官方给的是中等难度,但个人感觉挺难的,应该算中高难度,利用了递归方法以及深度搜索
审题目+事例+提示:
返回的是字符串数组,不能有重复,无返回顺序要求
解题思路:
采用分解的办法:
把第一个字符与与后面的字符进行交换(即求出所有可能在第一个位置的字符)
依次逐位固定一个字符,求后面所以字符的排列
去除重复元素,返回对应字符串集合
代码实现:
class Solution {
//为了让递归函数添加结果方便,定义到函数之外,这样无需带到递归函数的参数列表中
List<String> list = new ArrayList<>();
//同;但是其赋值依赖c,定义声明分开
char[] c;
public String[] permutation(String s) {
c = s.toCharArray();
//从第一层开始递归
dfs(0);
//将字符串数组ArrayList转化为String类型数组
return list.toArray(new String[list.size()]);
}
private void dfs(int x) {
// 当 x = len(arr) - 1 时,代表所有位已固定(最后一位只有 1 种情况),
//则将当前组合 arr 转化为字符串并加入 res ,并返回
if (x == c.length - 1) {
//将字符数组转换为字符串
list.add(String.valueOf(c));
return;
}
//为了防止同一层递归出现重复元素
HashSet<Character> set = new HashSet<>();
//这里就很巧妙了,第一层可以是a,b,c那么就有三种情况,
//这里i = x,正巧dfs(0),正好i = 0开始
// 当第二层只有两种情况,dfs(1)i = 1开始
for (int i = x; i < c.length; i++){
//发生剪枝,当包含这个元素的时候,直接跳过
if (set.contains(c[i])){
continue;
}
set.add(c[i]);
//交换元素,这里很是巧妙,当在第二层dfs(1),x = 1,
//那么i = 1或者 2, 不是交换1和1,要就是交换1和2
swap(i,x);
//进入下一层递归
dfs(x + 1);
//返回时交换回来,这样保证到达第1层的时候,一直都是abc。
//这里捋顺一下,开始一直都是abc,那么第一位置总共就3个交换
//分别是a与a交换,这个就相当于 x = 0, i = 0;
// a与b交换 x = 0, i = 1;
// a与c交换 x = 0, i = 2;
//就相当于上图中开始的三条路径
//第一个元素固定后,每个引出两条路径,
// b与b交换 x = 1, i = 1;
// b与c交换 x = 1, i = 2;
//所以,结合上图,在每条路径上标注上i的值,就会非常容易好理解了
swap(i,x);
}
}
private void swap(int i, int x) {
char temp = c[i];
c[i] = c[x];
c[x] = temp;
}
}