1762. Buildings With an Ocean View
Problem Description
In this problem, we are given an array heights
that represents the heights of buildings in a line, with the ocean situated to the right of the last building. The goal is to find out which buildings have an unobstructed view of the ocean. A building has an ocean view if all buildings to its right are shorter than it. We need to return a list of the indices of the buildings that can see the ocean. The list of indices should be sorted in increasing order and needs to be 0-indexed, which means the first building in the line has an index of 0.
Intuition
The solution involves iterating through the list of building heights in reverse (starting from the building farthest from the ocean). As we iterate, we maintain a running maximum height (mx
). When the current building's height exceeds this running maximum, it means this building has an ocean view, because there are no taller buildings to its right blocking its view of the ocean.
The steps for the solution are as follows:
- Initialize an empty list
ans
to store indices of buildings with ocean views. - Set a variable
mx
to 0 to keep track of the maximum height seen so far as we iterate backwards. - Loop through the heights array in reverse order (from last to first):
- Check if the current building's height is greater than
mx
, which is the tallest building observed to the right side of the current building. - If it is, the current building has an ocean view. We then:
- Append the index
i
of this building to theans
list. - Update the
mx
to the new maximum height.
- Append the index
- Check if the current building's height is greater than
- Since we filled
ans
in reverse order, we reverse it once more before returning to give the correct order of indices (from left to right).
By iterating from the end towards the beginning, we ensure that the mx
reflects the tallest building's height to the right of the current building. This way, each building is checked against only the relevant taller buildings that could potentially block its ocean view.
Learn more about Stack and Monotonic Stack patterns.
Solution Approach
The solution approach can be broken down into the following steps:
- We initialize an empty list
ans
that will eventually contain the indices of the buildings with an ocean view. - Define a variable
mx
to keep track of the maximum height encountered as we iterate through the list of buildings in reverse. This is initially set to0
. - We start a loop that iterates through the
heights
array from the last element (furthest from the ocean) towards the first element (closest to the ocean). - During each step of the loop, we compare the current building's height to
mx
. If the current height is greater, it means that this building has an unobstructed ocean view since all buildings to its right are shorter. - If the building has an ocean view, we append its index to the
ans
list and updatemx
to the current building's height, ensuring thatmx
always represents the tallest building encountered so far. - After iterating through all buildings, we reverse the
ans
list since we appended indices starting from the building closest to the ocean to get them sorted in the correct (increasing) order. The reasoning for this post-reversal is that indices are collected in decreasing order during the iteration from last to first.
This approach takes advantage of a simple greedy algorithm pattern, which, in this case, means that we always update our 'greedy' choice (mx
) to reflect the tallest encountered building so far. The mx
effectively "forgets" shorter buildings since they don't impact future comparisons.
In terms of data structures, only a simple list is used to keep track of the indices of buildings with an ocean view. The use of a list also allows us to efficiently reverse its contents at the end of our iteration.
Algorithm Complexity:
The time complexity of this solution is O(n)
, where n
is the number of buildings. This is because we have to iterate through all the buildings at least once. The space complexity is also O(n)
in the worst case, which occurs when all buildings have an ocean view, and we need a list of the same length as the input to store the indices.
The solution code utilizing this approach looks like this:
class Solution:
def findBuildings(self, heights: List[int]) -> List[int]:
ans = []
mx = 0
for i in range(len(heights) - 1, -1, -1):
if heights[i] > mx:
ans.append(i)
mx = heights[i]
return ans[::-1]
This code translates the approach described above into Python, taking advantage of the language's list and loop constructs to efficiently solve the problem.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's apply the solution approach to a small example. Consider the following array of building heights:
heights = [4, 2, 3, 1]
We want to find out which buildings have an unobstructed view of the ocean. Our ocean is to the right, so we need to see which buildings are not blocked by buildings of greater height to their right.
We start by initializing an empty list ans
to store indices and a variable mx
with a value of 0 to keep track of the maximum height we've seen so far.
Then we iterate backwards through the array:
- We start with the last building (index 3), height is 1.
mx
is 0. Since 1 > 0, we add index 3 toans
and updatemx
to 1. - Move to the next building (index 2), height is 3. Now, 3 > 1 (current
mx
), so we add this index (2) toans
and updatemx
to 3. - The next building's height (index 1) is 2. Because 2 is not greater than 3 (current
mx
), we don't do anything. - We now reach the first building (index 0), height is 4. Since 4 > 3, we add index 0 to
ans
and updatemx
to 4.
After iterating through the array, ans
is [0, 2, 3]
. However, this is in reverse order, so we reverse it to [3, 2, 0]
.
Buildings at indices 3, 2, and 0 have an unobstructed view of the ocean. The result is sorted in increasing order, as required by the problem statement.
Solution Implementation
1class Solution:
2 def findBuildings(self, heights: List[int]) -> List[int]:
3 # Initialize an empty list to hold the indices of buildings with an ocean view
4 ocean_view_indices = []
5
6 # Initialize the maximum height found so far to 0
7 max_height = 0
8
9 # Iterate from the last building back to the first
10 for i in range(len(heights) - 1, -1, -1):
11 # Compare the current building's height with the max height found so far
12 if heights[i] > max_height:
13 # If the current building is taller, it has an ocean view
14 # So we add its index to our list
15 ocean_view_indices.append(i)
16 # Update the max_height to the current building's height
17 max_height = heights[i]
18
19 # The resulting list is in reverse order, so we reverse it before returning
20 return ocean_view_indices[::-1]
21
1class Solution {
2 // This method finds the buildings that have an ocean view, given the heights of the buildings.
3 // A building has an ocean view if all buildings to its right have a smaller height.
4 public int[] findBuildings(int[] heights) {
5 // Number of buildings
6 int numberOfBuildings = heights.length;
7
8 // List to store indices of buildings with an ocean view
9 List<Integer> buildingsWithView = new ArrayList<>();
10
11 // Keep track of the maximum height seen so far from the right
12 int maxRightHeight = 0;
13
14 // Iterate buildings from right to left to check for ocean view
15 for (int i = numberOfBuildings - 1; i >= 0; --i) {
16 // If the current building is taller than the max height seen so far to its right,
17 // it has an ocean view
18 if (heights[i] > maxRightHeight) {
19 // Add the current building's index to the list
20 buildingsWithView.add(i);
21 // Update the max height seen so far to the height of the current building
22 maxRightHeight = heights[i];
23 }
24 }
25
26 // Since we traversed from right to left, reverse the list to maintain the original order
27 Collections.reverse(buildingsWithView);
28
29 // Convert the List<Integer> to int[] for the final answer
30 return buildingsWithView.stream().mapToInt(Integer::intValue).toArray();
31 }
32}
33
1#include <vector>
2#include <algorithm>
3
4class Solution {
5public:
6 // Function to find the buildings that can see the ocean
7 vector<int> findBuildings(vector<int>& heights) {
8 // The answer vector to store indices of the ocean-view buildings
9 vector<int> oceanViewBuildings;
10 // Variable to keep track of the maximum height observed as we scan from right to left
11 int max_height_so_far = 0;
12
13 // Iterate over the input 'heights' vector from right to left
14 for (int i = heights.size() - 1; i >= 0; --i) {
15 // If the current building's height is greater than the maximum height observed so far
16 if (heights[i] > max_height_so_far) {
17 // Add the index of this building to the ocean-view list
18 oceanViewBuildings.push_back(i);
19 // Update the maximum height to the height of the current building
20 max_height_so_far = heights[i];
21 }
22 }
23
24 // Since we added the indices in reverse order, we need to reverse the oceanViewBuildings vector
25 reverse(oceanViewBuildings.begin(), oceanViewBuildings.end());
26
27 // Return the final list of ocean-view building indices
28 return oceanViewBuildings;
29 }
30};
31
1function findBuildings(heights: number[]): number[] {
2 // Create an array to store the indices of the buildings with an ocean view.
3 const buildingsWithViews: number[] = [];
4 // Initialize a variable to keep track of the maximum height found so far as we iterate from right to left.
5 let maxHeight = 0;
6
7 // Start iterating from the last building towards the first.
8 for (let i = heights.length - 1; i >= 0; --i) {
9 // Check if the current building height is greater than the maximum height found.
10 if (heights[i] > maxHeight) {
11 // If so, add the index of this building to our result array.
12 buildingsWithViews.push(i);
13 // Update maxHeight to the height of the current building.
14 maxHeight = heights[i];
15 }
16 }
17
18 // Since we traversed the buildings from right to left, the resulting array is in reverse order.
19 // Reverse the array to return the indices in the correct order, from left to right.
20 return buildingsWithViews.reverse();
21}
22
Time and Space Complexity
Time Complexity
The time complexity of the given code can be determined by analyzing the loop that iterates in reverse through the list of heights
. Since the loop runs exactly once for each element in the heights
array, which has n
elements, this gives us a time complexity of O(n)
where n
is the length of the heights
array.
Space Complexity
The space complexity of the code is mainly due to the ans
list which stores the indices of buildings with an unobstructed view. In the worst case, all buildings can see the ocean, so the space taken by the ans
list can be n
in the worst case. Thus, the space complexity is O(n)
. Also, note that this does not account for the space used to store the input heights
as that is not part of the space used by the algorithm itself.
Learn more about how to find time and space complexity quickly using problem constraints.
What data structure does Breadth-first search typically uses to store intermediate states?
Recommended Readings
Stack Intro Imagine you have a pile of books on your desk If you want to add a new book you place it on top If you want to read a book you take it from the top And if you simply want to see which book is on the top you
Monotonic Stack Deque Intro If you'd prefer a video div class responsive iframe iframe src https www youtube com embed Dq_ObZwTY_Q title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div The word monotonic means a list or
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Want a Structured Path to Master System Design Too? Don’t Miss This!