Find the Count of Monotonic Pairs I
HardPrompt
You are given an array of positive integers nums of length n.
We call a pair of non-negative integer arrays (arr1, arr2) monotonic if:
- The lengths of both arrays are
n. arr1is monotonically non-decreasing, in other words,arr1[0] <= arr1[1] <= ... <= arr1[n - 1].arr2is monotonically non-increasing, in other words,arr2[0] >= arr2[1] >= ... >= arr2[n - 1].arr1[i] + arr2[i] == nums[i]for all0 <= i <= n - 1.
Return the count of monotonic pairs.
Since the answer may be very large, return it modulo 109 + 7.
Example 1:
Input: nums = [2,3,2]
Output: 4
Explanation:
The good pairs are:
([0, 1, 1], [2, 2, 1])([0, 1, 2], [2, 2, 0])([0, 2, 2], [2, 1, 0])([1, 2, 2], [1, 1, 0])
Example 2:
Input: nums = [5,5,5,5]
Output: 126
Constraints:
1 <= n == nums.length <= 20001 <= nums[i] <= 50
Approaches
3 approaches with complexity analysis and trade-offs.
This approach optimizes the naive DP solution by observing that the inner loop is calculating a sum over a range. Such summations can be computed efficiently using prefix sums. By pre-calculating the prefix sums for each row of the DP table, we can determine the value of any dp[i][j] in constant time, which significantly improves the overall time complexity.
Algorithm
- The DP state
dp[i][j]is the same as the naive approach. - The transition
dp[i][j] = sum(dp[i-1][k])is over a contiguous range ofk. - The upper bound for
kislimit = min(nums[i-1], j - max(0, nums[i] - nums[i-1])). - We can precompute prefix sums for each row
i-1of the DP table into an arrayps[i-1]. dp[i][j]can then be found in O(1) time usingps[i-1][limit].- This removes the innermost loop from the naive DP approach.
Walkthrough
The key insight is that the transition dp[i][j] = sum(dp[i-1][k]) is performed for k in the range [0, limit], where limit = min(nums[i-1], j - max(0, nums[i] - nums[i-1])). This is a prefix sum.
We can maintain a parallel 2D array, ps, where ps[i][x] stores the sum of dp[i][k] for k from 0 to x. After computing the i-1-th row of the dp table, we can compute the i-1-th row of the ps table in O(M) time. Then, when computing the i-th row of dp, each dp[i][j] can be found in O(1) by looking up the precomputed value in ps[i-1], effectively eliminating one loop from the previous approach.
Algorithm Steps:
- Create a DP table
dp[n][M+1]and a prefix sum tableps[n][M+1]. - Base Case (i=0): Fill
dp[0]andps[0]as before. - Transitions (i > 0): For
ifrom1ton-1:- For each
jfrom0tonums[i]:- Calculate the upper bound for
k:limit = min(nums[i-1], j - max(0, nums[i] - nums[i-1])). - If
limit >= 0, setdp[i][j] = ps[i-1][limit].
- Calculate the upper bound for
- Compute the prefix sums for the new
dp[i]row and store them inps[i].
- For each
- Final Result: The answer is
ps[n-1][nums[n-1]].
class Solution { public int countMonotonicPairs(int[] nums) { int n = nums.length; int maxVal = 0; for (int num : nums) { maxVal = Math.max(maxVal, num); } long[][] dp = new long[n][maxVal + 1]; long[][] ps = new long[n][maxVal + 1]; int MOD = 1_000_000_007; // Base case: i = 0 for (int j = 0; j <= nums[0]; j++) { dp[0][j] = 1; } ps[0][0] = dp[0][0]; for (int j = 1; j <= maxVal; j++) { ps[0][j] = (ps[0][j - 1] + dp[0][j]) % MOD; } // Fill DP table for i > 0 for (int i = 1; i < n; i++) { long diff = (long)nums[i] - nums[i-1]; for (int j = 0; j <= nums[i]; j++) { long k_upper_bound = j - Math.max(0, diff); long limit = Math.min(nums[i-1], k_upper_bound); if (limit >= 0) { dp[i][j] = ps[i-1][(int)limit]; } } ps[i][0] = dp[i][0]; for (int j = 1; j <= maxVal; j++) { ps[i][j] = (ps[i][j - 1] + dp[i][j]) % MOD; } } return (int) ps[n - 1][nums[n - 1]]; }}Complexity
Time
O(n * M). For each of the `n` states, we perform O(M) work to compute the DP values and their prefix sums.
Space
O(n * M), for the DP and prefix sum tables.
Trade-offs
Pros
Much faster than the naive DP approach, with a time complexity of O(n * M).
Handles the given constraints very efficiently.
Cons
Requires additional space for the prefix sum table, although the asymptotic space complexity remains the same.
Solutions
Solution
class Solution { public int countOfPairs ( int [] nums ) { final int mod = ( int ) 1 e9 + 7 ; int n = nums . length ; int m = Arrays . stream ( nums ). max (). getAsInt (); int [][] f = new int [ n ][ m + 1 ]; for ( int j = 0 ; j <= nums [ 0 ]; ++ j ) { f [ 0 ][ j ] = 1 ; } int [] g = new int [ m + 1 ]; for ( int i = 1 ; i < n ; ++ i ) { g [ 0 ] = f [ i - 1 ][ 0 ]; for ( int j = 1 ; j <= m ; ++ j ) { g [ j ] = ( g [ j - 1 ] + f [ i - 1 ][ j ]) % mod ; } for ( int j = 0 ; j <= nums [ i ]; ++ j ) { int k = Math . min ( j , j + nums [ i - 1 ] - nums [ i ]); if ( k >= 0 ) { f [ i ][ j ] = g [ k ]; } } } int ans = 0 ; for ( int j = 0 ; j <= nums [ n - 1 ]; ++ j ) { ans = ( ans + f [ n - 1 ][ j ]) % mod ; } return ans ; } }Video 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.