Unique Binary Search Trees | LeetCode | DP Solution, Explained
LeetCode 96. Unique Binary Search Trees. I explain the Dynamic Programming Solution in detail, along with intuitions on how to actually think about this problem. Problem Link.
0. Unique Binary Search Trees: Problem Discussion
0.0. I/O format
- Input: n
- Return: The number of unique BSTs
0.1. What are BSTs?
- The existence of nodes
zis not necessary, but if they do (any of them), they should follow the condition
x < y < z
1. Unique Binary Search Trees: Observations & Logic
In these type of counting problems, I like to aim for finding a pattern between the first few cases – maybe the
i+1th answer is double of
ith answer, or maybe there is a common difference between adjacent answers.
Its a good idea to look at the couple of smaller cases first, since they are easy to do manually, and in dp questions, they become a bliss. Let’s see what happens!
Huh. Maybe for n=x –> x? Let’s see a couple more examples to confirm or deny this.
Ah. For n = x –> x will not work. There’s something more going on. Look at the root of the trees for n = 3.
Interestingly enough, it looks as if there are some repeating sub-structures in the case of n = 3. Look at node
3 as an example. The nodes 1 and 2 will both be on the left side, and both have 2 arrangements they can be in – since n = 2 –> 2!
This means we are looking at a DP question.
In this case, we group the elements that would have come to the right and left side (using the property of BST), and we will call the appropriate n = 2 –> 2 OR n = 3 –> 5.
2. Unique Binary Search Trees: Implementation
The implementation is straightforward once we understand the DP logic:
- calculate some base cases, dp = dp = 1
- where dp[i] represents the answer for the
ith node, as in, n = i –> dp[i]
- then, for each
i, we try to find all the possible arrangements, each time increasing the left_side count by 1, and decreasing the right_side count by 1 simultaneously.
class Solution: def numTrees(self, n: int) -> int: dp = *(n+1) dp = 1 dp = 1 for i in range(2, n+1): dp[i] = 0 l, r = 0, i-1 while l < i: dp[i] += dp[l]*dp[r] l += 1 r -= 1 return dp[n]
2.1. Complexity Analysis
- Time: O(N2). O(N) to iterate over all the Ns and another O(N) nested to consider all left and right combinations.
- Space: O(N). To store all the dp values.
January 24, 2022
January 20, 2022
January 15, 2022