无重复字符串的排列组合

题目描述

来源于 https://leetcode-cn.com/

无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。

示例1:

 输入:S = "qwe"
 输出:["qwe", "qew", "wqe", "weq", "ewq", "eqw"]

示例2:

 输入:S = "ab"
 输出:["ab", "ba"]

提示:

  1. 字符都是英文字母。
  2. 字符串长度在[1, 9]之间。

解法一:迭代

考虑字符集合{a,b,c},首先取一个字符 a 构成字符串 a,然后在取一个字符,在先前构成的字符串的各个位置插入 b,就可以得到新的字符串。 同理,在前一步生成的各个字符串的各个位置插入字符 c,又可以得到大量新的字符串。

a

ab
ba

cab
acb
abc
cba
bca
bac

基于以上分析,可以写出如下代码:

class Solution {
public:
    vector<string> permutation(string s) {
        vector<string> result;
        result.push_back("");

        for(char ch: s){
            vector<string> new_result;
            for(const string& perm: result){
                for(int i = 0; i <= perm.size(); i++){
                    string next_perm = perm;
                    next_perm.insert(i, 1, ch);
                    new_result.push_back(std::move(next_perm));
                }
            }
            result = std::move(new_result);
        }
        return result;
    }
};

解法二:回溯法

采用回溯法,首先可以在所有字符中选择一个作为第一个字符,然后余下的字符中选择第二个,…直到没得选,这样就得到了一个排列组合了。

class Solution {
public:
    vector<string> permutation(string s) {
        vector<string> result;
        vector<bool> visited(s.size(), false);
        string path;
        dfs(path, s, visited, result);
        return result;
    }

    void dfs(string& path, const string &s, vector<bool>& visited, vector<string>& result){
        if(path.size() == s.size()){
            result.push_back(path);
            return;
        }
        
        for(int i = 0; i < s.size(); i++){
            if(visited[i]){
                continue;
            }
            visited[i] = true;
            path += s[i];
            dfs(path, s, visited, result);
            visited[i] = false;
            path.pop_back();
        }
    }
};

解法三:下一个排列组合

先排序,让字符串中各个字符呈现升序排列。然后不断调用 next_permutation,得到所有的组合。关于 next_permutation 的详细解释可以参考 下一个排列

class Solution {
public:
    vector<string> permutation(string s) {
        vector<string> ret;        
        sort(s.begin(), s.end());
        ret.push_back(s);
        while(next_permutation(s)){
            ret.push_back(s);
        }
        return ret;
    }

    bool next_permutation(string& s){
        int i = s.size() - 2;
        while(i >= 0 && s[i] >= s[i+1]){
            i--;
        }
        if(i < 0){
            return false;
        }
        int j = s.size() - 1;
        while(j >= 0 && s[j] <= s[i]){
            j--;
        }
        ::swap(s[i], s[j]);
        reverse(s.begin()+i+1, s.end());
        return true;
    }
};