LeetCode 2016 - Maximum Difference Between Increasing Elements
The problem is asking us to find the maximum difference between two elements in an array, with the condition that the smaller element appears before the larger element.
Difficulty: 🟢 Easy
Topics: Array
Solution
Problem Understanding
The problem is asking us to find the maximum difference between two elements in an array, with the condition that the smaller element appears before the larger element. Formally, given a 0-indexed array nums of length n, we need to find the largest value of nums[j] - nums[i] where i < j and nums[i] < nums[j]. If no such pair exists, we return -1.
The input represents an integer array where each element is guaranteed to be at least 1 and at most 10^9. The array has at least two elements and at most 1000 elements, which is small enough that an O(n^2) solution may technically work, but an O(n) solution is preferable. The expected output is a single integer, either the maximum valid difference or -1.
Important edge cases include arrays that are strictly decreasing (where no valid pair exists), arrays where the maximum difference is at the last element minus the first element, and arrays where multiple pairs have the same maximum difference.
Approaches
The brute-force approach iterates through all possible pairs (i, j) where i < j. For each pair, we check if nums[i] < nums[j] and calculate the difference. We then keep track of the largest difference encountered. This is correct because it explicitly evaluates every valid pair, but it is inefficient for larger arrays due to its O(n^2) time complexity.
The optimal approach relies on the key insight that to maximize nums[j] - nums[i] with i < j, we only need to track the minimum value seen so far as we iterate through the array. For each element nums[j], the maximum difference using that element is nums[j] - min_value_so_far. We update the maximum difference whenever this value exceeds the current maximum, and we also update the min_value_so_far if nums[j] is smaller than the current minimum. This works in O(n) time with O(1) space.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n^2) | O(1) | Iterate over all pairs (i, j) and compute differences |
| Optimal | O(n) | O(1) | Track minimum value so far and compute differences on the fly |
Algorithm Walkthrough
- Initialize two variables:
min_valueto the first element of the array andmax_diffto-1.min_valuewill track the smallest element seen so far, ensuringi < j.max_diffwill store the maximum difference found that satisfiesnums[i] < nums[j]. - Iterate through the array starting from index
1(since index0is our initial minimum). - For each element
nums[j], ifnums[j]is greater thanmin_value, calculate the differencenums[j] - min_valueand updatemax_diffif this difference is larger than the currentmax_diff. - Regardless of the comparison, update
min_valueifnums[j]is smaller than the currentmin_value. - Continue this process until the end of the array.
- Return
max_diff, which will either be the maximum difference found or-1if no valid pair exists.
Why it works: At each step, min_value guarantees that the candidate difference is computed using a previous element that occurs before the current one. This ensures i < j. By iterating through the array once, we consider all valid pairs indirectly and track the largest difference, giving the correct result efficiently.
Python Solution
from typing import List
class Solution:
def maximumDifference(self, nums: List[int]) -> int:
min_value = nums[0]
max_diff = -1
for num in nums[1:]:
if num > min_value:
max_diff = max(max_diff, num - min_value)
min_value = min(min_value, num)
return max_diff
The implementation starts by initializing min_value to the first element and max_diff to -1. We iterate through the array starting from the second element. For each element, we check if it is larger than min_value. If so, we update max_diff. Regardless, we update min_value to ensure it always represents the smallest element seen so far. This follows the optimal algorithm described above.
Go Solution
func maximumDifference(nums []int) int {
minValue := nums[0]
maxDiff := -1
for _, num := range nums[1:] {
if num > minValue {
diff := num - minValue
if diff > maxDiff {
maxDiff = diff
}
}
if num < minValue {
minValue = num
}
}
return maxDiff
}
In Go, we follow the same logic. We initialize minValue to the first element and maxDiff to -1. Iterating through the slice from index 1, we update maxDiff whenever a larger valid difference is found and update minValue if the current number is smaller. There is no need for additional data structures, and we handle large integers natively.
Worked Examples
Example 1: nums = [7,1,5,4]
| Index | num | min_value | num > min_value? | max_diff |
|---|---|---|---|---|
| 0 | 7 | 7 | - | -1 |
| 1 | 1 | 1 | No | -1 |
| 2 | 5 | 1 | Yes | 4 |
| 3 | 4 | 1 | Yes | 4 |
Return 4.
Example 2: nums = [9,4,3,2]
| Index | num | min_value | num > min_value? | max_diff |
|---|---|---|---|---|
| 0 | 9 | 9 | - | -1 |
| 1 | 4 | 4 | No | -1 |
| 2 | 3 | 3 | No | -1 |
| 3 | 2 | 2 | No | -1 |
Return -1.
Example 3: nums = [1,5,2,10]
| Index | num | min_value | num > min_value? | max_diff |
|---|---|---|---|---|
| 0 | 1 | 1 | - | -1 |
| 1 | 5 | 1 | Yes | 4 |
| 2 | 2 | 1 | Yes | 4 |
| 3 | 10 | 1 | Yes | 9 |
Return 9.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Single pass through the array, comparing each element with min_value |
| Space | O(1) | Only two extra variables are used, regardless of input size |
The optimal solution achieves linear time because it only requires tracking the minimum seen so far and updating the maximum difference on the fly. No additional data structures or nested loops are necessary, resulting in constant space usage.
Test Cases
# Provided examples
assert Solution().maximumDifference([7,1,5,4]) == 4 # normal case
assert Solution().maximumDifference([9,4,3,2]) == -1 # strictly decreasing
assert Solution().maximumDifference([1,5,2,10]) == 9 # maximum difference at last element
# Edge cases
assert Solution().maximumDifference([1,2]) == 1 # smallest possible array
assert Solution().maximumDifference([2,1]) == -1 # two elements decreasing
assert Solution().maximumDifference([5,5,5,5]) == -1 # all elements equal
assert Solution().maximumDifference([1,2,3,4,5]) == 4 # strictly increasing
assert Solution().maximumDifference([10,1,10,1,10]) == 9 # alternating high-low values
| Test | Why |
|---|---|
| [7,1,5,4] | normal case with valid difference |
| [9,4,3,2] | strictly decreasing, no valid pair |
| [1,5,2,10] | maximum difference occurs at last element |
| [1,2] | minimal size array with valid difference |
| [2,1] | minimal size array with no valid difference |
| [5,5,5,5] | all elements equal, no valid difference |
| [1,2,3,4,5] | strictly increasing, max difference is last-first |
| [10,1,10,1,10] | multiple peaks, ensure algorithm finds largest difference |
Edge Cases
One important edge case is when the array is strictly decreasing, such as [9,4,3,2]. Here, there is no valid pair where nums[i] < nums[j]. The algorithm handles this correctly by initializing max_diff to -1 and never finding a valid difference.
Another edge case is when all elements are equal, e.g., [5,5,5,5]. In this situation, the condition nums[i] < nums[j] is never satisfied. Again, the initialization of max_diff to `-1