Problem

You are given an array nums of n integers and an integer k.

For each subarray of nums, you can apply up to k operations on it. In each operation, you increment any element of the subarray by 1.

Note that each subarray is considered independently, meaning changes made to one subarray do not persist to another.

Return the number of subarrays that you can make non-decreasing ​​​​​after performing at most k operations.

An array is said to be non-decreasing if each element is greater than or equal to its previous element, if it exists.

Examples

Example 1

1
2
3
4
5
6
7
Input: nums = [6,3,1,2,4,4], k = 7
Output: 17
Explanation:
Out of all 21 possible subarrays of `nums`, only the subarrays `[6, 3, 1]`,
`[6, 3, 1, 2]`, `[6, 3, 1, 2, 4]` and `[6, 3, 1, 2, 4, 4]` cannot be made non-
decreasing after applying up to k = 7 operations. Thus, the number of non-
decreasing subarrays is `21 - 4 = 17`.

Example 2

1
2
3
4
5
6
7
8
Input: nums = [6,3,1,3,6], k = 4
Output: 12
Explanation:
The subarray `[3, 1, 3, 6]` along with all subarrays of `nums` with three or
fewer elements, except `[6, 3, 1]`, can be made non-decreasing after `k`
operations. There are 5 subarrays of a single element, 4 subarrays of two
elements, and 2 subarrays of three elements except `[6, 3, 1]`, so there are
`1 + 5 + 4 + 2 = 12` subarrays that can be made non-decreasing.

Constraints

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^9
  • 1 <= k <= 10^9

Solution

Method 1 – Sliding Window with Greedy Increment Tracking

Intuition

For each subarray, we want to know if we can make it non-decreasing by incrementing elements at most k times. We can use a sliding window and, for each window, calculate the minimum number of increments needed to make the subarray non-decreasing. If the total increments needed is ≤ k, the subarray is valid.

