00. Prefix Sum & Line Swipe#
Prefix Sum#
Theory#
Description#
The prefix sum technique allows for efficient range sum queries by precomputing cumulative sums in an array.
Steps#
-
Build the Prefix Sum Array:
And so on…
Create a new arrayprefixwhere each element at indexistores the sum of elements from the start of the array up to indexi:
Example:
Forarr = [3, 1, 4, 1, 5, 9], theprefix_sumarray is[3, 4, 8, 9, 14, 23]. -
Answer Range Sum Queries:
To find the sum of elements between indicesiandj, use:
sum(i, j) = prefix[j] - prefix[i-1]
Example:
Forarr = [3, 1, 4, 1, 5, 9], the sum from index2to4:
sum(2, 4) = prefix[4] - prefix[1] = 14 - 4 = 10.
Note
If i = 0, simply return prefix[j].
Time & Space Complexity#
- Time:
O(n)for building the prefix sum array,O(1)per query. - Space:
O(n)for storing the prefix sum array.
Problems#
1. Range Sum Query - Immutable (Leetcode:303)#
Problem Statement
Given an integer array nums, handle multiple queries of the following type:
Calculate the sum of the elements of nums between indices left and right inclusive where left <= right.
Implement the NumArray class:
NumArray(int[] nums)Initializes the object with the integer arraynums.int sumRange(int left, int right)Returns the sum of the elements of nums between indicesleftandrightinclusive (i.e.nums[left] + nums[left + 1] + ... + nums[right]).
Example 1:
Input
["NumArray", "sumRange", "sumRange", "sumRange"]
[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]
Output
[null, 1, -1, -3]Explanation
NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]);
numArray.sumRange(0, 2); // return (-2) + 0 + 3 = 1
numArray.sumRange(2, 5); // return 3 + (-5) + 2 + (-1) = -1
numArray.sumRange(0, 5); // return (-2) + 0 + 3 + (-5) + 2 + (-1) = -3
Constraints:
1 <= nums.length <= 104-105 <= nums[i] <= 1050 <= left <= right < nums.lengthAt most 104 calls will be made to sumRange.
Code & Explanation
-
Constructor (
__init__):- Initializes a list
prefix_sumwhereprefix_sum[i]stores the sum of the elements from index0toi-1. - Builds this
prefix_sumarray by iterating over the input listnums.
- Initializes a list
-
Method
sumRange(left, right):- Returns the sum of the subarray between indices left and right by calculating the difference:
prefix_sum[right+1] - prefix_sum[left]. - This allows constant time
O(1)querying of subarray sums after the initial setup.
- Returns the sum of the subarray between indices left and right by calculating the difference:
Time & Space: O(n) preprocessing, O(1) per query; O(n) extra space for the prefix array.
2. Left and Right Sum Differences (Leetcode:2574)#
Problem Statement
Given a 0-indexed integer array nums, find a 0-indexed integer array answer where:
answer.length == nums.length.answer[i] = |leftSum[i] - rightSum[i]|.
Where:
leftSum[i]is the sum of elements to the left of the indexiin the arraynums. If there is no such element,leftSum[i] = 0.rightSum[i]is the sum of elements to the right of the indexiin the arraynums. If there is no such element,rightSum[i] = 0.
Return the arrayanswer.
Example 1:
Input: nums = [10,4,8,3]
Output: [15,1,11,22]
Explanation: The array leftSum is [0,10,14,22] and the array rightSum is [15,11,3,0].
The array answer is [|0 - 15|,|10 - 11|,|14 - 3|,|22 - 0|] = [15,1,11,22].
Example 2:
Input: nums = [1]
Output: [0]
Explanation: The array leftSum is [0] and the array rightSum is [0].
The array answer is [|0 - 0|] = [0].
Constraints:
1 <= nums.length <= 10001 <= nums[i] <= 105
Code & Explanation
-
Initialization :
left_sum = 0: Tracks the sum of elements before the current index.right_sum = sum(nums): Initially holds the total sum of all elements.answer = []: Stores the result.
-
Loop through nums :
- For each element
num: - Update
left_sum: Addnumtoleft_sum. - Calculate and append absolute difference:
|left_sum - right_sum|is appended toanswer. - Update
right_sum: Subtractnumfromright_sum.
- For each element
-
Return answer :
- After the loop, return the computed differences in
answer.
- After the loop, return the computed differences in
Time & Space: O(n) time for one pass; O(1) extra space (excluding the output array).
3. XOR Queries of a Subarray (Leetcode:1310)#
Problem Statement
You are given an array arr of positive integers. You are also given the array queries where queries[i] = [lefti, righti].
For each query i compute the XOR of elements from lefti to righti (that is, arr[lefti] XOR arr[lefti + 1] XOR ... XOR arr[righti] ).
Return an array answer where answer[i] is the answer to the ith query.
Example 1:
Input:
arr = [1,3,4,8],queries = [[0,1],[1,2],[0,3],[3,3]]
Output:[2,7,14,8]
Explanation: The binary representation of the elements in the array are:
1 = 0001
3 = 0011
4 = 0100
8 = 1000
The XOR values for queries are:
[0,1] = 1 xor 3 = 2
[1,2] = 3 xor 4 = 7
[0,3] = 1 xor 3 xor 4 xor 8 = 14
[3,3] = 8
Example 2:
Input: arr = [4,8,2,10], queries = [[2,3],[1,3],[0,0],[0,3]]
Output: [8,0,4,4]
Constraints:
1 <= arr.length, queries.length <= 3 * 1041 <= arr[i] <= 109queries[i].length == 20 <= lefti <= righti < arr.length
Code & Explanation
-
Initialization:
prefix = [0] * (len(arr) + 1): Create a listprefixto store the cumulative XOR of elements in the array. The extra element accounts for the starting point (index 0).answer = []: This will store the result for each query.
-
Build Prefix XOR Array:
- For each element
arr[i]in the array, compute the cumulative XOR up to that index: prefix[i + 1] = prefix[i] ^ arr[i]: This updates theprefixlist, where each entry ati + 1holds the XOR of all elements from the start of the array up to indexi.
- For each element
-
Process Queries:
- For each query
[left, right], calculate the XOR of elements from indexlefttoright: answer.append(prefix[right + 1] ^ prefix[left]): This uses the precomputedprefixarray. The XOR of the subarray fromlefttorightis found by subtracting the prefix XORs atleftandright + 1.
- For each query
-
Return the Answer:
- The final
answerlist contains the result for each query, which is the XOR of the elements in the subarray defined byleftandright.
- The final
Time & Space: O(n + q) time for n elements and q queries; O(n) extra space for the prefix XOR array.
4. Subarray Sum Equals K (Leetcode:560)#
Problem Statement
Given an array of integers nums and an integer k, return the total number of subarrays whose sum equals to k.
A subarray is a contiguous non-empty sequence of elements within an array.
Example 1:
Input: nums = [1,1,1], k = 2
Output: 2
Example 2:
Input: nums = [1,2,3], k = 3
Output: 2
Constraints:
1 <= nums.length <= 2 * 104-1000 <= nums[i] <= 1000-107 <= k <= 107
Code & Explanation
-
Initialization:
count = 0: To store the number of valid subarrays.prefix_sum = 0: To keep track of the cumulative sum as we iterate through the array.dictionary = {0: 1}: This keeps track of how many times a certain prefix sum has occurred.- We start with
{0: 1}because a sum of0is possible before we start processing the array.
-
Iterate through the array:
- For each element
numin the array, update theprefix_sumby addingnumto it. - Compute the difference
diff = prefix_sum - k. Ifdiffexists in the dictionary, it means there are subarrays whose sum equalsk, and theircountis stored in thedictionary. - Increment
countby the number of timesdiffhas occurred. - Update the dictionary by increasing the
countofprefix_sum.
- For each element
-
Return the
count:- This gives the total number of subarrays whose sum equals
k.
- This gives the total number of subarrays whose sum equals
Time & Space: O(n) time for a single pass; O(n) extra space for the prefix-sum frequency map.
5. Product of Array Except Self (Leetcode:238)#
Problem Statement
Given an integer array nums, return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i].
The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer.
You must write an algorithm that runs in O(n) time and without using the division operation.
Example 1:
Input: nums = [1,2,3,4]
Output: [24,12,8,6]
Example 2:
Input: nums = [-1,1,0,-3,3]
Output: [0,0,9,0,0]
Constraints:
2 <= nums.length <= 10^5
-30 <= nums[i] <= 30
The input is generated such thatanswer[i]is guaranteed to fit in a 32-bit integer.
Follow up:
Can you solve the problem in O(1) extra space complexity? (The output array does not count as extra space for space complexity analysis.)
Code & Explanation
- First pass (prefix products):
- Initialize
answerto all1s and walk left to right. -
At index
i, store the product of everything to the left inanswer[i], then update runningprefix. -
Second pass (suffix products):
- Walk right to left with a running
suffixproduct. -
Multiply
answer[i]by the suffix product of all elements to the right. -
Why it works:
- Each index gets
(product of left side) × (product of right side)without division. - Time is
O(n)and extra space isO(1)excluding the output array.
Time & Space: O(n) time, two passes; O(1) extra space (output array not counted).
6. Increment Submatrices by One (Leetcode:2536)#
Problem Statement
You are given a positive integer n, indicating that we initially have an n x n 0-indexed integer matrix mat filled with zeroes.
You are also given a 2D integer array query. For each query[i] = [row1i, col1i, row2i, col2i], you should do the following operation:
Add 1 to every element in the submatrix with the top left corner (row1i, col1i) and the bottom right corner (row2i, col2i). That is, add 1 to mat[x][y] for all row1i <= x <= row2i and col1i <= y <= col2i.
Return the matrix mat after performing every query.
Example 1:
Input: n = 3, queries = [[1,1,2,2],[0,0,1,1]]
Output: [[1,1,0],[1,2,1],[0,1,1]]
Explanation: The diagram above shows the initial matrix, the matrix after the first query, and the matrix after the second query.
- In the first query, we add 1 to every element in the submatrix with the top left corner (1, 1) and bottom right corner (2, 2).
- In the second query, we add 1 to every element in the submatrix with the top left corner (0, 0) and bottom right corner (1, 1).
Example 2:
Input: n = 2, queries = [[0,0,1,1]]
Output: [[1,1],[1,1]]
Explanation: The diagram above shows the initial matrix and the matrix after the first query.
- In the first query we add 1 to every element in the matrix.
Constraints:
1 <= n <= 500
1 <= queries.length <= 10^4
0 <= row1i <= row2i < n
0 <= col1i <= col2i < n
Code & Explanation
- 2D difference array:
- For each query rectangle, add
+1at top-left and apply-1at the boundaries just outside the rectangle. -
This marks where increments start and stop without updating every cell.
-
Prefix reconstruction:
-
Convert the difference grid into the final matrix using 2D prefix sums:
mat[i][j] = diff[i][j] + mat[i-1][j] + mat[i][j-1] - mat[i-1][j-1]. -
Why it works:
- Each query costs
O(1)marking time instead ofO(n²)brute-force updates. - Overall complexity is
O(n² + q)forqqueries on ann × nmatrix.
Time & Space: O(n² + q) time; O(n²) extra space for the difference and result grids.
7. Range Sum Query 2D - Immutable (Leetcode:304)#
Problem Statement
Given a 2D matrix matrix, handle multiple queries of the following type:
Calculate the sum of the elements of matrix inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).
Implement the NumMatrix class:
NumMatrix(int[][] matrix) Initializes the object with the integer matrix matrix.
int sumRegion(int row1, int col1, int row2, int col2) Returns the sum of the elements of matrix inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).
You must design an algorithm where sumRegion works on O(1) time complexity.
Example 1:
Input:
["NumMatrix", "sumRegion", "sumRegion", "sumRegion"]
[[[[3, 0, 1, 4, 2], [5, 6, 3, 2, 1], [1, 2, 0, 1, 5], [4, 1, 0, 1, 7], [1, 0, 3, 0, 5]]], [2, 1, 4, 3], [1, 1, 2, 2], [1, 2, 2, 4]]
Output:
[null, 8, 11, 12]
Explanation:
NumMatrix numMatrix = new NumMatrix([[3, 0, 1, 4, 2], [5, 6, 3, 2, 1], [1, 2, 0, 1, 5], [4, 1, 0, 1, 7], [1, 0, 3, 0, 5]]);
numMatrix.sumRegion(2, 1, 4, 3); // return 8 (i.e sum of the red rectangle)
numMatrix.sumRegion(1, 1, 2, 2); // return 11 (i.e sum of the green rectangle)
numMatrix.sumRegion(1, 2, 2, 4); // return 12 (i.e sum of the blue rectangle)Constraints:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 200
-10^4 <= matrix[i][j] <= 10^4
0 <= row1 <= row2 < m
0 <= col1 <= col2 < n
At most10^4calls will be made tosumRegion.
Code & Explanation
- Build 2D prefix sums:
-
Use an extra row and column of zeros so rectangle sums can be computed with inclusion-exclusion.
-
Query in O(1):
-
For rectangle
(row1, col1)to(row2, col2), subtract the top and left strips and add back the overlapping corner:
prefix[row2+1][col2+1] - prefix[row1][col2+1] - prefix[row2+1][col1] + prefix[row1][col1]. -
Why it works:
- Preprocessing takes
O(mn); eachsumRegioncall is constant time.
Time & Space: O(mn) preprocessing, O(1) per query; O(mn) extra space for the 2D prefix grid.
8. Power of Heroes (Leetcode:2681)#
Problem Statement
You are given a 0-indexed integer array nums representing the strength of some heroes. The power of a group of heroes is defined as follows:
Let i0, i1, ... ,ik be the indices of the heroes in a group. Then, the power of this group is max(nums[i0], nums[i1], ... ,nums[ik])2 * min(nums[i0], nums[i1], ... ,nums[ik]).
Return the sum of the power of all non-empty groups of heroes possible. Since the sum could be very large, return it modulo 10^9 + 7.
Example 1:
Input: nums = [2,1,4]
Output: 141
Explanation:
1st group: [2] has power = 22 * 2 = 8.
2nd group: [1] has power = 12 * 1 = 1.
3rd group: [4] has power = 42 * 4 = 64.
4th group: [2,1] has power = 22 * 1 = 4.
5th group: [2,4] has power = 42 * 2 = 32.
6th group: [1,4] has power = 42 * 1 = 16.
7th group: [2,1,4] has power = 42 * 1 = 16.
The sum of powers of all groups is 8 + 1 + 64 + 4 + 32 + 16 + 16 = 141.
Example 2:
Input: nums = [1,1,1]
Output: 7
Explanation: A total of 7 groups are possible, and the power of each group will be 1. Therefore, the sum of the powers of all groups is 7.
Constraints:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9
Code & Explanation
- Sort heroes:
-
After sorting, when
xis processed in ascending order, every earlier value can be the minimum of a group whose maximum isx. -
Prefix contribution:
- For current max
x, groups with minxcontributex² × x. - Groups with an earlier minimum contribute
x² × (earlier min value). -
prefixSumtracks the sum of all valid minimums from previous elements, doubled at each step because each earlier hero can either be included or excluded. -
Modulo arithmetic:
- Apply
% (10⁹ + 7)after each multiplication/addition to avoid overflow.
Time & Space: O(n log n) time for sorting; O(1) extra space.
Problems at a glance#
| LC | Problem | |
|---|---|---|
| 303 | 1. Range Sum Query - Immutable | ↗ |
| 2574 | 2. Left and Right Sum Differences | ↗ |
| 1310 | 3. XOR Queries of a Subarray | ↗ |
| 560 | 4. Subarray Sum Equals K | ↗ |
| 238 | 5. Product of Array Except Self | ↗ |
| 2536 | 6. Increment Submatrices by One | ↗ |
| 304 | 7. Range Sum Query 2D - Immutable | ↗ |
| 2681 | 8. Power of Heroes | ↗ |
| 2848 | 1. Points That Intersect With Cars | ↗ |
| 1893 | 2. Check if All the Integers in a Range Are Covered | ↗ |
| 452 | 3. Minimum Number of Arrows to Burst Balloons | ↗ |
| 1094 | 4. Car Pooling | ↗ |
| 731 | 5. My Calendar II | ↗ |
| 2251 | 6. Number of Flowers in Full Bloom | ↗ |
| 732 | 7. My Calendar III | ↗ |
| 1326 | 8. Minimum Number of Taps to Open to Water a Garden | ↗ |
| 1851 | 9. Minimum Interval to Include Each Query | ↗ |
| 218 | 10. The Skyline Problem | ↗ |
Line Sweep#
Theory#
Description#
The Line Sweep Algorithm is a powerful technique used in computational geometry. It's an efficient way to solve problems like detecting intersections, finding the closest pair of points, or calculating the convex hull. Let’s break down the core concepts of this algorithm to understand how it works.
What is the Sweep Line?#
The sweep line is an imaginary vertical line that moves across a plane from left to right. As it moves, it sweeps through the objects in its path, processing important events at each step. Imagine it like a curtain slowly moving across a stage, revealing different parts of a scene. In the context of algorithms, this "curtain" moves across the plane, checking and reacting to specific points where events occur.
The sweep line doesn’t just move randomly—it advances through key points, called events, which are defined based on the specific problem being solved. By focusing on these events, the algorithm can efficiently process only the relevant parts of the data.
What are Events?#
An event is a point on the plane where something significant happens as the sweep line moves. These events are the heart of the algorithm because they trigger actions like adding or removing objects, or checking for interactions. Depending on the problem you're solving, events could include:
- Start events: The beginning of an object, such as the left endpoint of a line segment or the opening of a rectangle.
- End events: The end of an object, like the right endpoint of a line segment or the closing of a rectangle.
- Intersection events: When two objects, like two line segments, intersect or overlap.
The sweep line processes these events in order, one by one, and each event may lead to an update in the algorithm’s state—whether it’s adding a new object, removing one, or checking for an intersection.
How Does it Work?#
Here’s how the line sweep algorithm works in practice:
-
Sort the events: The first step is to sort all the events in order of their position along the x-axis (left to right). For example, if you are working with line segments, this would mean sorting by the x-coordinate of the start and end points of each segment.
-
Process events in order: The sweep line starts at the leftmost event and moves to the right. For each event, you do something specific:
- When the sweep line reaches a start event (like the left endpoint of a line segment), the segment is added to a list of active objects.
- When the sweep line reaches an end event (like the right endpoint), that segment is removed from the list of active objects.
- At each step, the algorithm may check for intersections or other interactions between active objects (e.g., checking if newly added segments intersect with others already in the list).
By sorting and processing events in this way, the algorithm can handle complex geometric problems without having to check every possible pair of objects, which would be much slower.
Problems#
1. Points That Intersect With Cars (Leetcode:2848)#
Problem Statement
You are given a 0-indexed 2D integer array nums representing the coordinates of the cars parking on a number line.
For any index i, nums[i] = [starti, endi] where starti is the starting point of the ith car and endi is the ending point of the ith car.
Return the number of integer points on the line that are covered with any part of a car.
Example 1:
Input: nums = [[3,6],[1,5],[4,7]]
Output: 7
Explanation: All the points from 1 to 7 intersect at least one car, therefore the answer would be 7.
Example 2:
Input: nums = [[1,3],[5,8]]
Output: 7
Explanation: Points intersecting at least one car are 1, 2, 3, 5, 6, 7, 8. There are a total of 7 points, therefore the answer would be 7.
Constraints:
1 <= nums.length <= 100
nums[i].length == 2
1 <= starti <= endi <= 100
Code & Explanation
- Mark interval boundaries:
-
For each car
[start, end], add+1atstartand-1atend + 1. -
Prefix sweep:
-
Prefix sum over the difference array gives how many cars cover each integer point.
-
Count covered points:
- Any position with a non-zero prefix value is covered by at least one car.
Time & Space: O(n + U) time where U is the coordinate range; O(U) extra space for the difference array.
2. Check if All the Integers in a Range Are Covered (Leetcode:1893)#
Problem Statement
You are given a 2D integer array ranges and two integers left and right. Each ranges[i] = [starti, endi]represents an inclusive interval between starti and endi.
Return true if each integer in the inclusive range [left, right] is covered by at least one interval in ranges. Return false otherwise.
An integer x is covered by an interval ranges[i] = [starti, endi] if starti <= x <= endi.
Example 1:
Input: ranges = [[1,2],[3,4],[5,6]], left = 2, right = 5
Output: true
Explanation: Every integer between 2 and 5 is covered:
- 2 is covered by the first range.
- 3 and 4 are covered by the second range.
- 5 is covered by the third range.
Example 2:
Input: ranges = [[1,10],[10,20]], left = 21, right = 21
Output: false
Explanation: 21 is not covered by any range.
Constraints:
1 <= ranges.length <= 50
1 <= starti <= endi <= 50
1 <= left <= right <= 50
Code & Explanation
- Build coverage counts:
-
Use the same difference-array technique:
+1at each interval start,-1just after each end. -
Sweep to get active coverage:
-
Prefix sum converts boundary marks into the number of intervals covering each integer.
-
Validate query range:
- Return
falseif any integer in[left, right]has coverage< 1; otherwise returntrue.
Time & Space: O(r + U) time for r ranges over coordinate universe U; O(U) extra space.
3. Minimum Number of Arrows to Burst Balloons (Leetcode:452)#
Problem Statement
There are some spherical balloons taped onto a flat wall that represents the XY-plane. The balloons are represented as a 2D integer array points where points[i] = [xstart, xend] denotes a balloon whose horizontal diameter stretches between xstart and xend. You do not know the exact y-coordinates of the balloons.
Arrows can be shot up directly vertically (in the positive y-direction) from different points along the x-axis. A balloon with xstart and xend is burst by an arrow shot at x if xstart <= x <= xend. There is no limit to the number of arrows that can be shot. A shot arrow keeps traveling up infinitely, bursting any balloons in its path.
Given the array points, return the minimum number of arrows that must be shot to burst all balloons.
Example 1:
Input: points = [[10,16],[2,8],[1,6],[7,12]]
Output: 2
Explanation: The balloons can be burst by 2 arrows:
- Shoot an arrow at x = 6, bursting the balloons [2,8] and [1,6].
- Shoot an arrow at x = 11, bursting the balloons [10,16] and [7,12].
Example 2:
Input: points = [[1,2],[3,4],[5,6],[7,8]]
Output: 4
Explanation: One arrow needs to be shot for each balloon for a total of 4 arrows.
Example 3:
Input: points = [[1,2],[2,3],[3,4],[4,5]]
Output: 2
Explanation: The balloons can be burst by 2 arrows:
- Shoot an arrow at x = 2, bursting the balloons [1,2] and [2,3].
- Shoot an arrow at x = 4, bursting the balloons [3,4] and [4,5].
Constraints:
1 <= points.length <= 10^5
points[i].length == 2
-2^31 <= xstart < xend <= 2^31 - 1
Code & Explanation
- Sweep intervals by end point:
-
Sort balloons by right endpoint so the sweep line processes expiring intervals in order.
-
Place arrows at sweep events:
- Track the current arrow position.
-
When a balloon starts after that position, shoot a new arrow at its end.
-
Why it works:
- Processing intervals in sweep order and placing each arrow as far right as possible maximizes overlap with future balloons.
Time & Space: O(n log n) time for sorting; O(1) extra space.
4. Car Pooling (Leetcode:1094)#
Problem Statement
There is a car with capacity empty seats. The vehicle only drives east (i.e., it cannot turn around and drive west).
You are given the integer capacity and an array trips where trips[i] = [numPassengersi, fromi, toi] indicates that the ith trip has numPassengersi passengers and the locations to pick them up and drop them off are fromi and toi respectively. The locations are given as the number of kilometers due east from the car's initial location.
Return true if it is possible to pick up and drop off all passengers for all the given trips, or false otherwise.
Example 1:
Input: trips = [[2,1,5],[3,3,7]], capacity = 4
Output: false
Example 2:
Example 2:
Input: trips = [[2,1,5],[3,3,7]], capacity = 5
Output: true
Constraints:
1 <= trips.length <= 1000
trips[i].length == 3
1 <= numPassengersi <= 100
0 <= fromi < toi <= 1000
1 <= capacity <= 10^5
Code & Explanation
- Passenger difference array:
-
Add passengers at pickup location
startand subtract them at drop locationend. -
Simulate the route:
-
Sweep from left to right, reducing remaining capacity by the net passenger change at each stop.
-
Feasibility check:
- If capacity ever goes negative, the trips cannot all be served.
Time & Space: O(t + L) time for t trips over L locations; O(L) extra space for the difference array.
5. My Calendar II (Leetcode:731)#
Problem Statement
You are implementing a program to use as your calendar. We can add a new event if adding the event will not cause a triple booking.
A triple booking happens when three events have some non-empty intersection (i.e., some moment is common to all the three events.).
The event can be represented as a pair of integers startTime and endTime that represents a booking on the half-open interval [startTime, endTime), the range of real numbers x such that startTime <= x < endTime.
Implement the MyCalendarTwo class:
MyCalendarTwo()Initializes the calendar object.boolean book(int startTime, int endTime)Returnstrueif the event can be added to the calendar successfully without causing a triple booking. Otherwise, returnfalseand do not add the event to the calendar.
Example 1:
Input:
["MyCalendarTwo", "book", "book", "book", "book", "book", "book"]
[[], [10, 20], [50, 60], [10, 40], [5, 15], [5, 10], [25, 55]]
Output:
[null, true, true, true, false, true, true]
>Explanation:
MyCalendarTwo myCalendarTwo = new MyCalendarTwo();
myCalendarTwo.book(10, 20); // return True, The event can be booked.
myCalendarTwo.book(50, 60); // return True, The event can be booked.
myCalendarTwo.book(10, 40); // return True, The event can be double booked.
myCalendarTwo.book(5, 15); // return False, The event cannot be booked, because it would result in a triple booking. myCalendarTwo.book(5, 10); // return True, The event can be booked, as it does not use time 10 which is already double booked.
myCalendarTwo.book(25, 55); // return True, The event can be booked, as the time in [25, 40) will be double booked with the third event, the time [40, 50) will be single booked, and the time [50, 55) will be double booked with the second event.
Constraints:
0 <= start < end <= 109
At most1000calls will be made tobook.
Code & Explanation
- Mark booking events:
-
Add
+1atstartTimeand-1atendTimeon a timeline difference map. -
Sweep active bookings:
-
Sort timeline keys and walk left to right, accumulating the current overlap count.
-
Reject triple bookings:
- If any point reaches overlap
>= 3, roll back the new booking and returnfalse.
Time & Space: O(k log k) per book call where k is distinct timeline keys; O(k) extra space.
6. Number of Flowers in Full Bloom (Leetcode:2251)#
Problem Statement
You are given a 0-indexed 2D integer array flowers, where flowers[i] = [starti, endi] means the ith flower will be in full bloom from starti to endi (inclusive).
You are also given a 0-indexed integer array people of size n, where people[i] is the time that the ith person will arrive to see the flowers.
Return an integer array answer of size n, where answer[i] is the number of flowers that are in full bloom when the ith person arrives.
Example 1:
Input: flowers = [[1,6],[3,7],[9,12],[4,13]], people = [2,3,7,11]
Output: [1,2,2,2]
Explanation: The figure above shows the times when the flowers are in full bloom and when the people arrive.
For each person, we return the number of flowers in full bloom during their arrival.
Example 2:
Input: flowers = [[1,10],[3,3]], people = [3,3,2]
Output: [2,2,1]
Explanation: The figure above shows the times when the flowers are in full bloom and when the people arrive.
For each person, we return the number of flowers in full bloom during their arrival.
Constraints:
1 <= flowers.length <= 5 * 10^4
flowers[i].length == 2
1 <= starti <= endi <= 10^9
1 <= people.length <= 5 * 10^4
1 <= people[i] <= 10^9
Code & Explanation
- Create mixed events:
-
Flower start adds
+1, flower end adds-1atend + 1, and each person arrival is a query event. -
Sort events:
-
Process all events in time order so the active bloom count is always correct when a person arrives.
-
Answer queries during sweep:
- Maintain
blooming_flowerswhile sweeping; when a person event is seen, record the current count inresult.
Time & Space: O((f + p) log (f + p)) time for f flowers and p people; O(f + p) extra space for events.
7. My Calendar III (Leetcode:732)#
Problem Statement
A k-booking happens when k events have some non-empty intersection (i.e., there is some time that is common to all k events.)
You are given some events [startTime, endTime), after each given event, return an integer k representing the maximum k-booking between all the previous events.
Implement the MyCalendarThree class:
MyCalendarThree()Initializes the object.int book(int startTime, int endTime)Returns an integerkrepresenting the largest integer such that there exists ak-booking in the calendar.
Example 1:
Input
["MyCalendarThree", "book", "book", "book", "book", "book", "book"]
[[], [10, 20], [50, 60], [10, 40], [5, 15], [5, 10], [25, 55]]
Output
[null, 1, 1, 2, 3, 3, 3]
Explanation
MyCalendarThree myCalendarThree = new MyCalendarThree();
myCalendarThree.book(10, 20); // return 1
myCalendarThree.book(50, 60); // return 1
myCalendarThree.book(10, 40); // return 2
myCalendarThree.book(5, 15); // return 3
myCalendarThree.book(5, 10); // return 3
myCalendarThree.book(25, 55); // return 3
Constraints:
0 <= startTime < endTime <= 10^9
At most400calls will be made tobook.
Code & Explanation
- Timeline difference map:
-
+1atstartTime,-1atendTimemarks where active bookings change. -
Sweep active bookings:
-
Sort all timeline keys and walk left to right, accumulating the current overlap count.
-
Track maximum k-booking:
- After each
bookcall, update and return the highest overlap seen so far.
Time & Space: O(k log k) per book call; O(k) extra space for the timeline map.
8. Minimum Number of Taps to Open to Water a Garden (Leetcode:1326)#
Problem Statement
There is a one-dimensional garden on the x-axis. The garden starts at the point 0 and ends at the point n. (i.e., the length of the garden is n).
There are n + 1 taps located at points [0, 1, ..., n] in the garden.
Given an integer n and an integer array ranges of length n + 1 where ranges[i] (0-indexed) means the i-th tap can water the area [i - ranges[i], i + ranges[i]] if it was open.
Return the minimum number of taps that should be open to water the whole garden, If the garden cannot be watered return -1.
Example 1:
Input: n = 5, ranges = [3,4,1,1,0,0]
Output: 1
Explanation: The tap at point 0 can cover the interval [-3,3]
The tap at point 1 can cover the interval [-3,5]
The tap at point 2 can cover the interval [1,3]
The tap at point 3 can cover the interval [2,4]
The tap at point 4 can cover the interval [4,4]
The tap at point 5 can cover the interval [5,5]
Opening Only the second tap will water the whole garden [0,5]
Example 2:
Input: n = 3, ranges = [0,0,0,0]
Output: -1
Explanation: Even if you activate all the four taps you cannot water the whole garden.
Constraints:
1 <= n <= 104
ranges.length == n + 1
0 <= ranges[i] <= 100
Code & Explanation
- Convert taps to intervals:
- Tap
iwith rangercovers[max(0, i - r), min(n, i + r)]. -
Sort intervals by start so the sweep line can process them in order.
-
Sweep from left to right:
-
At each covered position, collect all intervals that start before the current coverage ends and track the farthest reachable point.
-
Take minimum jumps:
- Open one tap per sweep jump. If coverage cannot advance, return
-1.
Time & Space: O(n log n) time for sorting intervals; O(n) extra space.
9. Minimum Interval to Include Each Query (Leetcode:1851)#
Problem Statement
You are given a 2D integer array intervals, where intervals[i] = [lefti, righti] describes the ith interval starting at lefti and ending at righti (inclusive). The size of an interval is defined as the number of integers it contains, or more formally righti - lefti + 1.
You are also given an integer array queries. The answer to the jth query is the size of the smallest interval i such that lefti <= queries[j] <= righti. If no such interval exists, the answer is -1.
Return an array containing the answers to the queries.
Example 1:
Input: intervals = [[1,4],[2,4],[3,6],[4,4]], queries = [2,3,4,5]
Output: [3,3,1,4]
Explanation: The queries are processed as follows:
- Query = 2: The interval [2,4] is the smallest interval containing 2. The answer is 4 - 2 + 1 = 3.
- Query = 3: The interval [2,4] is the smallest interval containing 3. The answer is 4 - 2 + 1 = 3.
- Query = 4: The interval [4,4] is the smallest interval containing 4. The answer is 4 - 4 + 1 = 1.
- Query = 5: The interval [3,6] is the smallest interval containing 5. The answer is 6 - 3 + 1 = 4.
Example 2:
Input: intervals = [[2,3],[2,5],[1,8],[20,25]], queries = [2,19,5,22]
Output: [2,-1,4,6]
Explanation: The queries are processed as follows:
- Query = 2: The interval [2,3] is the smallest interval containing 2. The answer is 3 - 2 + 1 = 2.
- Query = 19: None of the intervals contain 19. The answer is -1.
- Query = 5: The interval [2,5] is the smallest interval containing 5. The answer is 5 - 2 + 1 = 4.
- Query = 22: The interval [20,25] is the smallest interval containing 22. The answer is 25 - 20 + 1 = 6.
Constraints:
1 <= intervals.length <= 1051 <= queries.length <= 105intervals[i].length == 21 <= lefti <= righti <= 1071 <= queries[j] <= 107
Code & Explanation
- Sort intervals by size:
-
Smaller intervals are considered first when multiple intervals cover a query.
-
Process queries in increasing order:
-
Add every interval whose left endpoint is
<= queryinto a min heap keyed by interval size. -
Remove expired intervals:
- Pop intervals whose right endpoint is
< query. - The heap top gives the smallest valid interval size, or
-1if the heap is empty.
Time & Space: O(n log n + q log q) time; O(n + q) extra space for the heap and result.
- Create sweep events:
-
Interval start adds its size to the active set; interval end removes it at
right + 1. -
Sort events and queries:
-
Walk both lists in time order so each query sees exactly the intervals covering it.
-
Track active interval sizes:
- The answer for a query is the minimum size among currently active intervals.
Time & Space: O((n + q) log (n + q)) time; O(n + q) extra space for events.
10. The Skyline Problem (Leetcode: 218)#
Problem Statement
A city's skyline is the outer contour of the silhouette formed by all the buildings in that city when viewed from a distance. Given the locations and heights of all the buildings, return the skyline formed by these buildings collectively.
The geometric information of each building is given in the array buildings where buildings[i] = [lefti, righti, heighti]:
leftiis the x coordinate of the left edge of theithbuilding.rightiis the x coordinate of the right edge of theithbuilding.heightiis the height of theithbuilding.
You may assume all buildings are perfect rectangles grounded on an absolutely flat surface at height 0.
The skyline should be represented as a list of "key points" sorted by their x-coordinate in the form [[x1,y1],[x2,y2],...]. Each key point is the left endpoint of some horizontal segment in the skyline except the last point in the list, which always has a y-coordinate 0 and is used to mark the skyline's termination where the rightmost building ends. Any ground between the leftmost and rightmost buildings should be part of the skyline's contour.
Note: There must be no consecutive horizontal lines of equal height in the output skyline. For instance, [...,[2 3],[4 5],[7 5],[11 5],[12 7],...] is not acceptable; the three lines of height 5 should be merged into one in the final output as such: [...,[2 3],[4 5],[12 7],...]
Example 1:
Input: buildings = [[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]]
Output: [[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]]
Explanation:
Figure A shows the buildings of the input.
Figure B shows the skyline formed by those buildings. The red points in figure B represent the key points in the output list.
Example 2:
Input: buildings = [[0,2,3],[2,5,3]]
Output: [[0,3],[5,0]]
Constraints:
1 <= buildings.length <= 1040 <= lefti < righti <= 231 - 11 <= heighti <= 231 - 1buildingsis sorted byleftiin non-decreasing order.
Code & Explanation
- Convert buildings to events:
- A start event uses negative height so taller buildings are processed first at the same x-coordinate.
-
An end event marks where a building stops contributing height.
-
Sweep with a max heap:
- The heap stores active building heights and their end coordinates.
-
Lazy deletion removes buildings whose right edge has passed the sweep line.
-
Emit key points:
- Whenever the maximum active height changes, append
[x, new_height]to the answer.
Time & Space: O(n log n) time for sorting events and heap operations; O(n) extra space.
- Divide and conquer:
-
Split the building list in half and recursively compute each half's skyline.
-
Merge two skylines:
-
Walk both skylines in x-order, tracking the current height from each side.
-
Keep only height changes:
- Append a point only when the combined maximum height changes, producing the final contour.
Time & Space: O(n log n) time via divide-and-conquer; O(n) extra space for recursion stack and merged results.
