Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.python
For example, given n = 3, a solution set is:數組
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
複製代碼
簡單翻譯過來就是,寫出n對括號的全部組合狀況,注意是well-formed的組合。bash
這題目,so easy啊。app
個人思路以下,很明顯麼,這是一個排列組合的題目。n對括號,一共是2n個位置,也就是說在2n個位置裏面,找n個位置放(
,另外n個位置放)
,這就是一個C(n,m)的數學問題。在全部的組合裏找出來well-formed的組合,不就Ok了嘛,哈哈哈我可真是個小天才。less
首先要實現C(n,m)的代碼,也就是n個數裏,取m個數的全部狀況。而後...好難啊,木有思路。通過左思右想加百度谷歌。找到一個方法,使用遞歸的方式。先拿出第一個數,而後再從剩下的n-1個數去遞歸查找,就變成了一個C(n-1,m-1)的子問題。這裏用了一個維數組去存每種狀況的組合,用了一個結構體使用二維數組去存全部的組合狀況。代碼以下。ui
type TwoDArray struct {
arrays [][]int
}
func getItems(data []int, n int, outlen int, startIndex int, m int, array []int, arrIndex int, finalArray *TwoDArray) {
if m == 0 {
a := []int{}
for i := 0; i < outlen; i++ {
//fmt.Printf("%d \t", arry[i])
a = append(a, array[i])
}
finalArray.arrays = append(finalArray.arrays, a)
return
}
endIndex := n - m
for i := startIndex; i <= endIndex; i++ {
array[arrIndex] = data[i]
getItems(data, n, outlen, i+1, m-1, array, arrIndex+1, finalArray)
}
}
複製代碼
ok,拿到全部組合了以後就好作了。咱們按照位置的索引,將對應的位置進行替換就行了,先設置初始的串是2n個"(",而後把對應位置的"("替換成")",再驗證一下是不是well-formed的就能夠了,所有代碼以下spa
func match(a byte, b byte) bool {
if a == '(' && b == ')' {
return true
}
if a == '{' && b == '}' {
return true
}
if a == '[' && b == ']' {
return true
}
return false
}
func isValid(s string) bool {
l := []byte{}
top := -1
for i := 0; i < len(s); i++ {
if top == -1 && i == 0 {
top += 1
l = append(l, s[i])
continue
}
if top >= 0 {
if match(l[top], s[i]) {
l = l[:top]
top -= 1
} else {
top += 1
l = append(l, s[i])
}
} else {
top += 1
l = append(l, s[i])
}
}
if len(l) == 0 {
return true
}
return false
}
type TwoDArray struct {
arrays [][]int
}
func getItems(data []int, n int, outlen int, startIndex int, m int, array []int, arrIndex int, finalArray *TwoDArray) {
if m == 0 {
a := []int{}
for i := 0; i < outlen; i++ {
//fmt.Printf("%d \t", arry[i])
a = append(a, array[i])
}
finalArray.arrays = append(finalArray.arrays, a)
return
}
endIndex := n - m
for i := startIndex; i <= endIndex; i++ {
array[arrIndex] = data[i]
getItems(data, n, outlen, i+1, m-1, array, arrIndex+1, finalArray)
}
}
func generateParenthesis(n int) []string {
res := make([]string, 0)
if n == 0 {
return []string{"()"}
}
initStr := ""
data := []int{}
for i := 0; i < 2*n; i++ {
initStr += "("
data = append(data, i+1)
}
//組合用一個二進制數表示
arr := make([]int, n)
finalArry := &TwoDArray{}
getItems(data, len(data), n, 0, n, arr, 0, finalArry)
for i := 0; i < len(finalArry.arrays); i++ {
tmp := initStr
for _, m := range finalArry.arrays[i] {
pos := m - 1
tmp = tmp[:pos] + ")" + tmp[pos+1:]
}
if isValid(tmp) {
res = append(res, tmp)
}
}
return res
}
func main() {
a := generateParenthesis(3)
fmt.Println(a)
}
複製代碼
洋洋灑灑寫了100行代碼,提交上去驗證一下翻譯
Runtime: 12 ms, faster than 21.43% of Go online submissions for Generate Parentheses.
Memory Usage: 8.4 MB, less than 15.87% of Go online submissions for Generate Parentheses.
複製代碼
雖然經過了,可是時間複雜度和空間複雜度都過高了。我去看一看leetcode上的solution。第一種方法是純暴力解法直接找出全部組合。第二種解法以下,它的python代碼只有14行,我意識到我這是跑偏到北極去了。我確定是想不出來這種方法的,它的思路就是記錄左括號和右括號的數量,每次都是以一個左括號開始,若是右括號數量少的話就加一個右括號,以此來保證括號形式有效(well-formed),最後達到長度時候,把結果存下來。code
class Solution(object):
def generateParenthesis(self, N):
ans = []
def backtrack(S = '', left = 0, right = 0):
if len(S) == 2 * N:
ans.append(S)
return
if left < N:
backtrack(S+'(', left+1, right)
if right < left:
backtrack(S+')', left, right+1)
backtrack()
return ans
複製代碼
好吧,我已經開始嚴重懷疑個人智商了,我可能不適合作leetcode題目啊。orm
總結一下,其實題目並非很難,可能須要一些技巧性的思路。我一般都是按照常規思路去解決問題的,看到問題的時候首先會使用暴力方法,可是確定會有一些更節省時間和空間的辦法。一般是用空間換時間,或者是利用規律或者數學公式,或者是採起分治的策略。平時仍是要多刷一些題目進行練習來提升本身的思考能力和思惟方式。