Skip to content

Commit 7190cec

Browse files
committed
Runtime: 1 ms (Top 95.15%) | Memory: 41.70 MB (Top 26.54%)
1 parent a241a43 commit 7190cec

File tree

1 file changed

+62
-24
lines changed

1 file changed

+62
-24
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,66 @@
1+
// Runtime: 1 ms (Top 95.15%) | Memory: 41.70 MB (Top 26.54%)
2+
13
class Solution {
2-
public int mctFromLeafValues(int[] arr) {
3-
4-
int sum = 0;
5-
Stack<Integer> stack = new Stack<>();
6-
for (int num: arr) {
7-
sum += cleanUpStack(num, stack);
8-
}
9-
sum += cleanUpStack(17, stack);
10-
11-
return sum;
12-
}
4+
// Use stack. Similar to trapping the rain water problem and the largest rectangle under histogram
5+
// Use stack to keep a decreasing order by adding smaller values, while there is bigger value
6+
//arr[i] than the peek, pop it and store as mid and calculate the multiplication mid*min(arr[i],
7+
//stack.peek()).
8+
9+
// NOTE: if we observe the number array, in order to obtain the smallest sum of all non-leaf
10+
// values, we want to merge those small values first. In order words, the smaller a value
11+
// is, the lower leaf it should stay because this way as we are building the tree up,
12+
// we are building smaller multiplication/parent node first as it is only going to get bigger
13+
// as we build the tree up.
1314

14-
private int cleanUpStack(int target, Stack<Integer> stack) {
15-
int last = 0;
16-
int sum = 0;
17-
while (!stack.isEmpty() && stack.peek() <= target) {
18-
int cur = stack.pop();
19-
sum += last * cur;
20-
last = cur;
21-
}
22-
if (target != 17) {
23-
sum += target * last;
24-
stack.push(target);
25-
}
26-
return sum;
15+
// Ex: 4 3 2 1 5
16+
// There are many ways we can build a tree following the problem's requirement. However, to
17+
// gain smallest sum. We need to merge 2 and 1 first as they are the two smallest ones. To
18+
// do that, we use the stack mentioned above as a decreasing order. After
19+
// that we get a parent node with value 2. This node could be a left or right child of its parent
20+
// but what we want is that its parent needs also be as small as possible. We also know that its
21+
// parent has one mutiplier already: 2. Note: this 2 is not from the product of 1 * 2, but from the max of child
22+
// 1 and 2 as the problem requires. So, we see what values next to the leaf 2 could be a
23+
// candidate. Obviously, 3 since it is the smallest one in the stack Then, 3
24+
// becomes the left child and 1*2 = 2 becomes right child. See below:
25+
// ...
26+
// / \
27+
// 3 2
28+
// / \
29+
// 2 1
30+
//
31+
32+
// If we observe carefully, 3 2 1 is decreasing... So how about every time we see a "dip" point
33+
// in the array we calculate its multiplication. To do that, say we are at arr[i] and their
34+
// relations are arr[i-1] <= arr[i] <= arr[i+1]. The min multiplication is a[i] * min(arr[i-1],
35+
// arr[i+1]). Then the example above is arr[i] = 1, arr[i-1] = 2, arr[i+1] = 5
36+
37+
public int mctFromLeafValues(int[] arr) {
38+
if(arr == null || arr.length < 2){
39+
return 0;
40+
}
41+
42+
int res = 0;
43+
Stack<Integer> stack = new Stack<>();
44+
for(int num : arr){
45+
46+
// while num is bigger than peek(), pop and calculate
47+
while(!stack.isEmpty() && stack.peek() <= num){
48+
int mid = stack.pop();
49+
if(stack.isEmpty())
50+
res += mid * num;
51+
else
52+
res += mid * Math.min(stack.peek(), num);
53+
}
54+
55+
stack.push(num); // if num is smaller, push into stack
56+
}
57+
58+
// if there are values left in the stack, they sure will be mutiplied anyway
59+
// and added to the result.
60+
while(stack.size() > 1){ // > 1 because we have a peek() after pop() below
61+
res += stack.pop() * stack.peek();
62+
}
63+
64+
return res;
2765
}
2866
}

0 commit comments

Comments
 (0)