Intuition
The instability score at index i only depends on the running maximum of the elements up to i and the running minimum of the elements from i onward. Precompute both with two linear sweeps, then scan left-to-right for the first index whose score is <= k.
Explanation
Idea
The instability score at index i is max(nums[0..i]) - min(nums[i..n-1]). Recomputing that max and min from scratch at every index would be O(n) per index, or O(n^2) overall. But both quantities are running extremes, so we can precompute them.
prefixMax[i]= the maximum ofnums[0..i]. It satisfiesprefixMax[i] = max(prefixMax[i-1], nums[i]), so one left-to-right sweep fills it.suffixMin[i]= the minimum ofnums[i..n-1]. It satisfiessuffixMin[i] = min(suffixMin[i+1], nums[i]), so one right-to-left sweep fills it.
Once both arrays exist, score(i) = prefixMax[i] - suffixMin[i] is an O(1) lookup. Scan indices in increasing order and return the first one with score(i) <= k; if none qualifies, return -1.
Walk-through
Take nums = [5, 0, 1, 4], k = 3.
- Forward sweep (prefixMax): start with
prefixMax[0] = 5. Thenmax(5,0)=5,max(5,1)=5,max(5,4)=5->prefixMax = [5, 5, 5, 5]. - Backward sweep (suffixMin): start with
suffixMin[3] = 4. Thenmin(4,1)=1,min(1,0)=0,min(0,5)=0->suffixMin = [0, 0, 1, 4]. - Scan for the answer:
- i=0:
5 - 0 = 5 > 3. - i=1:
5 - 0 = 5 > 3. - i=2:
5 - 1 = 4 > 3. - i=3:
5 - 4 = 1 <= 3-> stable. Return 3.
- i=0:
Why it is correct
prefixMax is non-decreasing and suffixMin is non-increasing, but the score is not monotonic in general, so we cannot binary-search it — we must check indices in order to find the smallest stable one. The two sweeps guarantee every score lookup is exact and O(1).
Complexity
- Time: O(n) — two sweeps to build the arrays plus one scan.
- Space: O(n) — the
prefixMaxandsuffixMinarrays.
Implementation
class Solution {
public int firstStableIndex(int[] nums, int k) {
int n = nums.length;
int[] prefixMax = new int[n];
prefixMax[0] = nums[0];
for (int i = 1; i < n; i++) {
prefixMax[i] = Math.max(prefixMax[i - 1], nums[i]);
}
int[] suffixMin = new int[n];
suffixMin[n - 1] = nums[n - 1];
for (int i = n - 2; i >= 0; i--) {
suffixMin[i] = Math.min(suffixMin[i + 1], nums[i]);
}
for (int i = 0; i < n; i++) {
if (prefixMax[i] - suffixMin[i] <= k) {
return i;
}
}
return -1;
}
}