Range Addition II
EasyPrompt
You are given an m x n matrix M initialized with all 0's and an array of operations ops, where ops[i] = [ai, bi] means M[x][y] should be incremented by one for all 0 <= x < ai and 0 <= y < bi.
Count and return the number of maximum integers in the matrix after performing all the operations.
Example 1:
Input: m = 3, n = 3, ops = [[2,2],[3,3]]
Output: 4
Explanation: The maximum integer in M is 2, and there are four of it in M. So return 4.Example 2:
Input: m = 3, n = 3, ops = [[2,2],[3,3],[3,3],[3,3],[2,2],[3,3],[3,3],[3,3],[2,2],[3,3],[3,3],[3,3]]
Output: 4Example 3:
Input: m = 3, n = 3, ops = []
Output: 9
Constraints:
1 <= m, n <= 4 * 1040 <= ops.length <= 104ops[i].length == 21 <= ai <= m1 <= bi <= n
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly simulates the process described in the problem. We create an actual m x n matrix and perform each increment operation on it. After all operations are completed, we traverse the matrix to find the maximum value and count its occurrences.
Algorithm
- Create a 2D array
matrixof sizem x nand initialize all its elements to 0. - For each operation
opinops:- Let
row_lim = op[0]andcol_lim = op[1]. - For
ifrom0torow_lim - 1:- For
jfrom0tocol_lim - 1:matrix[i][j]++.
- For
- Let
- Initialize
max_val = 0. - Iterate through
matrixto find the maximum value and store it inmax_val. - Initialize
count = 0. - Iterate through
matrixagain. Ifmatrix[i][j] == max_val, incrementcount. - Return
count.
Walkthrough
We start by initializing an m x n integer matrix with all values set to 0. We then loop through every operation [a, b] in the ops array. For each operation, we use a nested loop to iterate through the sub-matrix from row 0 to a-1 and column 0 to b-1. In this sub-matrix, we increment the value of each cell M[i][j] by one. After processing all operations, the matrix M holds the final values. We then iterate through the entire matrix one more time to find the maximum value present. Finally, we perform another pass through the matrix to count how many cells are equal to this maximum value. This count is our result.
class Solution { public int maxCount(int m, int n, int[][] ops) { if (ops == null || ops.length == 0) { return m * n; } int[][] matrix = new int[m][n]; for (int[] op : ops) { int row_lim = op[0]; int col_lim = op[1]; for (int i = 0; i < row_lim; i++) { for (int j = 0; j < col_lim; j++) { matrix[i][j]++; } } } int maxVal = 0; if (m > 0 && n > 0) { // The top-left element is guaranteed to be one of the maximums maxVal = matrix[0][0]; } int count = 0; for (int i = 0; i < m; i++) { for (int j = _0; j < n; j++) { if (matrix[i][j] == maxVal) { count++; } } } return count; }}Complexity
Time
O(k * m * n), where `k` is the number of operations. For each of the `k` operations, we might update up to `m * n` cells. Finding the max and count takes another `O(m * n)`. This is highly inefficient and will time out for large inputs.
Space
O(m * n) to store the matrix. This can lead to a Memory Limit Exceeded error for large `m` and `n`.
Trade-offs
Pros
Simple to understand and implement as it directly follows the problem statement.
Cons
Extremely inefficient in terms of both time and space.
Will not pass the tests with larger constraints due to Time Limit Exceeded (TLE) and Memory Limit Exceeded (MLE).
A more insightful approach recognizes that the maximum value in the matrix will be achieved only in the cells that are affected by every single operation. The region affected by all operations is the intersection of the regions of each individual operation. This intersection is a rectangle whose dimensions are determined by the minimum row and column limits from all operations.
Algorithm
- Initialize
min_row = mandmin_col = n. - Iterate through each operation
opinops.- Update
min_row = min(min_row, op[0]). - Update
min_col = min(min_col, op[1]).
- Update
- Return
min_row * min_col.
Walkthrough
Each operation [a_i, b_i] increments a rectangle of cells from (0, 0) to (a_i-1, b_i-1). A cell (x, y) is incremented by an operation [a_i, b_i] if x < a_i and y < b_i. For a cell to be incremented by all operations, it must satisfy x < a_i and y < b_i for all i. This is equivalent to x < min(all a_i) and y < min(all b_i). Therefore, the cells with the maximum value (which will be ops.length) form a rectangle of size min_a x min_b, where min_a is the minimum of all a_i's and min_b is the minimum of all b_i's. The number of such cells is simply min_a * min_b. We can find these minimums in a single pass through the ops array. If ops is empty, no operations are performed. All cells remain 0, which is the maximum value. The number of such cells is m * n. Our logic handles this if we initialize our minimums to m and n.
class Solution { public int maxCount(int m, int n, int[][] ops) { int min_a = m; int min_b = n; for (int[] op : ops) { min_a = Math.min(min_a, op[0]); min_b = Math.min(min_b, op[1]); } return min_a * min_b; }}Complexity
Time
O(k), where `k` is the number of operations (`ops.length`). We iterate through the `ops` array only once.
Space
O(1). We only use a few variables to store the minimum row and column values, regardless of the input size.
Trade-offs
Pros
Extremely efficient in both time and space.
Simple and elegant solution based on a key observation.
Cons
Requires a logical leap to understand why this works, instead of direct simulation.
Solutions
Solution
/** * @param {number} m * @param {number} n * @param {number[][]} ops * @return {number} */ var maxCount = function (m, n, ops) { for (const [a, b] of ops) { m = Math.min(m, a); n = Math.min(n, b); } return m * n; };class Solution {public int maxCount(int m, int n, int[][] ops) { for (int[] op : ops) { m = Math.min(m, op[0]); n = Math.min(n, op[1]); } return m * n; }}class Solution {public: int maxCount(int m, int n, vector<vector<int>> &ops) { for (auto op : ops) { m = min(m, op[0]); n = min(n, op[1]); } return m * n; }};class Solution: def maxCount(self, m: int, n: int, ops: List[List[int]]) -> int: for a, b in ops: m = min(m, a) n = min(n, b) return m * n # from functools import reduce class Solution ( object ): def maxCount ( self , m , n , ops ): """ :type m: int :type n: int :type ops: List[List[int]] :rtype: int """ return reduce ( operator . mul , map ( min , zip ( * ops + [[ m , n ]])))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.