【回溯】【leetcode】字符串全排列(4题)

题目1:有重复字符全排列

输入一个字符串,打印出该字符串中字符的所有排列。

你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。

示例:

输入:s = "abc"
输出:["abc","acb","bac","bca","cab","cba"]

来源

剑指 Offer 38. 字符串的排列

面试题 08.08. 有重复字符串的排列组合

解题思路:回溯

同 有重复数字全排列 ,注意输入字符串有重复字符,代码如下,不做解释。

class Solution {
public:
    vector<string> result;
    string path;
    vector<string> permutation(string s) {
        vector<bool> used(s.size(), false);
        sort(s.begin(), s.end());
        back(s, used);
        return result;
    }
    void back(const string& s, vector<bool>& used) {
        if (path.size() == s.size()) {
            result.push_back(path);
            return;
        }
        for (int i = 0; i < s.size(); i++) {
            if (used[i]) continue; // 字符已使用,则跳过,
            used[i] = true;
            path.push_back(s[i]);
            back(s, used);
            path.resize(path.size() - 1);
            used[i] = false;
            while (i+1 < s.size() && s[i+1] == s[i]) i++; // 跳过相同字符
        }
    }
};

题目2:无重复字符全排列

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

示例1:

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

来源:面试题 08.07. 无重复字符串的排列组合

解题思路:回溯

在题目1代码基础上去掉排序和跳过重复字符两行代码即可。同 无重复数字全排列

class Solution {
public:
    vector<string> result;
    string path;
    vector<string> permutation(string s) {
        vector<bool> used(s.size(), false);
        back(s, used);
        return result;
    }
    void back(const string& s, vector<bool>& used) {
        if (path.size() == s.size()) {
            result.push_back(path);
            return;
        }
        for (int i = 0; i < s.size(); i++) {
            if (used[i]) continue;
            used[i] = true;
            path.push_back(s[i]);
            back(s, used);
            path.resize(path.size() - 1);
            used[i] = false;
        }
    }
};

题目3:字符串大小写所有情况

给定一个字符串S,通过将字符串S中的每个字母转变大小写,我们可以获得一个新的字符串。返回所有可能得到的字符串集合。

示例:
输入:S = "a1b2"
输出:["a1b2", "a1B2", "A1b2", "A1B2"]

输入:S = "3z4"
输出:["3z4", "3Z4"]

输入:S = "12345"
输出:["12345"]

来源:784. 字母大小写全排列

解题思路:回溯

递归调用时,遇到字母会有大小写两种情况,其他1种情况。

class Solution {
public:
    vector<string> result;
    string path;
    vector<string> letterCasePermutation(string S) {
        back(S, 0);
        return result;
    }
    void back(const string& s, int start) {
        if (start == s.size()) {
            result.push_back(path);
            return;
        }
        // 构造可能情况,记录于cand数组。
        char ch = s[start];
        char cand[2];
        int n = 0;
        cand[n++] = ch;
        if (ch >= 'a' && ch <= 'z') {
            cand[n++] = ch - 'a' + 'A';
        } else if (ch >= 'A' && ch <= 'Z') {
            cand[n++] = ch - 'A' + 'a';
        }
        // 遍历所有可能情况
        for (int i = 0; i < n; i++) {
            path.push_back(cand[i]);
            back(s, start+1);
            path.resize(path.size() - 1);
        }
    }
};

题目4:重复字符串中任意字符的所有排列

你有一套活字字模 tiles,其中每个字模上都刻有一个字母 tiles[i]。返回你可以印出的非空字母序列的数目。

注意:本题中,每个活字字模只能使用一次。

示例 1:

输入:"AAB"
输出:8
解释:可能的序列为 "A", "B", "AA", "AB", "BA", "AAB", "ABA", "BAA"。
示例 2:

输入:"AAABBC"
输出:188

来源:1079. 活字印刷

解题思路:回溯

tiles中任选k个字符的全排列,k从1遍历到N。

class Solution {
public:
    int result;
    string path;
    int numTilePossibilities(string tiles) {
        vector<bool> used(tiles.size(), false);
        sort(tiles.begin(), tiles.end());
        for (int i = 0; i < tiles.size(); i++) {
            back(tiles, used, i+1);
        }
        return result;
    }
    // 任取k个字符的全排列
    void back(const string& s, vector<bool>& used, int k) {
        if (path.size() == k) {
            result++;
            return;
        }
        for (int i = 0; i < s.size(); i++) {
            if (used[i]) continue; // 字符已使用,则跳过,
            used[i] = true;
            path.push_back(s[i]);
            back(s, used, k);
            path.resize(path.size() - 1);
            used[i] = false;
            while (i+1 < s.size() && s[i+1] == s[i]) i++; // 跳过相同字符
        }
    }
};

猜你喜欢

转载自blog.csdn.net/hbuxiaoshe/article/details/115176996