1. 程式人生 > >乘風破浪:LeetCode真題_022_Generate Parentheses

乘風破浪:LeetCode真題_022_Generate Parentheses

乘風破浪:LeetCode真題_022_Generate Parentheses

一、前言

   關於括號的題目,我們已經遇到過了驗證正確性的題目,現在讓我們生成合法的括號列表,怎麼辦呢?想來想去還是遞迴比較方便。

二、Generate Parentheses

2.1 問題

2.2 分析與解決

    既然用遞迴就要構造模型,這裡我們定義left和right分別代表剩餘的左右括號的數目,如果出現了left>right,那麼就會出現實際上的左括號小於右括號的結果,出現錯誤,如果剩餘都小於零就結束,只有都剩餘為0的時候才記錄,這樣我們就得到了結果。

public class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> res = new ArrayList<String>();
        helper(n, n, "", res);
        return res;
    }
    void helper(int left, int right, String out, List<String> res) {
        if (left < 0 || right < 0 || left > right) return;
        if (left == 0 && right == 0) {
            res.add(out);
            return;
        }
        helper(left - 1, right, out + "(", res);
        helper(left, right - 1, out + ")", res);
    }
}

 

    那麼官方是怎麼說的呢?

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> combinations = new ArrayList();
        generateAll(new char[2 * n], 0, combinations);
        return combinations;
    }

    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);
    }
}

     也是用了一種遞迴的方法,先生成左括號,再遞迴,直至遍歷完所有的情況,因此複雜度非常的高,究其原因是沒有考慮到一些本來就可以省略的情況。

 

    於是做出了改進,將一些情況進行了優化,只有右括號小於左括號的時候才能新增右括號,左括號也不能超過最大的上限:

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> ans = new ArrayList();
        backtrack(ans, "", 0, 0, n);
        return ans;
    }

    public void backtrack(List<String> ans, String cur, int open, int close, int max){
        if (cur.length() == max * 2) {
            ans.add(cur);
            return;
        }

        if (open < max)
            backtrack(ans, cur+"(", open+1, close, max);
        if (close < open)
            backtrack(ans, cur+")", open, close+1, max);
    }
}

三、總結

    這一題其實是比較難的,因為我們可能無從下手,就算用遞迴的時候也不能抓住要害,因此如何定義遞迴中變數的含義至關重要。