【LeetCode-784】字母大小写全排列
问题
给定一个字符串S,通过将字符串S中的每个字母转变大小写,我们可以获得一个新的字符串。返回所有可能得到的字符串集合。
示例
输入: S = "a1b2"
输出: ["a1b2", "a1B2", "A1b2", "A1B2"]
解答1:DFS
class Solution {
public:
vector<string> letterCasePermutation(string S) {
dfs(S, 0);
return res;
}
private:
vector<string> res;
void dfs(string& S, int pos) {
if (S.size() == pos) {
res.push_back(S);
return;
}
dfs(S, pos + 1); // 为数字或字母不改变大小写
if (isalpha(S[pos])) {
S[pos] ^= 32; // 字母改变大小写
dfs(S, pos + 1);
}
}
};
重点思路
DFS的精髓是change - explore - unchange
,本题需要explore的地方即大小写。
其中改变大小写的方法需要注意。小写转大写需要减去32,大写转小写需要加上32,而32的二进制表示为100000
,所以只需要在二进制的第5位做无进位的加法(异或)即可。
解答2:不考虑数字的二进制
class Solution {
public:
vector<string> letterCasePermutation(string S) {
int cnt = 0;
vector<string> res;
for (char ch : S) // 统计字母数量
if (isalpha(ch)) cnt++;
for (int mask = 0; mask < (1 << cnt); mask++) {
string ans;
int mv = 0;
for (char ch : S) {
if (isdigit(ch)) ans += ch;
else {
if (mask & (1 << mv++)) ans += ch ^ 32; // mask当前位为1时变大小写
else ans += ch;
}
}
res.push_back(ans);
}
return res;
}
};
解答3:考虑数字的二进制
class Solution {
public:
vector<string> letterCasePermutation(string S) {
int n = S.size(), k = 0;
vector<string> res;
for (int i = n - 1; i >= 0; i--) { // 反向遍历保证后续取值方便
k <<= 1;
if (isalpha(ch)) k |= 1; // 使用二进制标记当前位是否为字母
}
int sub = k;
do {
string ans = S;
for (int i = 0; i < n; i++)
if (sub & (1 << i)) ans[i] ^= 32;
res.push_back(ans);
sub = (sub - 1) & k; // 注意此处取子集的方式
} while (sub != k);
return res;
}
};
重点思路
本题取子集的方式比较特殊,相较于解答2也更加的通用。例如,它能取100101的所有子集,而解答2的取子集方法只能取得全1二进制(类似11111)的所有子集。