[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));
        }
    }
}
posted @ 2021-06-23 22:36  ACBingo  阅读(26)  评论(0编辑  收藏  举报