递归和回溯解决括号匹配问题

递归和回溯解决括号匹配问题

递归在之前的文章中有提及,有朋友在后台大呼不过瘾,刚好又刷到了一道可以用到递归的算法题,还是我们的老朋友:匹配有效括号,废话不多说,先上题目。

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

 

示例:

输入:n = 3
输出:[
       "((()))",
       "(()())",
       "(())()",
       "()(())",
       "()()()"
     ]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/generate-parentheses

经过分析,这涉及到了两个关键问题:

  1. 如何判断组合成的括号字符串是有效的
  2. 如何构建所有可能性的括号字符串。

第一个问题比较容易想通,必须要左右括号成对出现即可。
如果是暴力解法可以考虑把这两个问题分成两步去处理好,而如果是用递归,肯定是希望每次递归的时候不仅创建出排列组合,且这个组合出来的字符串是有效的。

func generateParenthesis(n int) []string {
	return generate(n)
}


func generate(n int) []string {
	cache := map[int][]string{}

	if cache[n] != nil {
		return cache[n]
	}
	var ans []string

	if n == 0 {
		ans = append(ans, "")

	} else {
		for c := 0; c < n; c++ {
			currentLeft := generate(c)
			currentRight := generate(n - c -1)
			for _, value_left := range currentLeft {
				for _, value_right := range currentRight {
					ans = append(ans, "(" + value_left + ")" + value_right)
				}
			}
		}
	}
	cache[n] = ans
	return ans
}

递归的关键在于找到边界,也就是分别对左括号和右括号的创建进行递归,这样就能生成出符合条件的字符串。总体来说这次递归的解法非常符合人性,条理清晰,也用到一个cache的map来存储结果,提高执行效率。

其实这道题也可以使用回溯的方法来实现,具体代码实现如下:

func generateParenthesis2(n int) []string {
	ans := new([]string) // 设置一个指向类型为string的切片的指针

	var curr []byte
	backtrack(ans, curr, 0, 0, n)

	return *ans // 反取指针,获得结果切片
}

// 回溯函数
func backtrack(ans *[]string, curr []byte, open int, close int, max int) {
	if len(curr) == max * 2 {
		*ans = append(*ans, string(curr[:]))
		return
	}

	if open < max { // 左括号没有超过最大值,则添加做括号,最后删除切片的最后一个元素
		curr = append(curr, '(')
		backtrack(ans, curr, open+1, close, max)
		curr = append(curr[0:len(curr)-1], curr[len(curr):]...) // 这个删除方式最直接,但是
	}

	if close < open { // 当右括号比作括号少,则添加,最后删除切片的最后一个元素
		curr = append(curr, ')')
		backtrack(ans, curr, open, close+1, max)
		curr = append(curr[0:len(curr)-1], curr[len(curr):]...)
	}
}

回溯也就是动态规划,把每次结果都带入到下一次回溯中,通过比较开闭括号的个数,来动态地调整。
算法题有时候可以考虑多种解法去实现,刷题的同时也能体会到不同编程语言的妙处。
本文首发自我的微信公众号:成都有娃儿,欢迎关注。

原文地址:https://www.cnblogs.com/freephp/p/13340436.html