Back to Heap Merge And Stacks
Maximum Width Ramp
Maximum Width Ramp
š§© Problem Statement
A ramp in an integer array nums is a pair (i, j) for which i < j and nums[i] <= nums[j]. The width of such a ramp is j - i.
Given an integer array nums, return the maximum width of a ramp in nums. If there is no ramp in nums, return 0.
š¹ Example 1:
Input:
nums = [6,0,8,2,1,5]
Output:
4
Explanation:
The maximum width ramp is achieved at (i, j) = (1, 5): nums[1] = 0 and nums[5] = 5. Width = 5 - 1 = 4.
š Approaches
1. Decreasing Stack + Reverse Iteration ($O(N)$)
- Concept: To maximize
j - iwhereA[i] <= A[j], we want the smallestipossible for a givenj. - Candidates for
i: We only care abouti's that are "potential starts" of a ramp. IfA[k] < A[i]andk < i, thenkis a strictly better candidate for a start index thanibecause it's further left and smaller (easier to satisfy $\le$). - Algorithm:
- Build a stack of indices
iwherenums[i]is strictly decreasing. This stack contains all candidates for the "start" of a ramp. - Iterate
jbackwards fromn-1to0. - While
stackis not empty andnums[stack.top()] <= nums[j]:
- We found a valid ramp!
width = j - stack.top().- Update max width.
stack.pop()(Becausestack.top()will never form a wider ramp with anyk < j, so we can discard it).
ā³ Time & Space Complexity
- Time Complexity: $O(N)$. Each element is pushed and popped at most once.
- Space Complexity: $O(N)$ for the stack.
š Code Implementations
C++
#include <vector>
#include <stack>
#include <iostream>
#include <algorithm>
using namespace std;
class Solution {
public:
int maxWidthRamp(vector<int>& nums) {
int n = nums.size();
stack<int> s;
for (int i = 0; i < n; i++) {
if (s.empty() || nums[s.top()] > nums[i]) {
s.push(i);
}
}
int maxWidth = 0;
for (int j = n - 1; j >= 0; j--) {
while (!s.empty() && nums[s.top()] <= nums[j]) {
maxWidth = max(maxWidth, j - s.top());
s.pop();
}
}
return maxWidth;
}
};
Python
from typing import List
class Solution:
def maxWidthRamp(self, nums: List[int]) -> int:
n = len(nums)
stack = []
# Build decreasing stack
for i in range(n):
if not stack or nums[stack[-1]] > nums[i]:
stack.append(i)
maxWidth = 0
# Traverse backwards
for j in range(n - 1, -1, -1):
while stack and nums[stack[-1]] <= nums[j]:
maxWidth = max(maxWidth, j - stack.pop())
return maxWidth
Java
import java.util.Stack;
class Solution {
public int maxWidthRamp(int[] nums) {
int n = nums.length;
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < n; i++) {
if (stack.isEmpty() || nums[stack.peek()] > nums[i]) {
stack.push(i);
}
}
int maxWidth = 0;
for (int j = n - 1; j >= 0; j--) {
while (!stack.isEmpty() && nums[stack.peek()] <= nums[j]) {
maxWidth = Math.max(maxWidth, j - stack.pop());
}
}
return maxWidth;
}
}
š Real-World Analogy
Building a Bridge:
You want to build the widest bridge. You plant potential left pillars only if the ground is lower than previous spots (so you can support a higher connection later?). Then you start from the far right and try to connect to the leftmost possible pillar that is lower than you.
šÆ Summary
ā Preprocessing Potential Starts: Identifying that we only need a decreasing subsequence for start indices is the key insight.
Solution Code
O(n) TimeO(1) Space
#include <algorithm>
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
class Solution {
public:
int maxWidthRamp(vector<int> &nums) {
int n = nums.size();
stack<int> s;
for (int i = 0; i < n; i++) {
if (s.empty() || nums[s.top()] > nums[i]) {
s.push(i);
}
}
int maxWidth = 0;
for (int j = n - 1; j >= 0; j--) {
while (!s.empty() && nums[s.top()] <= nums[j]) {
maxWidth = max(maxWidth, j - s.top());
s.pop();
}
}
return maxWidth;
}
};
int main() {
Solution sol;
vector<int> nums = {6, 0, 8, 2, 1, 5};
cout << "Test Case 1: " << sol.maxWidthRamp(nums) << endl; // Expect 4
return 0;
}
SYSTEM STABLEUTF-8 ⢠STATIC_RENDER