1. 程式人生 > 其它 >[LeetCode] 劍指 Offer 38. 字串的排列

[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));
        }
    }
}