LeetCode 第二十二题 括号生成
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
方法一
使用暴力的方法,将所有的括号组合都列举出来,再判断是否符合括号生成的规则。
这里我们使用了一个递归函数,函数首先判断当前生成括号长度是否达到n*2
,如果长度满足要求,判断其是否符合括号生成规则,如果符合,将其加入,否则舍弃
如果长度没有达到n*2,添加‘(’和‘)’,递归代码。
在判断其是否符合括号生成规则时,使用一个balance因子,如果是‘(’,balanle自增,如果是‘)’,balance自减,需要注意的是,balance如果小于零,直接返回false,这是因为避免了防止类似于“)(”这种情况
Java
public List<String> generateParenthesis(int n) {
List<String> result = new ArrayList<>();
generateAll(new char[n * 2], 0, result);
return result;
}
public void generateAll(char[] current, int pos, List<String> result) {
if (pos == current.length) {
if (valid(current)) {
result.add(new String(current));
}
} else {
current[pos] = '(';
generateAll(current, pos + 1, result);
current[pos] = ')';
generateAll(current, pos + 1, result);
}
}
public boolean valid(char[] current) {
int balance = 0;
for (char c : current) {
if (c == '(') {
balance++;
} else {
balance--;
}
if (balance < 0)
return false;/// 防止类似于“)(”这种情况
}
return (balance == 0);
}
C++
小问题
在将Java代码转换到C++过程中,遇到了这样一个问题:char current[]字符串数组在Java中可以直接求出其长度,而在c++中,我们只能使用sizeof()函数或者strlen()函数求其长度。
sizeof()可以求其长度,但当我们将char current[]传入到void generateAll(char current[],int pos,vector<string>& result)
时,此时的current就变成一个指针了,使用sizeof()得到的长度始终为4。
strlen()求其长度,strlen()得到的是从第一个字符到’\0’直接的长度,如果字符串中本来就有’\0’,那么我们得到的长度就是错误。
解决办法
使用strlen()求其长度,在char current[]初始化时,为其添加一些字符,如下所示:
for(int i=0; i<n*2; i++)
current[i]='*';
current[n*2]='\0';
这样以来,成功的解决了问题,当然,如果你有更好的方法,也可以互相交流。
下面是C++完整代码。
class Solution
{
public:
vector<string> generateParenthesis(int n)
{
vector<string> result = vector<string>();
char current[n*2+1];
for(int i=0; i<n*2; i++)
current[i]='*';
current[n*2]='\0';
generateAll(current,0,result);
return result;
}
void generateAll(char current[],int pos,vector<string>& result)
{
if(strlen(current)==pos)
{
if(valid(current))
{
result.push_back(current);
}
}
else
{
current[pos]='(';
generateAll(current,pos+1,result);
current[pos]=')';
generateAll(current,pos+1,result);
}
}
bool valid(char current[])
{
int balance=0;
for(int i=0; i<strlen(current); i++)
{
if(current[i]=='(')
balance++;
else
balance--;
if(balance<0)
return false;
}
return (balance==0);
}
};
Python
在python代码中,遇到了这样的问题:最终输出的结果,result中的结果都是一样的,正如下面代码所展示的一样,输出结果为:[[")",")",")",")",")",")"],[")",")",")",")",")",")"],[")",")",")",")",")",")"],[")",")",")",")",")",")"],[")",")",")",")",")",")"]]
class Solution(object):
def generateParenthesis(self, n):
result = []
current = ['0' for i in range(n * 2)]
self.generateAll(current, 0, result)
return result
def generateAll(self, current, pos, result):
if (len(current) == pos):
if self.valid(current):
result.append(current)
print(result)
else:
current[pos] = '('
self.generateAll(current, pos + 1, result)
current[pos] = ')'
self.generateAll(current, pos + 1, result)
def valid(self, current):
balance = 0
for c in current:
if (c == '('):
balance = balance + 1
else:
balance = balance - 1
if (balance < 0):
return False
return balance == 0
最终,只好再更改代码,在函数中多传入一个长度参数,成功的解决了问题,代码如下所示:
class Solution(object):
def generateParenthesis(self, n):
result = []
self.generateAll("", n, 0, result)
return result
def generateAll(self, current, n, pos, result):
if (n*2 == pos):
if self.valid(current):
result.append(current)
else:
current_1 = current + '('
self.generateAll(current_1, n, pos + 1, result)
current_2 = current + ')'
self.generateAll(current_2, n, pos + 1, result)
def valid(self, current):
balance = 0
for c in current:
if (c == '('):
balance = balance + 1
else:
balance = balance - 1
if (balance < 0):
return False
return balance == 0
方法二
因为符合条件的括号序列,左括号和有括号都是相等的,并且现有左括号,后有右括号,根据这个特点,我们在遍历过程中,直接根据其特性进行组合。
Java
public List<String> generateParenthesis(int n) {
List<String> result = new ArrayList<>();
backTrack(result, "", 0, 0, n);
return result;
}
public void backTrack(List<String> result, String current, int open, int close, int n) {
if (n * 2 == current.length()) {
result.add(current);
} else {
if (open < n)
backTrack(result, current + '(', open + 1, close, n);
if (close < open)
backTrack(result, current + ')', open, close + 1, n);
}
}
C++
vector<string> generateParenthesis(int n)
{
vector<string> result=vector<string>();
backTrack(result,"",0,0,n);
return result;
}
void backTrack(vector<string>& result,string current,int open,int close,int n)
{
if(n*2==current.length())
result.push_back(current);
else
{
if(open<n)
backTrack(result, current+'(',open+1,close,n);
if(close<open)
backTrack(result,current+')',open,close+1,n);
}
}
Python
def generateParenthesis(self, n):
result = []
self.backTrack(result, "", 0, 0, n)
return result
def backTrack(self, result, current, open, close, n):
if n * 2 == len(current):
result.append(current)
else:
if open < n:
self.backTrack(result, current + '(', open + 1, close, n)
if close < open:
self.backTrack(result, current + ')', open, close + 1, n)
方法三
方法三更加简单明了,因为整个括号表达式都类似于"(" + left + ")" + right
这样的形式,也就是首先一个左括号,后面一个右括号,左括号和右括号之间添加一部分,右括号后面添加一部分,根据这个特点,可以将代码写成如下所示。
Java
public List<String> generateParenthesis(int n) {
List<String> result = new ArrayList<>();
if (n == 0)
result.add("");
else
for (int c = 0; c < n; c++)
for (String left : generateParenthesis(c))
for (String right : generateParenthesis(n - 1 - c))
result.add("(" + left + ")" + right);
return result;
}
C++
vector<string> generateParenthesis(int n)
{
vector<string>result=vector<string>();
if(n==0)
result.push_back("");
else
for(int c=0; c<n; c++)
{
vector<string> result_left=generateParenthesis(c);
for(int i=0;i<result_left.size();i++)
{
string left=result_left[i];
vector<string>result_right=generateParenthesis(n-1-c);
for(int j=0;j<result_right.size();j++)
{
string right=result_right[j];
result.push_back("("+left+")"+right);
}
}
}
return result;
}
python
def generateParenthesis(self, n):
result = []
if n == 0:
result.append("")
else:
for c in range(n):
for left in self.generateParenthesis(c):
for right in self.generateParenthesis(n - 1 - c):
result.append("(" + left + ")" + right)
return result