题目1:有重复字符全排列
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
示例:
输入:s = "abc"
输出:["abc","acb","bac","bca","cab","cba"]
来源:
解题思路:回溯
同 有重复数字全排列 ,注意输入字符串有重复字符,代码如下,不做解释。
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"]
解题思路:回溯
在题目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"]
解题思路:回溯
递归调用时,遇到字母会有大小写两种情况,其他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++; // 跳过相同字符
}
}
};