トピック1:すべての反復文字が配置されます
文字列を入力し、文字列内の文字のすべての順列を出力します。
この文字列配列は任意の順序で返すことができますが、重複する要素を含めることはできません。
例:
到入:s = "abc"
輸出出:["abc"、 "acb"、 "bac"、 "bca"、 "cab"、 "cba"]
出典:
インタビューの質問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のコードに基づいて、繰り返される文字を並べ替えてスキップするための2行のコードを削除します。ノー繰り返しデジタルフルアライメント。
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"]
問題解決のアイデア:バックトラック
再帰的に呼び出す場合、大文字と小文字の2つのケースと、もう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:文字列内の任意の文字のすべての順列を繰り返す
活字フォントタイルのセットがあり、それぞれに文字タイルが刻印されています[i]。印刷できる空でない文字シーケンスの数を返します。
注:この質問では、各タイプは1回しか使用できません。
例1:
入力: "AAB"
出力:8
説明:可能なシーケンスは、 "A"、 "B"、 "AA"、 "AB"、 "BA"、 "AAB"、 "ABA"、 "BAA"です。
例2:
入力:「AAABBC」
出力:188
出典:1079。活字印刷
問題解決のアイデア:バックトラック
タイル内の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++; // 跳过相同字符
}
}
};