Approach

  1. For each possible starting index i, expand the window to the right as far as possible such that the total increments needed does not exceed k.
  2. For each window, keep track of the required increments to make the subarray non-decreasing:
    • If the next element is less than the previous, we need to increment it to match the previous value.
    • Accumulate the total increments needed.
  3. For each valid window, count the subarray.
  4. Return the total count.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
    long long countNonDecreasingSubarrays(vector<int>& nums, int k) {
        int n = nums.size();
        long long ans = 0;
        for (int i = 0; i < n; ++i) {
            int ops = 0;
            int prev = nums[i];
            for (int j = i; j < n; ++j) {
                if (nums[j] < prev) {
                    ops += prev - nums[j];
                }
                if (ops > k) break;
                ans++;
                prev = max(prev, nums[j]);
            }
        }
        return ans;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
func CountNonDecreasingSubarrays(nums []int, k int) int64 {
    n := len(nums)
    var ans int64
    for i := 0; i < n; i++ {
        ops := 0
        prev := nums[i]
        for j := i; j < n; j++ {
            if nums[j] < prev {
                ops += prev - nums[j]
            }
            if ops > k {
                break
            }
            ans++
            if nums[j] > prev {
                prev = nums[j]
            }
        }
    }
    return ans
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Solution {
    public long countNonDecreasingSubarrays(int[] nums, int k) {
        int n = nums.length;
        long ans = 0;
        for (int i = 0; i < n; i++) {
            int ops = 0, prev = nums[i];
            for (int j = i; j < n; j++) {
                if (nums[j] < prev) {
                    ops += prev - nums[j];
                }
                if (ops > k) break;
                ans++;
                prev = Math.max(prev, nums[j]);
            }
        }
        return ans;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution {
    fun countNonDecreasingSubarrays(nums: IntArray, k: Int): Long {
        val n = nums.size
        var ans = 0L
        for (i in 0 until n) {
            var ops = 0
            var prev = nums[i]
            for (j in i until n) {
                if (nums[j] < prev) {
                    ops += prev - nums[j]
                }
                if (ops > k) break
                ans++
                prev = maxOf(prev, nums[j])
            }
        }
        return ans
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution:
    def countNonDecreasingSubarrays(self, nums: list[int], k: int) -> int:
        n = len(nums)
        ans = 0
        for i in range(n):
            ops = 0
            prev = nums[i]
            for j in range(i, n):
                if nums[j] < prev:
                    ops += prev - nums[j]
                if ops > k:
                    break
                ans += 1
                prev = max(prev, nums[j])
        return ans
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
impl Solution {
    pub fn count_non_decreasing_subarrays(nums: Vec<i32>, k: i32) -> i64 {
        let n = nums.len();
        let mut ans = 0i64;
        for i in 0..n {
            let mut ops = 0;
            let mut prev = nums[i];
            for j in i..n {
                if nums[j] < prev {
                    ops += prev - nums[j];
                }
                if ops > k {
                    break;
                }
                ans += 1;
                prev = prev.max(nums[j]);
            }
        }
        ans
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Solution {
    countNonDecreasingSubarrays(nums: number[], k: number): number {
        const n = nums.length;
        let ans = 0;
        for (let i = 0; i < n; i++) {
            let ops = 0, prev = nums[i];
            for (let j = i; j < n; j++) {
                if (nums[j] < prev) {
                    ops += prev - nums[j];
                }
                if (ops > k) break;
                ans++;
                prev = Math.max(prev, nums[j]);
            }
        }
        return ans;
    }
}

Complexity

  • ⏰ Time complexity: O(n^2), since we check all subarrays.
  • 🧺 Space complexity: O(1), only constant extra space is used.

Method 2 – Sliding Window with Next Greater Index (NGI)

Intuition

If a subarray [L, R] can be made non-decreasing with at most k operations, then any subarray [L, X] where L ≤ X ≤ R can also be made non-decreasing. For a subarray, the minimum operations needed to make all elements equal to the largest value T is (R - L + 1) * T - sum(L, R). This linear relationship allows efficient window adjustment.

Approach

  1. Precompute the next greater index (ngi) for each element using a stack.
  2. Use a sliding window [idx, i] to track the current valid subarray.
  3. Maintain the largest value in the window (curLargeValue) and the total operations needed (totalK).
  4. If totalK exceeds k, adjust the window using ngi to efficiently skip invalid regions.
  5. For each valid window, count the subarrays ending at i.
  6. After processing, add the remaining valid subarrays.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#define ll long long
class Solution {
public:
    long long countNonDecreasingSubarrays(vector<int>& nums, int k) {
        int n = nums.size();
        stack<int> st;
        vector<int> ngi(n, n);
        for (int i = 0; i < n; i++) {
            while (!st.empty() && nums[i] > nums[st.top()]) {
                ngi[st.top()] = i;
                st.pop();
            }
            st.push(i);
        }
        int idx = 0;
        ll count = 0;
        int curLargeValue = nums[idx];
        ll totalK = 0;
        for (int i = 0; i < n; i++) {
            if (nums[i] > curLargeValue) {
                curLargeValue = nums[i];
            } else {
                totalK += curLargeValue - nums[i];
            }
            while (totalK > k) {
                count += i - idx;
                if (nums[idx + 1] >= nums[idx]) {
                    idx++;
                } else {
                    ll prev = nums[idx];
                    ll prevIdx = idx;
                    ll cur = nums[idx + 1];
                    ll curIdx = idx + 1;
                    curLargeValue = cur;
                    while (ngi[curIdx] <= i && ngi[prevIdx] != ngi[curIdx]) {
                        totalK -= (prev - cur) * (ngi[curIdx] - curIdx);
                        curIdx = ngi[curIdx];
                        cur = nums[curIdx];
                        curLargeValue = cur;
                    }
                    if (i >= ngi[curIdx] && ngi[prevIdx] == ngi[curIdx]) {
                        totalK -= (prev - cur) * (ngi[curIdx] - curIdx);
                        curLargeValue = nums[ngi[curIdx]];
                        cur = curLargeValue;
                        curIdx = ngi[curIdx];
                        prev = cur;
                        prevIdx = curIdx;
                        while (i >= ngi[curIdx] && ngi[prevIdx] == ngi[curIdx]) {
                            curLargeValue = nums[ngi[curIdx]];
                            curIdx = ngi[curIdx];
                            prev = cur;
                            prevIdx = curIdx;
                        }
                    } else {
                        totalK -= (prev - cur) * (i - curIdx + 1);
                    }
                    idx++;
                }
            }
        }
        count += 1ll * (n - idx) * (n - idx + 1) / 2;
        return count;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
func countNonDecreasingSubarrays(nums []int, k int) int64 {
    n := len(nums)
    ngi := make([]int, n)
    for i := range ngi {
        ngi[i] = n
    }
    st := []int{}
    for i := 0; i < n; i++ {
        for len(st) > 0 && nums[i] > nums[st[len(st)-1]] {
            ngi[st[len(st)-1]] = i
            st = st[:len(st)-1]
        }
        st = append(st, i)
    }
    idx := 0
    count := int64(0)
    curLargeValue := nums[idx]
    totalK := int64(0)
    for i := 0; i < n; i++ {
        if nums[i] > curLargeValue {
            curLargeValue = nums[i]
        } else {
            totalK += int64(curLargeValue - nums[i])
        }
        for totalK > int64(k) {
            count += int64(i - idx)
            if nums[idx+1] >= nums[idx] {
                idx++
            } else {
                prev := nums[idx]
                prevIdx := idx
                cur := nums[idx+1]
                curIdx := idx+1
                curLargeValue = cur
                for ngi[curIdx] <= i && ngi[prevIdx] != ngi[curIdx] {
                    totalK -= int64(prev-cur) * int64(ngi[curIdx]-curIdx)
                    curIdx = ngi[curIdx]
                    cur = nums[curIdx]
                    curLargeValue = cur
                }
                if i >= ngi[curIdx] && ngi[prevIdx] == ngi[curIdx] {
                    totalK -= int64(prev-cur) * int64(ngi[curIdx]-curIdx)
                    curLargeValue = nums[ngi[curIdx]]
                    cur = curLargeValue
                    curIdx = ngi[curIdx]
                    prev = cur
                    prevIdx = curIdx
                    for i >= ngi[curIdx] && ngi[prevIdx] == ngi[curIdx] {
                        curLargeValue = nums[ngi[curIdx]]
                        curIdx = ngi[curIdx]
                        prev = cur
                        prevIdx = curIdx
                    }
                } else {
                    totalK -= int64(prev-cur) * int64(i-curIdx+1)
                }
                idx++
            }
        }
    }
    count += int64(n-idx) * int64(n-idx+1) / 2
    return count
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class Solution {
    public long countNonDecreasingSubarrays(int[] nums, int k) {
        int n = nums.length;
        int[] ngi = new int[n];
        Arrays.fill(ngi, n);
        Deque<Integer> st = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            while (!st.isEmpty() && nums[i] > nums[st.peek()]) {
                ngi[st.pop()] = i;
            }
            st.push(i);
        }
        int idx = 0;
        long count = 0;
        int curLargeValue = nums[idx];
        long totalK = 0;
        for (int i = 0; i < n; i++) {
            if (nums[i] > curLargeValue) {
                curLargeValue = nums[i];
            } else {
                totalK += curLargeValue - nums[i];
            }
            while (totalK > k) {
                count += i - idx;
                if (nums[idx + 1] >= nums[idx]) {
                    idx++;
                } else {
                    long prev = nums[idx];
                    int prevIdx = idx;
                    long cur = nums[idx + 1];
                    int curIdx = idx + 1;
                    curLargeValue = (int)cur;
                    while (ngi[curIdx] <= i && ngi[prevIdx] != ngi[curIdx]) {
                        totalK -= (prev - cur) * (ngi[curIdx] - curIdx);
                        curIdx = ngi[curIdx];
                        cur = nums[curIdx];
                        curLargeValue = (int)cur;
                    }
                    if (i >= ngi[curIdx] && ngi[prevIdx] == ngi[curIdx]) {
                        totalK -= (prev - cur) * (ngi[curIdx] - curIdx);
                        curLargeValue = nums[ngi[curIdx]];
                        cur = curLargeValue;
                        curIdx = ngi[curIdx];
                        prev = cur;
                        prevIdx = curIdx;
                        while (i >= ngi[curIdx] && ngi[prevIdx] == ngi[curIdx]) {
                            curLargeValue = nums[ngi[curIdx]];
                            curIdx = ngi[curIdx];
                            prev = cur;
                            prevIdx = curIdx;
                        }
                    } else {
                        totalK -= (prev - cur) * (i - curIdx + 1);
                    }
                    idx++;
                }
            }
        }
        count += 1L * (n - idx) * (n - idx + 1) / 2;
        return count;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class Solution {
    fun countNonDecreasingSubarrays(nums: IntArray, k: Int): Long {
        val n = nums.size
        val ngi = IntArray(n) { n }
        val st = ArrayDeque<Int>()
        for (i in 0 until n) {
            while (st.isNotEmpty() && nums[i] > nums[st.last()]) {
                ngi[st.removeLast()] = i
            }
            st.addLast(i)
        }
        var idx = 0
        var count = 0L
        var curLargeValue = nums[idx]
        var totalK = 0L
        for (i in 0 until n) {
            if (nums[i] > curLargeValue) {
                curLargeValue = nums[i]
            } else {
                totalK += curLargeValue - nums[i]
            }
            while (totalK > k) {
                count += i - idx
                if (nums[idx + 1] >= nums[idx]) {
                    idx++
                } else {
                    var prev = nums[idx].toLong()
                    var prevIdx = idx
                    var cur = nums[idx + 1].toLong()
                    var curIdx = idx + 1
                    curLargeValue = cur.toInt()
                    while (ngi[curIdx] <= i && ngi[prevIdx] != ngi[curIdx]) {
                        totalK -= (prev - cur) * (ngi[curIdx] - curIdx)
                        curIdx = ngi[curIdx]
                        cur = nums[curIdx].toLong()
                        curLargeValue = cur.toInt()
                    }
                    if (i >= ngi[curIdx] && ngi[prevIdx] == ngi[curIdx]) {
                        totalK -= (prev - cur) * (ngi[curIdx] - curIdx)
                        curLargeValue = nums[ngi[curIdx]]
                        cur = curLargeValue.toLong()
                        curIdx = ngi[curIdx]
                        prev = cur
                        prevIdx = curIdx
                        while (i >= ngi[curIdx] && ngi[prevIdx] == ngi[curIdx]) {
                            curLargeValue = nums[ngi[curIdx]]
                            curIdx = ngi[curIdx]
                            prev = cur
                            prevIdx = curIdx
                        }
                    } else {
                        totalK -= (prev - cur) * (i - curIdx + 1)
                    }
                    idx++
                }
            }
        }
        count += 1L * (n - idx) * (n - idx + 1) / 2
        return count
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class Solution:
    def countNonDecreasingSubarrays(self, nums: list[int], k: int) -> int:
        n = len(nums)
        ngi = [n] * n
        st = []
        for i in range(n):
            while st and nums[i] > nums[st[-1]]:
                ngi[st.pop()] = i
            st.append(i)
        idx = 0
        count = 0
        curLargeValue = nums[idx]
        totalK = 0
        for i in range(n):
            if nums[i] > curLargeValue:
                curLargeValue = nums[i]
            else:
                totalK += curLargeValue - nums[i]
            while totalK > k:
                count += i - idx
                if nums[idx + 1] >= nums[idx]:
                    idx += 1
                else:
                    prev = nums[idx]
                    prevIdx = idx
                    cur = nums[idx + 1]
                    curIdx = idx + 1
                    curLargeValue = cur
                    while ngi[curIdx] <= i && ngi[prevIdx] != ngi[curIdx]:
                        totalK -= (prev - cur) * (ngi[curIdx] - curIdx)
                        curIdx = ngi[curIdx]
                        cur = nums[curIdx]
                        curLargeValue = cur
                    if i >= ngi[curIdx] && ngi[prevIdx] == ngi[curIdx]:
                        totalK -= (prev - cur) * (ngi[curIdx] - curIdx)
                        curLargeValue = nums[ngi[curIdx]]
                        cur = curLargeValue
                        curIdx = ngi[curIdx]
                        prev = cur
                        prevIdx = curIdx
                        while i >= ngi[curIdx] && ngi[prevIdx] == ngi[curIdx]:
                            curLargeValue = nums[ngi[curIdx]]
                            curIdx = ngi[curIdx]
                            prev = cur
                            prevIdx = curIdx
                    else:
                        totalK -= (prev - cur) * (i - curIdx + 1)
                    idx += 1
        count += (n - idx) * (n - idx + 1) // 2
        return count
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
impl Solution {
    pub fn count_non_decreasing_subarrays(nums: Vec<i32>, k: i32) -> i64 {
        let n = nums.len();
        let mut ngi = vec![n; n];
        let mut st = Vec::new();
        for i in 0..n {
            while let Some(&top) = st.last() {
                if nums[i] > nums[top] {
                    ngi[top] = i;
                    st.pop();
                } else {
                    break;
                }
            }
            st.push(i);
        }
        let mut idx = 0;
        let mut count = 0i64;
        let mut cur_large = nums[idx];
        let mut total_k = 0i64;
        for i in 0..n {
            if nums[i] > cur_large {
                cur_large = nums[i];
            } else {
                total_k += (cur_large - nums[i]) as i64;
            }
            while total_k > k as i64 {
                count += (i - idx) as i64;
                if nums[idx + 1] >= nums[idx] {
                    idx += 1;
                } else {
                    let mut prev = nums[idx] as i64;
                    let mut prev_idx = idx;
                    let mut cur = nums[idx + 1] as i64;
                    let mut cur_idx = idx + 1;
                    cur_large = cur as i32;
                    while ngi[cur_idx] <= i && ngi[prev_idx] != ngi[cur_idx] {
                        total_k -= (prev - cur) * (ngi[cur_idx] as i64 - cur_idx as i64);
                        cur_idx = ngi[cur_idx];
                        cur = nums[cur_idx] as i64;
                        cur_large = cur as i32;
                    }
                    if i >= ngi[cur_idx] && ngi[prev_idx] == ngi[cur_idx] {
                        total_k -= (prev - cur) * (ngi[cur_idx] as i64 - cur_idx as i64);
                        cur_large = nums[ngi[cur_idx]];
                        cur = cur_large as i64;
                        cur_idx = ngi[cur_idx];
                        prev = cur;
                        prev_idx = cur_idx;
                        while i >= ngi[cur_idx] && ngi[prev_idx] == ngi[cur_idx] {
                            cur_large = nums[ngi[cur_idx]];
                            cur_idx = ngi[cur_idx];
                            prev = cur;
                            prev_idx = cur_idx;
                        }
                    } else {
                        total_k -= (prev - cur) * ((i - cur_idx + 1) as i64);
                    }
                    idx += 1;
                }
            }
        }
        count += ((n - idx) as i64) * ((n - idx + 1) as i64) / 2;
        count
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class Solution {
    countNonDecreasingSubarrays(nums: number[], k: number): number {
        const n = nums.length;
        const ngi: number[] = Array(n).fill(n);
        const st: number[] = [];
        for (let i = 0; i < n; i++) {
            while (st.length && nums[i] > nums[st[st.length - 1]]) {
                ngi[st.pop()!] = i;
            }
            st.push(i);
        }
        let idx = 0;
        let count = 0;
        let curLargeValue = nums[idx];
        let totalK = 0;
        for (let i = 0; i < n; i++) {
            if (nums[i] > curLargeValue) {
                curLargeValue = nums[i];
            } else {
                totalK += curLargeValue - nums[i];
            }
            while (totalK > k) {
                count += i - idx;
                if (nums[idx + 1] >= nums[idx]) {
                    idx++;
                } else {
                    let prev = nums[idx];
                    let prevIdx = idx;
                    let cur = nums[idx + 1];
                    let curIdx = idx + 1;
                    curLargeValue = cur;
                    while (ngi[curIdx] <= i && ngi[prevIdx] != ngi[curIdx]) {
                        totalK -= (prev - cur) * (ngi[curIdx] - curIdx);
                        curIdx = ngi[curIdx];
                        cur = nums[curIdx];
                        curLargeValue = cur;
                    }
                    if (i >= ngi[curIdx] && ngi[prevIdx] == ngi[curIdx]) {
                        totalK -= (prev - cur) * (ngi[curIdx] - curIdx);
                        curLargeValue = nums[ngi[curIdx]];
                        cur = curLargeValue;
                        curIdx = ngi[curIdx];
                        prev = cur;
                        prevIdx = curIdx;
                        while (i >= ngi[curIdx] && ngi[prevIdx] == ngi[curIdx]) {
                            curLargeValue = nums[ngi[curIdx]];
                            curIdx = ngi[curIdx];
                            prev = cur;
                            prevIdx = curIdx;
                        }
                    } else {
                        totalK -= (prev - cur) * (i - curIdx + 1);
                    }
                    idx++;
                }
            }
        }
        count += (n - idx) * (n - idx + 1) / 2;
        return count;
    }
}

Complexity

  • ⏰ Time complexity: O(n), since each element is pushed and popped from the stack at most once and the sliding window is amortized.
  • 🧺 Space complexity: O(n), for the stack and ngi array.