Second Largest Element in Array
Given an integer array nums, return the second largest distinct element in the array.
The answer must be strictly smaller than the largest element. Return -1 if fewer than two distinct values exist.
Example 1:
Input: nums = [12, 35, 1, 10, 34, 1]
Output: 34
Explanation: The largest element is 35, and the second-largest distinct element is 34.
Example 2:
Input: nums = [10, 10, 10]
Output: -1
Explanation: All elements are equal, so no second-largest distinct element exists.
Example 3:
Input: nums = [5]
Output: -1
Explanation: A single element cannot have a second-largest element.
Brute Force: Sorting
Sort a copy of the array, then look for the first value smaller than the largest.
- If the array has fewer than 2 elements, return
-1. - Make a copy of the array and sort it. The largest value is now at the end.
- Start from the second last index and move backward.
- Skip every value equal to
largest, because duplicates of the maximum are not distinct. - Return the first value smaller than
largest. - If no such value exists, return
-1.
class Solution {public:int secondLargest(vector<int>& nums) {int n = nums.size();if (n < 2) {return -1;}vector<int> sortedNums = nums;sort(sortedNums.begin(), sortedNums.end());int largest = sortedNums[n - 1];for (int index = n - 2; index >= 0; index--) {if (sortedNums[index] < largest) {return sortedNums[index];}}return -1;}};
- Time: O(n log n). Sorting is the slow part.
- Space: O(n). We keep a sorted copy of the array.
Better Approach: Two Passes
Sorting is not needed. We only care about the largest and the second largest. So we use two simple loops.
- If the array has fewer than 2 elements, return
-1. - Pass 1: find the
largestvalue. - Pass 2: look only at values strictly smaller than
largest, and keep the biggest one assecondLargest. - Use a flag
hasSecond, so we do not depend on a fake value like-1orINT_MIN. - If
hasSecondis true, returnsecondLargest. Otherwise return-1.
class Solution {public:int secondLargest(vector<int>& nums) {int n = nums.size();if (n < 2) {return -1;}int largest = nums[0];for (int index = 1; index < n; index++) {if (nums[index] > largest) {largest = nums[index];}}int secondLargest = 0;bool hasSecond = false;for (int current : nums) {if (current < largest) {if (!hasSecond || current > secondLargest) {secondLargest = current;hasSecond = true;}}}if (!hasSecond) {return -1;}return secondLargest;}};
- Time: O(n). Two passes, which is still linear.
- Space: O(1). We only use a few variables.
Optimal Approach: Single Pass
We can track both values in one pass.
- If the array has fewer than 2 elements, return
-1. - Set
largest = nums[0]. KeepsecondLargestand a flaghasSecond = false. - Loop from index 1. For each
current:- If
current > largest: the oldlargestbecomessecondLargest, thenlargest = current. SethasSecond = true. - Else if
current < largest: ifhasSecondis false orcurrent > secondLargest, updatesecondLargest = currentand sethasSecond = true. - If
current == largest: ignore it, because the answer must be distinct.
- If
- If
hasSecondis true, returnsecondLargest. Otherwise return-1.
class Solution {public:int secondLargest(vector<int>& nums) {int n = nums.size();if (n < 2) {return -1;}int largest = nums[0];int secondLargest = 0;bool hasSecond = false;for (int index = 1; index < n; index++) {int current = nums[index];if (current > largest) {secondLargest = largest;largest = current;hasSecond = true;} else if (current < largest) {if (!hasSecond || current > secondLargest) {secondLargest = current;hasSecond = true;}}}if (!hasSecond) {return -1;}return secondLargest;}};
Dry Run
Take nums = [12, 35, 1, 10, 34, 1] with the single pass approach.
1Start: largest = 12, secondLargest = none, hasSecond = false2 3Step | current | what happens | largest | secondLargest4-----|---------|----------------------------------------|---------|--------------5 1 | 35 | 35 > largest, old largest moves down | 35 | 126 2 | 1 | 1 < largest, but 1 > 12? No | 35 | 127 3 | 10 | 10 < largest, but 10 > 12? No | 35 | 128 4 | 34 | 34 < largest, and 34 > 12? Yes | 35 | 349 5 | 1 | 1 < largest, but 1 > 34? No | 35 | 3410 11hasSecond = true, so return secondLargest.12 13Return: 34Comparison of All Approaches
| Approach | Passes | Time | Space | Idea |
|---|---|---|---|---|
| Brute Force (Sorting) | Sort + 1 scan | O(n log n) | O(n) | Sort a copy, scan back for a smaller value |
| Better (Two Passes) | 2 | O(n) | O(1) | Find the largest, then the biggest value below it |
| Optimal (Single Pass) | 1 | O(n) | O(1) | Track both values together in one loop |
Complexity
Time: O(n)
We go through the array once, and each element needs only a few comparisons.
Space: O(1)
We only use three variables: largest, secondLargest, and hasSecond.
How to Explain It in an Interview
How to Explain it in an Interview
The 30-Second Spoken Pitch
"The simple idea is to sort a copy of the array and scan backward from the end, skipping duplicates of the maximum, until I find a smaller value. That is O of n log n time and O of n space. A better idea is to skip sorting. In the first pass I find the largest value, and in the second pass I find the biggest value that is strictly smaller than it. That is O of n time and O of 1 space. To make it a single pass, I keep largest, secondLargest, and a flag called hasSecond, so I do not rely on a fake sentinel value. If the current value is bigger than largest, the old largest becomes the second largest, and the current value becomes the new largest. If the current value is smaller than largest, I update the second largest when it is bigger than what I have, or when I do not have one yet. If the value equals largest, I ignore it, because the answer must be distinct. At the end, if hasSecond is true I return secondLargest, otherwise I return minus one. The time complexity is O of n and the space complexity is O of 1."
Next TopicRemove Duplicates from Sorted Array