Largest Number At Least Twice of Others
EasyPrompt
You are given an integer array nums where the largest integer is unique.
Determine whether the largest element in the array is at least twice as much as every other number in the array. If it is, return the index of the largest element, or return -1 otherwise.
Example 1:
Input: nums = [3,6,1,0]
Output: 1
Explanation: 6 is the largest integer.
For every other number in the array x, 6 is at least twice as big as x.
The index of value 6 is 1, so we return 1.Example 2:
Input: nums = [1,2,3,4]
Output: -1
Explanation: 4 is less than twice the value of 3, so we return -1.
Constraints:
2 <= nums.length <= 500 <= nums[i] <= 100- The largest element in
numsis unique.
Approaches
3 approaches with complexity analysis and trade-offs.
This approach involves sorting a copy of the array to easily identify the largest and second-largest elements. The comparison is then straightforward, but it requires finding the original index of the largest element.
Algorithm
- If the array has only one element, the condition is trivially met, so we return index 0.
- Create a copy of the input array
numsto preserve the original indices. - Sort the copied array in ascending order.
- The largest element is
sorted_nums[n-1]and the second largest issorted_nums[n-2]. - Check if
sorted_nums[n-1] >= 2 * sorted_nums[n-2]. If not, the condition fails, so return -1. - If the condition holds, we need the original index of the largest element. Iterate through the original
numsarray to find the first occurrence ofsorted_nums[n-1]and return its index.
Walkthrough
The core idea is that after sorting, the largest element will be the last element in the array, and the second-largest will be the second to last. This simplifies finding these two key values. Since sorting modifies the array, we must work on a copy to preserve the original indices, which are needed for the final result.
import java.util.Arrays; class Solution { public int dominantIndex(int[] nums) { // Constraints guarantee nums.length >= 2 int[] numsCopy = Arrays.copyOf(nums, nums.length); Arrays.sort(numsCopy); int maxVal = numsCopy[nums.length - 1]; int secondMaxVal = numsCopy[nums.length - 2]; if (maxVal < 2 * secondMaxVal) { return -1; } // Find the original index of the max value for (int i = 0; i < nums.length; i++) { if (nums[i] == maxVal) { return i; } } return -1; // Should not be reached due to problem constraints }}Complexity
Time
O(N log N) - Dominated by the sorting algorithm. Finding the index in the original array takes an additional O(N) time.
Space
O(N) - Required to store a copy of the array to preserve the original indices after sorting.
Trade-offs
Pros
The logic to find the largest and second-largest elements becomes very simple after sorting.
Cons
Less efficient in terms of time complexity compared to linear scan approaches.
Requires extra space for the array copy.
This approach iterates through the array twice. The first pass finds the largest element and its index. The second pass verifies if this largest element is at least twice as large as every other element.
Algorithm
- Initialize
maxValto the minimum possible value andmaxIndexto -1. - First Pass: Iterate through the
numsarray to find the largest elementmaxValand its indexmaxIndex. - Second Pass: Iterate through the
numsarray again. - For each element
numat indexi: Ifiis not themaxIndex, check ifmaxVal < 2 * num. If this condition is ever met, return -1 immediately. - If the second loop completes without returning, it means the condition holds for all other elements. Return
maxIndex.
Walkthrough
This is a straightforward approach that separates the problem into two distinct steps: finding the maximum and then verifying the condition. It's more efficient than sorting as it avoids the O(N log N) overhead by using linear scans.
class Solution { public int dominantIndex(int[] nums) { // Constraints guarantee nums.length >= 2 int maxVal = -1; int maxIndex = -1; // First pass: find the max element and its index for (int i = 0; i < nums.length; i++) { if (nums[i] > maxVal) { maxVal = nums[i]; maxIndex = i; } } // Second pass: check the condition for (int i = 0; i < nums.length; i++) { if (i != maxIndex && maxVal < 2 * nums[i]) { return -1; } } return maxIndex; }}Complexity
Time
O(N) - We perform two separate linear scans of the array, which results in O(N) + O(N) = O(N) time.
Space
O(1) - We only use a few variables to store the maximum value and its index, requiring constant extra space.
Trade-offs
Pros
Simple to implement and understand.
Efficient O(N) time complexity.
No extra space required.
Cons
Requires iterating through the array twice, which is less optimal than a single-pass solution.
The most efficient approach, which finds the largest and second-largest elements in a single pass through the array. After the pass, it performs a final check to see if the condition is met.
Algorithm
- Initialize
maxVal = -1,secondMaxVal = -1, andmaxIndex = -1. - Iterate through the
numsarray once. - For each element
numat indexi:- If
numis greater than the currentmaxVal, it means we've found a new largest number. The oldmaxValbecomes the newsecondMaxVal. UpdatesecondMaxVal = maxVal,maxVal = num, andmaxIndex = i. - Otherwise, if
numis greater than the currentsecondMaxVal(but notmaxVal), it's the new second-largest number. UpdatesecondMaxVal = num.
- If
- After the loop, we have the largest and second-largest values.
- Check if
maxVal >= 2 * secondMaxVal. If it is, returnmaxIndex. Otherwise, return -1.
Walkthrough
By keeping track of both the largest and second-largest numbers seen so far, we can solve the problem in one iteration. The key insight is that we only need to compare the largest number with the second-largest number. If the largest is at least twice the second-largest, it will also be at least twice every other number, as all other numbers are smaller than or equal to the second-largest.
class Solution { public int dominantIndex(int[] nums) { // Constraints guarantee nums.length >= 2 int maxVal = -1; int secondMaxVal = -1; int maxIndex = -1; for (int i = 0; i < nums.length; i++) { if (nums[i] > maxVal) { secondMaxVal = maxVal; maxVal = nums[i]; maxIndex = i; } else if (nums[i] > secondMaxVal) { secondMaxVal = nums[i]; } } if (maxVal >= 2 * secondMaxVal) { return maxIndex; } return -1; }}Complexity
Time
O(N) - The array is traversed only once.
Space
O(1) - Only a few variables are used to track the state, requiring constant extra space.
Trade-offs
Pros
Most optimal solution with linear time and constant space.
Processes the array in a single pass, making it very efficient.
Cons
The logic can be slightly more complex to reason about compared to a two-pass approach, as it involves updating two maximums simultaneously.
Solutions
Solution
class Solution {public int dominantIndex(int[] nums) { int n = nums.length; int k = 0; for (int i = 0; i < n; ++i) { if (nums[k] < nums[i]) { k = i; } } for (int i = 0; i < n; ++i) { if (k != i && nums[k] < nums[i] * 2) { return -1; } } return k; }}/** * @param {number[]} nums * @return {number} */ var dominantIndex = function (nums) { let k = 0; for (let i = 0; i < nums.length; ++i) { if (nums[i] > nums[k]) { k = i; } } for (let i = 0; i < nums.length; ++i) { if (i !== k && nums[k] < nums[i] * 2) { return -1; } } return k; };class Solution {public: int dominantIndex(vector<int> &nums) { int n = nums.size(); int k = 0; for (int i = 0; i < n; ++i) { if (nums[k] < nums[i]) { k = i; } } for (int i = 0; i < n; ++i) { if (k != i && nums[k] < nums[i] * 2) { return -1; } } return k; }};class Solution: def dominantIndex(self, nums: List[int]) -> int: x, y = nlargest(2, nums) return nums . index(x) if x >= 2 * y else - 1Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.