Leetcode刷题记录 递归——9.19

本文详细解析了括号生成问题的三种算法实现:暴力法、回溯法及动态规划法。并通过实例展示了每种方法的具体步骤及代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

递归代码的一般结构

int function(level,parm1,param2...){
	//递归终结条件
	if level>MAX_LEVEL;
		process_result;
		return//处理当前层逻辑
	process(level,data..);
	//下探到下一层
	self.function(level+1,p1....);
	
	//清理当前层
}

题目:
在这里插入图片描述
如何判断出这道题是一道递归题?
(n+1)个括号列表就是在n个括号的基础上添加一对括号即可,也就是1-2-3…-n-n+1是逐层迭代的,也可以理解为逐层递归。
解法1:暴力法
1.将所有可能的括号解列举出来,不管正确与否,例如(((((( 也算;
2.将不符合条件的解删除(创建一个评价函数)
如何判断是错误的解?
通过列举观察,我们可以发现一般像**())(()** (((() 这样的括号都是错误的,即解必须满足两个条件:
1.指针从左向右移动过程中,右括号’)‘的数量必须小于等于左括号’('的数量
2.指针遍历完后,左右括号数量必须相等;
根据上诉条件,我们可以创建一个balance,遍历过程中,有一个左括号balabce++,否则–,如果遍历过程中balance<0,或者遍历完成后balance!=0,说明这个解是错误的。
代码如下:

class Solution {
	void list_all(string str, int n, vector<string>& res) {
		//首先写出脱离递归条件
		if (str.size() == 2 * n) {
			if (is_right(str) == 0)
				res.push_back(str);
			return;
		}
		list_all(str + '(', n, res);
		list_all(str + ')', n, res);
	}
	int is_right(string &str) {
		int balance = 0;
		for (auto &i : str) {
			if (i == '(')
				balance++;
			else
				balance--;
			if (balance < 0)
				return balance;
		}
		return balance;
	}
public:
	vector<string> generateParenthesis(int n) {
		vector<string>result;
		list_all("", n, result);
		return result;
	}
};

list_all是递归函数,is_right是判断函数。

解法二:回溯法
我们其实可以在递归中就将这个判断条件加入进去,在函数中加入两个参数,left_numright_num,分别代表左括号的数量和右括号的数量。在加括号的过程中,左括号可以随时加,但是不能大于n,右括号在小于左括号的情况下可以加。这样就可以使得所有的解满足条件。
代码如下:

class Solution {
public:
	vector<string> generateParenthesis(int n) {
		vector<string>vec;
		new_generator(vec,0,0,n,"");
		return vec;
	}
	void new_generator(vector<string> &vec,int left_num,int right_num ,int sum,string s) {
		if (left_num + right_num == 2 * sum) {
			vec.push_back(s);
			return;
		}
		if (left_num < sum)
			new_generator(vec, left_num + 1, right_num, sum, s + "(");
		if (right_num < left_num)
			new_generator(vec, left_num, right_num + 1, sum, s + ")");

	}	
};

这个方法在leetcode上运行耗时0ms,算是最优方法。

解法三:动态规划
这个解法比较难以想到,它首先建立一个括号()
’ (’ a ‘)’ b
后续加的括号可以分成两部分a和b,a加到括号中,b加到括号外,通过循环可以依次求出f(1),f(2)…f(n)
具体可以见以下链接
https://leetcode-cn.com/problems/generate-parentheses/solution/hui-su-suan-fa-by-liweiwei1419/
python代码如下:
from typing import List

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        if n == 0:
            return []

        dp = [None for _ in range(n + 1)]
        dp[0] = [""]

        for i in range(1, n + 1):
            cur = []
            for j in range(i):
                left = dp[j]
                right = dp[i - j - 1]
                for s1 in left:
                    for s2 in right:
                        cur.append("(" + s1 + ")" + s2)
            dp[i] = cur
        return dp[n]

作者:liweiwei1419
链接:https://leetcode-cn.com/problems/generate-parentheses/solution/hui-su-suan-fa-by-liweiwei1419/
来源:力扣(LeetCode)

我用C++写了一个

class Solution {
public:
	vector<string> generateParenthesis(int n) {
		vector<vector<string>>vec(n+1);
		vec[0].push_back("");
		string str;
		for (int i = 1; i <=n; i++) {
			for(int j=0;j<i;j++){
				for (string &str2:vec[j]) {
					for (string &str1 : vec[i-1-j]) {
						str = "(" + str1 + ")" + str2;
						vec[i].push_back(str);
					}
				}
			}
		}
		return vec[n];
	}
};

这个方法的特点在于:
1、自底向上:从小规模问题开始,逐渐得到大规模问题的解集;
2、无后效性:后面的结果的得到,不会影响到前面的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值