Searching & Sorting · 26 of 36
EKOSPOJ
Set a saw blade as high as possible so that the tree tops it cuts off still add up to the wood you need.
- Simple way
- time O(n * max)
room O(1) - Clever way
- time O(n log max)
room O(1)
The problem, simply
You get the heights of n trees in a row and a number M, the meters of wood you need. A long saw blade is set at height H and sweeps over the whole row. Every tree taller than H loses its top part, and you keep those tops. Trees shorter than H are not touched.
Find the highest whole number H that still gives you at least M meters of wood. A higher blade is kinder to the forest.
A story to remember it
Picture it
Trees of height 6, 9, 4 and 8, blade at 5. The tops are 1, 4, 0 and 3, which is 8 meters. At height 6 the tops would be only 0 + 3 + 0 + 2 = 5.
- blade
- 5
- wood
- 8
- need
- 6
- looking now
- just added
- ignored
Examples
A normal case
- In
trees = [6, 9, 4, 8], M = 6- Out
5
At 5 you get 1 + 4 + 3 = 8, which is enough. At 6 you get 3 + 2 = 5, which is not.
Exactly enough
- In
trees = [20, 15, 10, 17], M = 7- Out
15
At 15 you get 5 + 2 = 7, exactly enough. At 16 you get 4 + 1 = 5.
Bigger forest
- In
trees = [4, 42, 40, 26, 46], M = 20- Out
36
At 36 you get 6 + 4 + 10 = 20. At 37 you get 5 + 3 + 9 = 17.
You need every bit
- In
trees = [5, 5, 5], M = 15- Out
0
Only cutting at the ground gives 15. Any higher blade gives less.
One tree
- In
trees = [10], M = 1- Out
9
Cut just the top meter off.
Way 1: the simple way
Start the blade at the top of the tallest tree, where it cuts nothing. Lower it one meter at a time. Each time, add up the tops. Stop at the first height that gives enough wood.
Hstarts at the tallest height.- Wood at
His the sum oftree - Hover trees taller thanH. - If the wood is at least
M, answerH. Otherwise lowerHby one.
class Solution {
long woodAt(int[] trees, int h) {
long wood = 0;
for (int t : trees) {
if (t > h) wood += t - h; // only the part above the blade
}
return wood;
}
public int highestBlade(int[] trees, long need) {
int top = 0;
for (int t : trees) top = Math.max(top, t);
for (int h = top; h >= 0; h--) {
if (woodAt(trees, h) >= need) return h; // first one from the top
}
return 0;
}
}How long it takes: trees can be a billion meters tall, and each height costs a walk over all n trees: O(n * max). Extra room: O(1).
Way 2: the clever way
Raising the blade never gives more wood. So the heights line up as yes, yes, yes, no, no: low blades give enough, high blades do not. We want the last yes. That is a job for binary search on the answer.
lo = 0,hi =the tallest tree.- Try
mid. Add up the wood. - Enough wood: remember
mid, then try higher withlo = mid + 1. - Not enough: try lower with
hi = mid - 1. - When
lopasseshi, the remembered height is the answer.
The bottom row in the animation lists every blade height. Heights marked done give enough wood, heights marked rejected are too high.
Guess a blade height, count the wood, throw away half
01 / 10
The blade can go anywhere from 0 (cut every tree to the ground) to 9 (the tallest tree, so no wood at all). We need at least 6 meters of wood.
- need
- 6
- looking now
- checking
- done
- answer
- rejected
- just added
- ignored
class Solution {
long woodAt(int[] trees, long h) {
long wood = 0;
for (int t : trees) {
if (t > h) wood += t - h;
}
return wood;
}
public long highestBlade(int[] trees, long need) {
long lo = 0, hi = 0;
for (int t : trees) hi = Math.max(hi, t);
long best = 0;
while (lo <= hi) {
long mid = lo + (hi - lo) / 2;
if (woodAt(trees, mid) >= need) {
best = mid; // enough wood, try a higher blade
lo = mid + 1;
} else {
hi = mid - 1; // not enough, go lower
}
}
return best;
}
}How long it takes: about log(max) guesses (30 for a billion), each walking all trees once: O(n log max). Extra room: O(1).
Watch out for
- Adding
tree - Hfor short trees too. A tree shorter than the blade gives 0, not a negative number. - Moving the wrong pointer. Enough wood means the blade can go higher, so
lomoves up. - The problem promises the answer exists (the total wood is at least
M). If not, decide what to return before you search. - Reading a million numbers with a slow scanner times out on SPOJ. Use a fast reader.
What interviewers ask next
- Can you avoid scanning every tree for every guess? Sort the trees and build prefix sums. Then the wood at height
His (sum of trees taller thanH) minusHtimes (how many there are), found with one binary search. Each guess costsO(log n). - Even better: after sorting, walk down from the tallest tree and find the stretch where the answer lands, then solve for
Hwith one division. That isO(n log n)for the sort andO(n)after. - Same pattern elsewhere: "Koko eating bananas" (lowest speed that finishes in time) and "minimum days to make bouquets" are this exact search with a different check.
- What if heights are real numbers? Binary search on a double for a fixed number of rounds.
Remember this
Grown-up words: the guessing game is binary search on the answer, "higher means less wood" is a monotonic function, adding up the tops is the feasibility check, and the total that might not fit is integer overflow.