1、题目:面试题 08.08. 有重复字符串的排列组合
2、思路
-
利用set集合
前面逻辑同面试题 08.07. 无重复字符串的排列组合,利用set集合的不可重复性,将所有排列组合都放入set集合中,set集合会将重复的去掉,但是会遍历所有的排列组合,时间复杂度高。
-
剪枝
当该位置上面的字符在之前已经填入过相同的字符时,就不需要再填入这个字符,就将这个字符的分支去掉。
3、代码
-
利用set集合
class Solution {
// set集合去重
private Set<String> res = new HashSet<>();
public String[] permutation(String S) {
char[] cs = S.toCharArray();
dfs(cs, 0);
return res.toArray(new String[0]);
}
private void dfs(char[] cs, int index) {
if (index == cs.length - 1) {
res.add(new String(cs));
return;
}
for (int i = index; i < cs.length; i++) {
swap(cs, index, i);
dfs(cs, index + 1);
swap(cs, index, i);
}
}
/**
* 交换数组中的两个元素
*/
private void swap(char[] cs, int i, int j) {
char temp = cs[i];
cs[i] = cs[j];
cs[j] = temp;
}
}
-
剪枝(进阶)
class Solution {
private List<String> res = new ArrayList<>();
private Set[] set;
public String[] permutation(String S) {
char[] cs = S.toCharArray();
this.set = new Set[cs.length];
for (int i = 0; i < set.length; i++) {
set[i] = new HashSet();
}
dfs(cs, 0);
return res.toArray(new String[0]);
}
private void dfs(char[] cs, int index) {
if (index == cs.length - 1) {
res.add(new String(cs));
return;
}
for (int i = index; i < cs.length; i++) {
// 判断该位置是否已经使用过cs[i]字符了
if (!set[index].contains(cs[i])) {
swap(cs, index, i);
// 表示该字符已经出现在该位置上了, 下次遍历到相同字符直接跳过
set[index].add(cs[index]);
dfs(cs, index + 1);
swap(cs, index, i);
}
}
// 该位置已经遍历所有字符, 将标识数组回溯到初始状态
set[index].clear();
}
/**
* 交换数组中的两个元素
*/
private void swap(char[] cs, int i, int j) {
char temp = cs[i];
cs[i] = cs[j];
cs[j] = temp;
}
}