Skip to content

Commit e9cfab5

Browse files
authored
feat: add solutions for lc No.3888 (#5128)
1 parent f9a020e commit e9cfab5

11 files changed

Lines changed: 972 additions & 2 deletions

File tree

solution/2700-2799/2753.Count Houses in a Circular Street II/README_EN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/2700-2799/2753.Co
3636
<pre>
3737
<strong>Input:</strong> street = [1,1,1,1], k = 10
3838
<strong>Output:</strong> 4
39-
<strong>Explanation:</strong> There are 4 houses, and all their doors are open.
39+
<strong>Explanation:</strong> There are 4 houses, and all their doors are open.
4040
The number of houses is less than k, which is 10.</pre>
4141

4242
<p><strong class="example">Example 2:</strong></p>
Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
1+
---
2+
comments: true
3+
difficulty: 困难
4+
edit_url: https://github.com/doocs/leetcode/edit/main/solution/3800-3899/3888.Minimum%20Operations%20to%20Make%20All%20Grid%20Elements%20Equal/README.md
5+
---
6+
7+
<!-- problem:start -->
8+
9+
# [3888. Minimum Operations to Make All Grid Elements Equal 🔒](https://leetcode.cn/problems/minimum-operations-to-make-all-grid-elements-equal)
10+
11+
[English Version](/solution/3800-3899/3888.Minimum%20Operations%20to%20Make%20All%20Grid%20Elements%20Equal/README_EN.md)
12+
13+
## 题目描述
14+
15+
<!-- description:start -->
16+
17+
<p>You are given a 2D integer array <code>grid</code> of size <code>m &times; n</code>, and an integer <code>k</code>.</p>
18+
19+
<p>In one operation, you can:</p>
20+
21+
<ul>
22+
<li>Select any <code>k x k</code> <strong>submatrix</strong> of <code>grid</code>, and</li>
23+
<li>Increment <strong>all elements</strong> inside that <strong>submatrix</strong> by 1.</li>
24+
</ul>
25+
26+
<p>Return the <strong>minimum</strong> number of operations required to make all elements in the grid <strong>equal</strong>. If it is not possible, return -1.</p>
27+
A submatrix <code>(x1, y1, x2, y2)</code> is a matrix that forms by choosing all cells <code>matrix[x][y]</code> where <code>x1 &lt;= x &lt;= x2</code> and <code>y1 &lt;= y &lt;= y2</code>.
28+
<p>&nbsp;</p>
29+
<p><strong class="example">Example 1:</strong></p>
30+
31+
<div class="example-block">
32+
<p><strong>Input:</strong> <span class="example-io">grid = [[3,3,5],[3,3,5]], k = 2</span></p>
33+
34+
<p><strong>Output:</strong> <span class="example-io">2</span></p>
35+
36+
<p><strong>Explanation:</strong></p>
37+
38+
<p data-end="266" data-start="150">Choose the left <code>2 x 2</code> submatrix (covering the first two columns) and apply the operation twice.</p>
39+
40+
<ul>
41+
<li>After 1 operation: <code>[[4, 4, 5], [4, 4, 5]]</code></li>
42+
<li>After 2 operations: <code>[[5, 5, 5], [5, 5, 5]]</code></li>
43+
</ul>
44+
45+
<p>All elements become equal to 5. Thus, the minimum number of operations is 2.</p>
46+
</div>
47+
48+
<p><strong class="example">Example 2:</strong></p>
49+
50+
<div class="example-block">
51+
<p><strong>Input:</strong> <span class="example-io">grid = [[1,2],[2,3]], k = 1</span></p>
52+
53+
<p><strong>Output:</strong> <span class="example-io">4</span></p>
54+
55+
<p><strong>Explanation:</strong></p>
56+
57+
<p>Since <code>k = 1</code>, each operation increments a single cell <code>grid[i][j]</code> by 1. To make all elements equal, the final value must be 3.</p>
58+
59+
<ul>
60+
<li>Increase <code>grid[0][0] = 1</code> to 3, requiring 2 operations.</li>
61+
<li>Increase <code>grid[0][1] = 2</code> to 3, requiring 1 operation.</li>
62+
<li>Increase <code>grid[1][0] = 2</code> to 3, requiring 1 operation.</li>
63+
</ul>
64+
65+
<p>Thus, the minimum number of operations is <code>2 + 1 + 1 + 0 = 4</code>.</p>
66+
</div>
67+
68+
<p>&nbsp;</p>
69+
<p><strong>Constraints:</strong></p>
70+
71+
<ul>
72+
<li><code>1 &lt;= m == grid.length &lt;= 1000</code></li>
73+
<li><code>1 &lt;= n == grid[i].length &lt;= 1000</code></li>
74+
<li><code>-10<sup>5</sup> &lt;= grid[i][j] &lt;= 10<sup>5</sup></code></li>
75+
<li><code>1 &lt;= k &lt;= min(m, n)</code></li>
76+
</ul>
77+
78+
<!-- description:end -->
79+
80+
## 解法
81+
82+
<!-- solution:start -->
83+
84+
### 方法一:二维差分 + 贪心
85+
86+
由于操作只能增加元素的值,因此最终网格的所有元素必须等于某个目标值 $T$,且 $T \ge \max(\textit{grid})$。
87+
88+
从左上角 $(0, 0)$ 开始遍历网格。对于任意位置 $(i, j)$,如果它当前的数值小于 $T$,由于后续的操作(以更靠右或更靠下的位置为左上角的操作)都无法覆盖到 $(i, j)$,因此必须在当前位置执行 $T - \text{current\_val}$ 次以 $(i, j)$ 为左上角的 $k \times k$ 增加操作。
89+
90+
如果每次执行操作都遍历 $k \times k$ 区域,复杂度将达到 $O(m \cdot n \cdot k^2)$。我们可以使用二维差分数组 $\textit{diff}$ 来记录操作。通过实时维护 $\textit{diff}$ 的二维前缀和,我们可以在 $O(1)$ 时间内获取当前位置的累计增量,并在 $O(1)$ 时间内更新一个 $k \times k$ 区域的未来影响。
91+
92+
通常情况下 $T = \max(\textit{grid})$ 即可。但在某些 $k \times k$ 覆盖重叠的情况下,较小的 $T$ 可能导致中间位置被动增加后超过 $T$。根据数学一致性,若 $T = \max(\textit{grid})$ 和 $T = \max(\textit{grid}) + 1$ 均不可行,则该网格无法通过 $k \times k$ 操作变平。
93+
94+
时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$,其中 $m$ 和 $n$ 分别是网格的行数和列数。
95+
96+
<!-- tabs:start -->
97+
98+
#### Python3
99+
100+
```python
101+
class Solution:
102+
def minOperations(self, grid: list[list[int]], k: int) -> int:
103+
m, n = len(grid), len(grid[0])
104+
mx = max(max(row) for row in grid)
105+
106+
def check(target: int) -> int:
107+
diff = [[0] * (n + 2) for _ in range(m + 2)]
108+
total_ops = 0
109+
110+
for i, row in enumerate(grid, 1):
111+
for j, val in enumerate(row, 1):
112+
diff[i][j] += diff[i - 1][j] + diff[i][j - 1] - diff[i - 1][j - 1]
113+
114+
cur_val = val + diff[i][j]
115+
116+
if cur_val > target:
117+
return -1
118+
119+
if cur_val < target:
120+
if i + k - 1 > m or j + k - 1 > n:
121+
return -1
122+
123+
needed = target - cur_val
124+
total_ops += needed
125+
diff[i][j] += needed
126+
diff[i + k][j] -= needed
127+
diff[i][j + k] -= needed
128+
diff[i + k][j + k] += needed
129+
return total_ops
130+
131+
for t in range(mx, mx + 2):
132+
res = check(t)
133+
if res != -1:
134+
return res
135+
136+
return -1
137+
```
138+
139+
#### Java
140+
141+
```java
142+
class Solution {
143+
int[][] grid;
144+
int m, n, k;
145+
146+
public long minOperations(int[][] grid, int k) {
147+
this.grid = grid;
148+
this.k = k;
149+
this.m = grid.length;
150+
this.n = grid[0].length;
151+
152+
int mx = Integer.MIN_VALUE;
153+
for (int[] row : grid) {
154+
for (int v : row) {
155+
mx = Math.max(mx, v);
156+
}
157+
}
158+
159+
for (int t = mx; t <= mx + 1; t++) {
160+
long res = check(t);
161+
if (res != -1) {
162+
return res;
163+
}
164+
}
165+
return -1;
166+
}
167+
168+
private long check(int target) {
169+
long[][] diff = new long[m + 2][n + 2];
170+
long totalOps = 0;
171+
172+
for (int i = 1; i <= m; i++) {
173+
for (int j = 1; j <= n; j++) {
174+
diff[i][j] += diff[i - 1][j] + diff[i][j - 1] - diff[i - 1][j - 1];
175+
long cur = grid[i - 1][j - 1] + diff[i][j];
176+
177+
if (cur > target) {
178+
return -1;
179+
}
180+
181+
if (cur < target) {
182+
if (i + k - 1 > m || j + k - 1 > n) {
183+
return -1;
184+
}
185+
186+
long need = target - cur;
187+
totalOps += need;
188+
189+
diff[i][j] += need;
190+
diff[i + k][j] -= need;
191+
diff[i][j + k] -= need;
192+
diff[i + k][j + k] += need;
193+
}
194+
}
195+
}
196+
return totalOps;
197+
}
198+
}
199+
```
200+
201+
#### C++
202+
203+
```cpp
204+
class Solution {
205+
public:
206+
long long minOperations(vector<vector<int>>& grid, int k) {
207+
int m = grid.size();
208+
int n = grid[0].size();
209+
int mx = grid[0][0];
210+
for (auto& row : grid) {
211+
for (int val : row) {
212+
mx = max(mx, val);
213+
}
214+
}
215+
216+
auto check = [&](int target) -> long long {
217+
vector<vector<long long>> diff(m + 2, vector<long long>(n + 2, 0));
218+
long long total_ops = 0;
219+
220+
for (int i = 1; i <= m; ++i) {
221+
for (int j = 1; j <= n; ++j) {
222+
diff[i][j] += diff[i - 1][j] + diff[i][j - 1] - diff[i - 1][j - 1];
223+
long long cur_val = grid[i - 1][j - 1] + diff[i][j];
224+
225+
if (cur_val > target) {
226+
return -1;
227+
}
228+
229+
if (cur_val < target) {
230+
if (i + k - 1 > m || j + k - 1 > n) {
231+
return -1;
232+
}
233+
234+
long long needed = target - cur_val;
235+
total_ops += needed;
236+
diff[i][j] += needed;
237+
diff[i + k][j] -= needed;
238+
diff[i][j + k] -= needed;
239+
diff[i + k][j + k] += needed;
240+
}
241+
}
242+
}
243+
244+
return total_ops;
245+
};
246+
247+
for (int t = mx; t <= mx + 1; ++t) {
248+
long long res = check(t);
249+
if (res != -1) {
250+
return res;
251+
}
252+
}
253+
254+
return -1;
255+
}
256+
};
257+
```
258+
259+
#### Go
260+
261+
```go
262+
func minOperations(grid [][]int, k int) int64 {
263+
m, n := len(grid), len(grid[0])
264+
maxVal := grid[0][0]
265+
for _, row := range grid {
266+
maxVal = max(maxVal, slices.Max(row))
267+
}
268+
269+
check := func(target int) int64 {
270+
diff := make([][]int64, m+2)
271+
for i := range diff {
272+
diff[i] = make([]int64, n+2)
273+
}
274+
var totalOps int64
275+
276+
for i := 1; i <= m; i++ {
277+
for j := 1; j <= n; j++ {
278+
diff[i][j] += diff[i-1][j] + diff[i][j-1] - diff[i-1][j-1]
279+
curVal := int64(grid[i-1][j-1]) + diff[i][j]
280+
281+
if curVal > int64(target) {
282+
return -1
283+
}
284+
285+
if curVal < int64(target) {
286+
if i+k-1 > m || j+k-1 > n {
287+
return -1
288+
}
289+
needed := int64(target) - curVal
290+
totalOps += needed
291+
diff[i][j] += needed
292+
diff[i+k][j] -= needed
293+
diff[i][j+k] -= needed
294+
diff[i+k][j+k] += needed
295+
}
296+
}
297+
}
298+
return totalOps
299+
}
300+
301+
for t := maxVal; t <= maxVal+1; t++ {
302+
if res := check(t); res != -1 {
303+
return res
304+
}
305+
}
306+
307+
return -1
308+
}
309+
```
310+
311+
#### TypeScript
312+
313+
```ts
314+
function minOperations(grid: number[][], k: number): number {
315+
const m = grid.length;
316+
const n = grid[0].length;
317+
let maxVal = grid[0][0];
318+
319+
for (const row of grid) {
320+
for (const val of row) {
321+
maxVal = Math.max(maxVal, val);
322+
}
323+
}
324+
325+
const check = (target: number): number => {
326+
const diff: number[][] = Array.from({ length: m + 2 }, () => Array(n + 2).fill(0));
327+
let totalOps = 0;
328+
329+
for (let i = 1; i <= m; i++) {
330+
for (let j = 1; j <= n; j++) {
331+
diff[i][j] += diff[i - 1][j] + diff[i][j - 1] - diff[i - 1][j - 1];
332+
const curVal = grid[i - 1][j - 1] + diff[i][j];
333+
334+
if (curVal > target) return -1;
335+
336+
if (curVal < target) {
337+
if (i + k - 1 > m || j + k - 1 > n) return -1;
338+
339+
const needed = target - curVal;
340+
totalOps += needed;
341+
diff[i][j] += needed;
342+
diff[i + k][j] -= needed;
343+
diff[i][j + k] -= needed;
344+
diff[i + k][j + k] += needed;
345+
}
346+
}
347+
}
348+
349+
return totalOps;
350+
};
351+
352+
for (let t = maxVal; t <= maxVal + 1; t++) {
353+
const res = check(t);
354+
if (res !== -1) return res;
355+
}
356+
357+
return -1;
358+
}
359+
```
360+
361+
<!-- tabs:end -->
362+
363+
<!-- solution:end -->
364+
365+
<!-- problem:end -->

0 commit comments

Comments
 (0)