LeetCode022——括号生成

版权声明:版权所有,转载请注明原网址链接。 https://blog.csdn.net/qq_41231926/article/details/82259034

我的LeetCode代码仓:https://github.com/617076674/LeetCode

原题链接:https://leetcode-cn.com/problems/generate-parentheses/description/

题目描述:

知识点:递归、回溯

思路一:暴力解法(没有剪枝操作的回溯)

先生成出所有可能的括号组合,再筛选出有效的括号组合。

对于n对括号,其生成的括号组合字符串的长度为2n,因此总共可以生成(2 ^ n)个字符串,在其中筛选出有效的字符串。

由于题目所给的有效括号中只有小括号,我们不需要采用LeetCode020——有效括号的方法,用一个栈来判断,我们只需要遍历字符串,在字符串的每一个字符位置处记录左括号的个数和右括号的个数,如果任一字符的位置处出现了右括号的个数大于左括号的个数,那么这个字符串就是无效的括号组合。最后遍历完该字符串后我们的左括号个数应该和右括号个数相等。

通过上述分析,此思路的时间复杂度是(n * 2 ^ n)级别的。我们将每一个生成的字符串都视为是有效的,而总共有2 ^ n个字符串,每个字符串的长度为n,因此空间复杂度是O(n * 2 ^ n)级别的。

JAVA代码:

public class Solution {
	
	private List<String> list;
	List<Character> brackets;
	
	public List<String> generateParenthesis(int n) {
		list = new ArrayList<>();
		brackets = new ArrayList<>();
        brackets.add('(');
        brackets.add(')');
        generateParenthesis(new StringBuilder(), 0, n);
        return list;
	}
	
	//stringBuilder中存储了索引为0 ~ (index - 1)的字符,现在考虑第index索引位置的字符
	private void generateParenthesis(StringBuilder stringBuilder, int index, int n) {
		if(index == 2 * n) {
			if(isValidString(stringBuilder.toString())) {
				list.add(stringBuilder.toString());
			}
			return;
		}
		for(int i = 0; i < brackets.size(); i++) {
			stringBuilder.append(brackets.get(i));
			generateParenthesis(stringBuilder, index + 1, n);
			stringBuilder.deleteCharAt(stringBuilder.length() - 1);
		}
	}
	
	private boolean isValidString(String string) {
		int leftCount = 0;
		int rightCount = 0;
		for(int i = 0; i < string.length(); i++) {
			if(string.charAt(i) == '(') {
				leftCount++;
			}else {
				rightCount++;
			}
			if(rightCount > leftCount) {
				return false;
			}
		}
		return rightCount == leftCount;
	}
}

LeetCode解题报告:

思路二:在思路一的基础上通过剪枝操作,提前消去无效的字符串

因为要穷举出所有可能的并且有效的括号组合,本题的回溯解法还是很容易想到的。

在递归的过程中,只有在我们知道序列仍然保持有效时才添加 '(' or ')' ,而不是像思路一那样每次添加。我们可以通过设置两个变量leftCount和rightCount来分别跟踪到目前为止放置的左括号和右括号的数目来做到这一点。

回溯过程中注意以下几点。

(1)在Solution类中新建内部的私有成员变量,可以防止递归函数中一直传递该变量。

(2)注意相关变量的手动回溯

这个思路的时间复杂度和空间复杂度分析很复杂,超出了我们所能推导的范围,这里做一个了解。

时间复杂度为O(\frac{4^{n}}{n^{0.5}}),在回溯过程中,每个有效序列最多需要n步。空间复杂度即递归深度也为O(\frac{4^{n}}{n^{0.5}}),并使用O(n)的空间来存储有效序列。

JAVA代码:

public class Solution {
	
	List<String> list;
	List<Character> brackets;
	
	public List<String> generateParenthesis(int n) {
        list = new ArrayList<>();
        brackets = new ArrayList<>();
        brackets.add('(');
        brackets.add(')');
        generateParenthesis(new StringBuilder(), 0, 0, n);
        return list;
    }
	
	//stringBuilder中存放了leftCount个左括号,rightCount个右括号
	private void generateParenthesis(StringBuilder stringBuilder, int leftCount, int rightCount, int n) {
		if(leftCount + rightCount == 2 * n) {
			list.add(stringBuilder.toString());
			return;
		}
		if(leftCount == rightCount) {
			stringBuilder.append(brackets.get(0));
			generateParenthesis(stringBuilder, leftCount + 1, rightCount, n);
			stringBuilder.deleteCharAt(stringBuilder.length() - 1);
		}else if(leftCount > rightCount) {
			if(leftCount == n) {
				stringBuilder.append(brackets.get(1));
				generateParenthesis(stringBuilder, leftCount, rightCount + 1, n);
				stringBuilder.deleteCharAt(stringBuilder.length() - 1);
			}else if(leftCount < n) {
				for(int i = 0; i < brackets.size(); i++) {
					stringBuilder.append(brackets.get(i));
					if(i == 0) {
						generateParenthesis(stringBuilder, leftCount + 1, rightCount, n);
					}else {
						generateParenthesis(stringBuilder, leftCount, rightCount + 1, n);			
					}
					stringBuilder.deleteCharAt(stringBuilder.length() - 1);
				}
			}
		}
	}
}

LeetCode解题报告:

思路三:闭合数

这个思路参考自LeetCode官网,链接如下:https://leetcode-cn.com/articles/generate-parentheses/#_3

核心思想:对于一个有效的括号组合,对于其中一对括号而言,这一对括号中间的内容一定是有效的括号组合,而这一对括号外的内容也一定是有效的括号组合

为了防止出现重复的括号组合,我们假设这一对括号的左边没有内容。因此就变成了这一对括号中间的内容一定是有效的括号组合,而这一对括号右边的内容也一定是有效的括号组合。(我们完全也可以假设这一对括号的左边没有内容,结果是一样的。)

时间复杂度和空间复杂度和思路二一样,均为O(\frac{4^{n}}{n^{0.5}}),分析也比较复杂。

JAVA代码:

public class Solution {

	public List<String> generateParenthesis(int n) {
		List<String> list = new ArrayList<>();
		if(n == 0) {
			list.add("");
		}
		for(int i = 0; i < n; i++) {
			List<String> list1 = generateParenthesis(i);
			List<String> list2 = generateParenthesis(n - i - 1);
			for (String s1 : list1) {
				for (String s2 : list2) {
					list.add("(" + s1 + ")" + s2);
				}
			}
		}
		return list;
	}
}

LeetCode解题报告:

猜你喜欢

转载自blog.csdn.net/qq_41231926/article/details/82259034