A valid parentheses pair meets two requirements:
- The number of left and right parentheses are equal.
- The left parenthese number >= right in the prefix of valid parenthese pair, such
((()
,((())
or((()))
.
And final result will meets the requirement: left parentheses total number is equal to right one.
We use (left
, right
) (the parentheses number) to represent every node, we can either choose left or right parenthese, that will form a full binary tree for every possible combination.
(3, 2) means 3
(
and 2)
in the string.
But we have to meet the valid rules (tree pruning):
- If
left
(left parentheses number) <n
, we can put(
. - If
right
<left
, we can put)
.
And we can run either DFS or BFS to traverse every node to form the result string. Here we use DFS:
- We start from
left
= 0 andright
= 0,str
is empty. - If
left
<n
, we can put(
and we incrementleft
. - If
right
<left
(not match), then put)
to match and incrementright
. - If
left
=right
=n
, return thestr
. (A valid pair)
You can draw a binary tree for
n = 2
, that would be really helpful!
class Solution {
private val results = mutableListOf<String>()
fun generateParenthesis(n: Int): List<String> {
dfs(n, 0, 0, "")
return result
}
private fun dfs(n: Int, left: Int, right: Int, str: String) {
// Print the node
if (left == n && right == n) {
results.add(str)
} else {
// Traverse left subtree
if (left < n) {
dfs(n, left + 1, right, str + "(")
}
// Traverse right substree
if (right < left && right < n) {
dfs(n, left, right + 1, str + ")")
}
}
}
}
Or we can use remaining count:
private val results = mutableListOf<String>()
fun generateParenthesis(n: Int): List<String> {
dfs(n - 1, n, "(")
return results
}
private fun dfs(left: Int, right: Int, str: String) {
if (left > right) return
if (left == 0 && right == 0) {
results.add(str.toString())
return
}
if (left > 0) dfs(left - 1, right, str + "(")
if (right > 0) dfs(left, right - 1, str + ")")
}
With string list to avoid string concanetation.
private val results = mutableListOf<String>()
fun generateParenthesis(n: Int): List<String> {
dfs(n, n, mutableListOf<String>())
return results
}
private fun dfs(left: Int, right: Int, str: MutableList<String>) {
// Prune
if (right < left) return
if (left == 0 && right == 0) {
results.add(str.joinToString(""))
return
}
if (left > 0) {
str.add("(")
dfs(left - 1, right, str)
// Backtracking
str.removeAt(str.size - 1)
}
if (right > 0) {
str.add(")")
dfs(left, right - 1, str)
// Backtracking
str.removeAt(str.size - 1)
}
}
- Time Complexity:
O(2^2n)
. - Space Complexity:
O(n)
for recursive function call stack.
The solution explanation provides different complexity, and it's too complex and out of scope.
We also can use BFS to traverse to generate all combination.