Problem
Given an integer array, determine whether there exist three elements at strictly increasing indices whose values are also strictly increasing. You only need to return true or false โ not the triplet itself.
- Input:
nums = [2, 1, 5, 0, 4, 6] - Output:
true - Explanation: Values 1, 4, and 6 appear in left-to-right order and satisfy 1 < 4 < 6.
Counter-example: nums = [5, 4, 3, 2, 1] returns false because every element is smaller than the one before it, so no increasing triplet can exist.
Intuition
This is the length-3 case of the longest increasing subsequence problem. The greedy insight is that you only need two "candidate" values: the smallest element seen so far, and the smallest element that already has something smaller before it. Any element that exceeds both candidates immediately confirms a valid triplet.
Approach 1 โ Precomputed Min/Max Arrays
For each index treated as the "middle" of the triplet, check whether a smaller element exists anywhere to its left and a larger element exists anywhere to its right.
Steps:
- Build
left_minwhereleft_min[i]is the minimum ofnums[0..i]. - Build
right_maxwhereright_max[i]is the maximum ofnums[i..n-1]. - For each middle index
jfrom 1 to n-2, check ifleft_min[j-1] < nums[j] < right_max[j+1]. - Return
Trueif any valid middle exists, otherwiseFalse.
1def increasingTriplet(nums: list[int]) -> bool:
2 n = len(nums)
3 if n < 3:
4 return False
5
6 left_min = [0] * n
7 left_min[0] = nums[0]
8 for i in range(1, n):
9 left_min[i] = min(left_min[i - 1], nums[i])
10
11 right_max = [0] * n
12 right_max[n - 1] = nums[n - 1]
13 for i in range(n - 2, -1, -1):
14 right_max[i] = max(right_max[i + 1], nums[i])
15
16 for j in range(1, n - 1):
17 if left_min[j - 1] < nums[j] < right_max[j + 1]:
18 return True
19
20 return False- Time: O(n) โ three linear passes over the array.
- Space: O(n) โ two auxiliary arrays of length n.
Approach 2 โ Greedy with Two Candidates
Track first (smallest element seen) and second (smallest element with a valid smaller predecessor). Any element exceeding second immediately completes a valid triplet.
Steps:
- Initialize
first = second = +โ. - For each number, apply exactly one of three cases:
num โค first: updatefirstโ new global minimum.num โค second: updatesecondโ better candidate middle element.- Otherwise:
num > second > some earlier first, returnTrue.
- Return
Falseif the loop ends without finding a triplet.
The non-obvious invariant: when first gets updated to a later, smaller value, second still encodes the promise that a valid (old_first, second) pair existed earlier in the array โ so any future value greater than second genuinely completes a triplet.
1def increasingTriplet(nums: list[int]) -> bool:
2 first = second = float('inf')
3
4 for num in nums:
5 if num <= first:
6 first = num # new global minimum, best candidate for first element
7 elif num <= second:
8 second = num # valid middle element relative to some earlier first
9 else:
10 return True # num > second, which itself had something smaller before it
11
12 return False- Time: O(n) โ single pass through the array.
- Space: O(1) โ two scalar variables regardless of input size.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| Precomputed arrays | O(n) | O(n) | When code clarity and explicit structure matter more than memory |
| Greedy two candidates | O(n) | O(1) | Space-constrained environments or whenever you need to impress in an interview |
Common Mistakes
- Discarding
secondwhenfirstis updated: When a new minimum overwritesfirst,secondremains valid because it was established relative to an earlier, largerfirst. The algorithm is correct even thoughfirstmay now point to an index aftersecond. - Using strict
<instead of<=when updating candidates: Changingnum <= firsttonum < firstbreaks arrays like[1, 1, 1, 2]โ the equal case should refreshfirst, not fall through to thesecondbranch. - Returning
Truewhennum == second: Equal values do not form a strictly increasing triplet, sonum == secondshould updatesecond, not trigger an early return โ this is why the thirdelsebranch fires only whennum > second. - Treating
firstandsecondas a positionally valid pair at any moment: They are not always positionally ordered.firstcan advance to a later index whilesecondholds a value from an earlier position. The logical invariant holds, but the raw indices may appear reversed. - Skipping the
n < 3guard in the array approach: The loop accessesright_max[j + 1]withjup ton - 2, which requires at least 3 elements; a 2-element input causes an index out of bounds without the guard.
Related Problems
longest-increasing-subsequenceโ the general form: find the longest increasing subsequence, of which this problem is the length-3 special case3sumโ also locates triplets satisfying a condition, but the constraint is a sum target rather than an orderingis-subsequenceโ verifying that elements appear in left-to-right order, the same positional constraint at the heart of this problemmaximum-subarrayโ greedy linear scan that tracks the best accumulated state at each index, same algorithmic flavornon-overlapping-intervalsโ greedy candidate selection under an ordering constraint to maximize a count