04. Optimal Binary Search Tree
Efficient solutions to compute minimum cost of Optimal Binary Search Tree using DP, including optimized variants.
The problem can be found at the following link: π Question Link
π§© Problem Description
You are given a set of distinct keys in sorted order, represented by keys[]. Each key ki represents a data record accessed during a search operation. For all keys, you are also given a frequency array freq[], which denotes how many times key ki is searched for.
The cost of accessing a key in a binary search tree is calculated by multiplying its access frequency by the level at which it appears in the tree. Therefore, different arrangements of keys in the BST result in different total search costs.
Your task is to calculate the minimum total search cost required to construct a binary search tree containing all the keys.
Note: Consider the root of the BST is at level 1.
π Examples
Example 1
Input: keys[] = [10, 12], freq[] = [34, 50]
Output: 118
Explanation: There can be two possible BSTs:
Tree I: 10 as root, 12 as right child β Cost = 34*1 + 50*2 = 134
Tree II: 12 as root, 10 as left child β Cost = 50*1 + 34*2 = 118
The minimum cost is 118.Example 2
Input: keys[] = [10, 12, 20], freq[] = [34, 8, 50]
Output: 142
Explanation: Among all possible BSTs, the optimal configuration has:
20 as root (level 1), 10 as left child (level 2), 12 as right child of 10 (level 3)
Cost = 1*50 + 2*34 + 3*8 = 142π Constraints
$1 \le \text{keys.size()} = \text{freq.size()} \le 100$
$1 \le \text{keys}[i], \text{freq}[i] \le 10^4$
β
My Approach
The optimal approach uses Dynamic Programming with Prefix Sum Optimization to efficiently compute the minimum cost BST:
Dynamic Programming with Prefix Sum
Initialize DP Table:
Create a 2D DP table
dp[i][j]representing the minimum cost to construct a BST with keys from indexitoj.Base case:
dp[i][i] = freq[i](single key costs its frequency at level 1).
Precompute Prefix Sums:
Build prefix sum array
ps[]whereps[i]stores the cumulative sum of frequencies up to indexi-1.This allows O(1) range sum queries:
sum(i, j) = ps[j+1] - ps[i].
Fill DP Table:
Iterate over all possible subarray lengths
lfrom 2 to n.For each subarray
[i, j], try every keyrin the range as the root.Calculate cost when key
ris root:cost = dp[i][r-1] + dp[r+1][j] + frequencySum(i, j).The frequency sum represents the cost increment as all keys in the range go one level deeper.
Recurrence Relation:
dp[i][j] = min(dp[i][r-1] + dp[r+1][j]) + sum(freq[i..j])for all r in [i, j].Left subtree cost + Right subtree cost + Total frequency sum of current range.
Return Result:
dp[0][n-1]contains the minimum cost for constructing BST with all keys.
π Time and Auxiliary Space Complexity
Expected Time Complexity: O(nΒ³), as we have three nested loops: one for subarray length (O(n)), one for starting position (O(n)), and one for choosing the root within the range (O(n)).
Expected Auxiliary Space Complexity: O(nΒ²), as we use a 2D DP table of size nΓn and a prefix sum array of size n+1.
π§βπ» Code (C++)
class Solution {
public:
int minCost(vector<int> &keys, vector<int> &freq) {
int n = keys.size();
vector<vector<int>> dp(n, vector<int>(n, 0));
vector<int> ps(n + 1, 0);
for (int i = 0; i < n; i++) ps[i + 1] = ps[i] + freq[i];
for (int i = 0; i < n; i++) dp[i][i] = freq[i];
for (int l = 2; l <= n; l++) {
for (int i = 0; i <= n - l; i++) {
int j = i + l - 1;
dp[i][j] = INT_MAX;
int fsum = ps[j + 1] - ps[i];
for (int r = i; r <= j; r++) {
int c = (r > i ? dp[i][r - 1] : 0) + (r < j ? dp[r + 1][j] : 0) + fsum;
dp[i][j] = min(dp[i][j], c);
}
}
}
return dp[0][n - 1];
}
};β Code (Java)
class Solution {
public int minCost(int keys[], int freq[]) {
int n = keys.length;
int[][] dp = new int[n][n];
int[] ps = new int[n + 1];
for (int i = 0; i < n; i++) ps[i + 1] = ps[i] + freq[i];
for (int i = 0; i < n; i++) dp[i][i] = freq[i];
for (int l = 2; l <= n; l++) {
for (int i = 0; i <= n - l; i++) {
int j = i + l - 1;
dp[i][j] = Integer.MAX_VALUE;
int fsum = ps[j + 1] - ps[i];
for (int r = i; r <= j; r++) {
int c = (r > i ? dp[i][r - 1] : 0) + (r < j ? dp[r + 1][j] : 0) + fsum;
dp[i][j] = Math.min(dp[i][j], c);
}
}
}
return dp[0][n - 1];
}
}π Code (Python)
class Solution:
def minCost(self, keys, freq):
n = len(keys)
dp = [[0] * n for _ in range(n)]
ps = [0] * (n + 1)
for i in range(n):
ps[i + 1] = ps[i] + freq[i]
dp[i][i] = freq[i]
for l in range(2, n + 1):
for i in range(n - l + 1):
j = i + l - 1
dp[i][j] = float('inf')
fsum = ps[j + 1] - ps[i]
for r in range(i, j + 1):
c = (dp[i][r - 1] if r > i else 0) + (dp[r + 1][j] if r < j else 0) + fsum
dp[i][j] = min(dp[i][j], c)
return dp[0][n - 1]π§ Contribution and Support
For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: π¬ Any Questions?. Let's make this learning journey more collaborative!
β If you find this helpful, please give this repository a star! β
πVisitor Count
Last updated