第三章:回溯算法最佳实践:括号生成

labuladong 回溯算法最佳实践:括号生成

22. 括号生成

问题转化为:现在有 2n 个位置,每个位置可以放置字符 ‘(‘ 或者 ‘)’,求生成所有可能的并且有效的括号组合

  • 可用的左括号数量为 left 个,可用的右括号数量为 rgiht 个。cur表示当前字符串状态
  • 左右括号都能用完,说明是合法的,res中记录当前cur
  • 剩下的左括号比右括号多,或者括号数量小于0,说明是不合法的,直接return
  • 回溯:做选择,撤销选择
class Solution(object):
    def generateParenthesis(self, n):
        """
        :type n: int
        :rtype: List[str]
        """
        res=[]
        choose=['(',')']
        def backtrack(left,right,cur):# 还可以放几个左括号/右括号,当前字符串的状态

            # 合法的情况
            if left==0 and right==0: # 左右括号都用完了,合法
                res.append(cur)
                return
            # 不合法的情况
            # 剩下的左括号比右括号多,或者括号数量小于0
            if left>right or left<0 or right<0:
                return

            # 回溯, 有两种写法
            # 写法1:以左括号为例
            cur=cur+choose[0] # 做选择 ,尝试放左括号
            backtrack(left-1,right,cur)  
            cur=cur[:-1]  #撤销选择
            # 写法2:以右括号为例,直接在backtrack中进行更新
            backtrack(left,right-1,cur+choose[1])
        backtrack(n,n,'')
        return res
class Solution {
public:
    vector <string> res;
    vector <string> choose{"(", ")"};

    void backtrack(string visited, int left, int right) {
        if (left == 0 && right == 0) {
            res.push_back(visited);
            return;
        }
        if (left > right || left < 0 || right < 0) {
            return;
        }

//        只有两种选择,分别列举即可
        visited.append(choose[0]);
        backtrack(visited, left - 1, right);
        visited.pop_back();

        visited.append(choose[1]);
        backtrack(visited, left, right - 1);
        visited.pop_back();

        // // 或者写成回溯框架
        // for (int i = 0; i < 2; ++i) {
        //     if (i == 0) {
        //         visited.append(choose[0]);
        //         backtrack(visited, left - 1, right);
        //     } else {
        //         visited.append(choose[1]);
        //         backtrack(visited, left, right - 1);
        //     }
        //     visited.pop_back();
        // }
    }

    vector <string> generateParenthesis(int n) {
        string visited;
        backtrack(visited, n, n);
        return res;
    }
};

   转载规则


《第三章:回溯算法最佳实践:括号生成》 M 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
第三章:双指针技巧总结 第三章:双指针技巧总结
labuladong 双指针技巧总结 利用快慢指针或者左右指针解决问题 141. 环形链表利用快慢指针,一开始都指到头结点处,然后每次快指针走两步,慢指针。若最后相遇了,说明有环 # Definition for singly-linked
2020-08-12
下一篇 
第二章:递归反转链表的一部分 第二章:递归反转链表的一部分
labuladong 递归反转链表的一部分 92. 反转链表 II方法1.递归反转链表 (只是说明递归方法的思想,本题优解应参考方法2) 先看例题206. 反转整个链表 对于递归算法,最重要的就是明确递归函数实现的功能(而不是跳进递归中
2020-08-12
  目录