[LeetCode] 剑指 Offer 38. 字符串的排列
回溯DFS
但是该递归函数并没有满足「全排列不重复」的要求,在重复的字符较多的情况下,该递归函数会生成大量重复的排列。对于任意一个空位,如果存在重复的字符,该递归函数会将它们重复填上去并继续尝试导致最后答案的重复。
解决该问题的一种较为直观的思路是,我们首先生成所有的排列,然后进行去重。而另一种思路是我们通过修改递归函数,使得该递归函数只会生成不重复的序列。
具体地,我们只要在递归函数中设定一个规则,保证在填每一个空位的时候重复字符只会被填入一次。具体地,我们首先对原字符串排序,保证相同的字符都相邻,在递归函数中,我们限制每次填入的字符一定是这个字符所在重复字符集合中「从左往右第一个未被填入的字符」,即如下的判断条件:
if (vis[j] || (j > 0 && !vis[j - 1] && s[j - 1] == s[j])) {
continue;
}
这个限制条件保证了对于重复的字符,我们一定是从左往右依次填入的空位中的。
class Solution {
public String[] permutation(String s) {
List<Character> notUsed = new ArrayList<>();
for (int i=0;i<s.length();i++) {
notUsed.add(s.charAt(i));
}
Set<String> ans = new HashSet<>();
dfs(ans, notUsed, "");
String[] arr = new String[ans.size()];
return ans.toArray(arr);
}
public void dfs(Set<String> ans, List<Character> notUsed, String cur) {
if (notUsed.size() == 0) {
ans.add(cur);
return;
}
for (int i=0;i<notUsed.size();i++) {
List<Character> newList = new ArrayList<>(notUsed);
newList.remove(i);
dfs(ans, newList, cur + notUsed.get(i));
}
}
}