Leaders in an Array | Brute to Optimal
This lecture covers the "Leaders in an Array" problem (also known as "Superior Elements" on various coding platforms). We will explore how to identify elements that are strictly greater than all elements to their right, transitioning from a naive brute-force approach to an optimal single-pass backward traversal.
1. Understanding the Problem & Definition of a Leader
An element in an array is called a Leader (or a Superior Element) if it is strictly greater than all the elements present on its right side.
Core Rules
- An element is a leader if and only if:
- The Last Element Rule: The last element of an array is always a leader because there are no elements to its right.
Visualizing with an Example
Consider the array: [10, 22, 12, 3, 0, 6]
Index: 0 1 2 3 4 5
Array: [10, 22, 12, 3, 0, 6]
- Is
22a leader? Yes. The elements to its right are[12, 3, 0, 6]. Since is strictly greater than all of them, it is a leader. - Is
12a leader? Yes. The elements to its right are[3, 0, 6]. Since is strictly greater than all of them, it is a leader. - Is
3a leader? No. The elements to its right are[0, 6]. Since , is not a leader. - Is
10a leader? No. Elements like22and12to its right are greater than . - Is
6a leader? Yes. It is the last element, so there are no elements to its right to challenge it.
2. Output Format Variations
Depending on the coding platform (e.g., LeetCode, GeeksforGeeks, Coding Ninjas), the required output format for the leaders can vary:
- Array Order (Original Sequence): The leaders must appear in the order they exist in the input array.
- Example Output:
[22, 12, 6]
- Example Output:
- Sorted Order: The leaders must be returned in ascending sorted order.
- Example Output:
[6, 12, 22]
- Example Output:
Note: Our primary goal is to design an efficient algorithm to collect all the leaders. Once collected, we can easily format, reverse, or sort the collection to match the platform's requirements.
3. The Brute Force Approach (Naive)
The most intuitive way to solve this problem is to simulate the definition directly. For every element in the array, we perform a linear search on its right side to verify if any element is greater than or equal to it.
Algorithm Workflow
- Use an outer loop with index
irunning from0ton - 1. - For each element
A[i], assume it is a leader by setting a boolean flagisLeader = true. - Run an inner loop with index
jfromi + 1ton - 1. - If any element
A[j] >= A[i]is found, setisLeader = falseand break out of the inner loop. - If
isLeaderremainstrueafter checking all elements to the right, addA[i]to the answer list.
4. Brute Force Code Implementation
C++
#include <vector>
std::vector<int> getLeadersBruteForce(std::vector<int>& a) {
std::vector<int> ans;
int n = a.size();
for (int i = 0; i < n; i++) {
bool isLeader = true;
// Check all elements to the right
for (int j = i + 1; j < n; j++) {
if (a[j] >= a[i]) {
isLeader = false;
break;
}
}
// If no element to the right was greater or equal
if (isLeader) {
ans.push_back(a[i]);
}
}
return ans;
}
Java
import java.util.ArrayList;
import java.util.List;
public class Solution {
public static List<Integer> getLeadersBruteForce(int[] a) {
List<Integer> ans = new ArrayList<>();
int n = a.length;
for (int i = 0; i < n; i++) {
boolean isLeader = true;
for (int j = i + 1; j < n; j++) {
if (a[j] >= a[i]) {
isLeader = false;
break;
}
}
if (isLeader) {
ans.add(a[i]);
}
}
return ans;
}
}
Python
def get_leaders_brute_force(a: list[int]) -> list[int]:
ans = []
n = len(a)
for i in range(n):
is_leader = True
for j in range(i + 1, n):
if a[j] >= a[i]:
is_leader = False
break
if is_leader:
ans.append(a[i])
return ans
Complexity Analysis (Brute Force)
- Time Complexity: In the worst-case scenario (e.g., a sorted array in ascending order), the inner loop runs approximately times.
- Space Complexity: auxiliary space.
If we consider the space used to store and return the answer, the worst-case space complexity is (e.g., when the array is strictly decreasing, like
[5, 4, 3, 2, 1], and every element is a leader).
5. The Optimal Approach (Right-to-Left Scan)
To optimize the time complexity, we must eliminate the redundant inner loop.
The Core Intuition
An element is a leader if it is greater than the maximum element present to its right.
By scanning the array from right to left (backwards), we can dynamically track the maximum element seen so far (maxi). This allows us to determine if the current element is a leader in time.
6. Step-by-Step Walkthrough of the Optimal Approach
Let's trace the optimal algorithm on the array [10, 22, 12, 3, 0, 6]:
-
Initialization:
- Set
maxi = INT_MIN(or a very small number). - Initialize an empty list
ansto collect leaders.
- Set
-
Trace Table:
- Post-Processing:
- The collected leaders in
ansare[6, 12, 22]. - If original array order is required: Reverse the array
ans[22, 12, 6]. - If sorted order is required: Sort the array
ans[6, 12, 22].
- The collected leaders in
7. Optimal Code Implementation
Below are the complete, production-grade implementations in C++, Java, and Python. These implementations include the sorting step to match platforms that require a sorted output.
C++
#include <vector>
#include <algorithm>
#include <climits>
std::vector<int> superiorElements(std::vector<int>& a) {
std::vector<int> ans;
int maxi = INT_MIN;
int n = a.size();
// Traverse the array from right to left
for (int i = n - 1; i >= 0; i--) {
if (a[i] > maxi) {
ans.push_back(a[i]);
maxi = a[i]; // Update the maximum element on the right
}
}
// If the platform requires sorted order:
std::sort(ans.begin(), ans.end());
// If original order was required instead, we would do:
// std::reverse(ans.begin(), ans.end());
return ans;
}
Java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Solution {
public static List<Integer> superiorElements(int[] a) {
List<Integer> ans = new ArrayList<>();
int maxi = Integer.MIN_VALUE;
int n = a.length;
// Traverse the array from right to left
for (int i = n - 1; i >= 0; i--) {
if (a[i] > maxi) {
ans.add(a[i]);
maxi = a[i]; // Update the maximum element on the right
}
}
// If the platform requires sorted order:
Collections.sort(ans);
// If original order was required instead, we would do:
// Collections.reverse(ans);
return ans;
}
}
Python
import sys
def superior_elements(a: list[int]) -> list[int]:
ans = []
maxi = -sys.maxsize - 1
n = len(a)
# Traverse the array from right to left
for i in range(n - 1, -1, -1):
if a[i] > maxi:
ans.append(a[i])
maxi = a[i] # Update the maximum element on the right
# If the platform requires sorted order:
ans.sort()
# If original order was required instead, we would do:
# ans.reverse()
return ans
8. Complexity Analysis (Optimal Approach)
Time Complexity
- Collection Phase: because we iterate through the array of size exactly once.
- Formatting Phase:
- If Reversing (Original Order): in the worst case.
- If Sorting (Sorted Order): where is the number of leaders. In the worst case (strictly decreasing array), , making the sorting step .
- Total Time Complexity: if only reversing is needed, or if sorting is required.
Space Complexity
- Auxiliary Space: as we only use a few variables (
maxi,i,n) to perform the computation. - Output Space: in the worst case to store and return the leaders.
9. Comparison of Approaches
Summary and Key Takeaways
- Leader Definition: An element is a leader if it is strictly greater than all elements to its right.
- The Last Element is Always a Leader: Because there are no elements to its right, the last element of any array always satisfies the leader condition.
- Brute Force Drawback: Checking every element against all elements to its right results in redundant comparisons and an inefficient time complexity.
- Optimal Traversal Direction: Scanning the array backwards (from right to left) allows us to maintain a running maximum (
maxi) of the elements processed so far. - Single-Pass Decision: With the running maximum, we can determine if any element is a leader in time by checking if
A[i] > maxi. - Post-Processing Flexibility: Backward traversal naturally collects leaders in reverse order. Depending on the problem constraints, we can easily reverse the output array in time or sort it in time.