トピック:
ブラケット。n組の括弧のすべての正当な(たとえば、開いた1対1の対応)組み合わせを出力するアルゴリズムを設計します。
注:ソリューションセットに重複するサブセットを含めることはできません。
たとえば、n = 3の場合、生成される結果は次のようになります。
[
"((()))"、
"(()())"、
"(())()"、
"()(())"、
"()()()"
]
ソース:
問題解決のアイデア:バックトラック
左と右の2つの変数を定義します。左は「(」の数を記録し、右は「)」の数を記録します。
- 再帰的終了条件:左括弧を最初に終了する必要があるため、右括弧が終了すると終了します
- 再帰呼び出し条件:左右の現在の状況に応じて、次のキャラクターの可能な状況を判断します
public:
vector<string> result;
string path;
vector<string> generateParenthesis(int n) {
back(n, 0, 0);
return result;
}
void back(int n, int left, int right) {
if (right == n) {
// 返回结果
result.push_back(path);
return;
}
// 找出所有可能情况
char cand[2];
int sz = 0;
if (left < n) {
cand[sz++] = '(';
}
if (left > right) {
cand[sz++] = ')';
}
// 处理每种可能情况
for (int i = 0; i < sz; i++) {
path.push_back(cand[i]);
if (cand[i] == '(')
back(n, left+1, right);
else
back(n, left, right+1);
path.resize(path.size() - 1);
}
}
};
別の考え方として、コードは次のように、より簡潔になっています。
2つの変数、leftは左括弧の残りの数を記録し、rightは右括弧の残りの数を記録します。考えられる状況は2つあります。
- 左括弧、残りがある場合は処理
- 左括弧が左で、左括弧が小さい場合の右括弧。
class Solution {
public:
vector<string> result;
string path;
vector<string> generateParenthesis(int n) {
back(n, n);
return result;
}
// left记录左括号剩余数量,right记录右括号剩余数量
void back(int left, int right) {
if (left == 0 && right == 0) {
result.push_back(path);
return;
}
// 无非2种可能情况
if (left > 0) {
// 情况1
path.push_back('(');
back(left-1, right);
path.resize(path.size() - 1);
}
if (left < right && right > 0) {
// 情况2
path.push_back(')');
back(left, right - 1);
path.resize(path.size() - 1);
}
}
};