Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
You are given an m x n matrix grid of positive integers. Your task is to determine if it is possible to make either one horizontal or one vertical cut on the grid such that:
Return true if such a partition exists; otherwise, return false.
Note: A section is connected if every cell in it can be reached from any other cell by moving up, down, left, or right through other cells in the section.
Example 1:
Input: grid = [[1,4],[2,3]]
Output: true
Explanation:
1 + 4 = 5 and 2 + 3 = 5, which are equal. Thus, the answer is true.Example 2:
Input: grid = [[1,2],[3,4]]
Output: true
Explanation:
1 + 3 = 4 and 2 + 4 = 6.6 - 2 = 4), both sections have equal sums and remain connected. Thus, the answer is true.Example 3:
Input: grid = [[1,2,4],[2,3,5]]
Output: false
Explanation:
1 + 2 + 4 = 7 and 2 + 3 + 5 = 10.10 - 3 = 7), both sections have equal sums, but they do not remain connected as it splits the bottom section into two parts ([2] and [5]). Thus, the answer is false.Example 4:
Input: grid = [[4,1,8],[3,2,6]]
Output: false
Explanation:
No valid cut exists, so the answer is false.
Constraints:
1 <= m == grid.length <= 1051 <= n == grid[i].length <= 1052 <= m * n <= 1051 <= grid[i][j] <= 105Problem summary: You are given an m x n matrix grid of positive integers. Your task is to determine if it is possible to make either one horizontal or one vertical cut on the grid such that: Each of the two resulting sections formed by the cut is non-empty. The sum of elements in both sections is equal, or can be made equal by discounting at most one single cell in total (from either section). If a cell is discounted, the rest of the section must remain connected. Return true if such a partition exists; otherwise, return false. Note: A section is connected if every cell in it can be reached from any other cell by moving up, down, left, or right through other cells in the section.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map
[[1,4],[2,3]]
[[1,2],[3,4]]
[[1,2,4],[2,3,5]]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3548: Equal Sum Grid Partition II
class Solution {
public boolean canPartitionGrid(int[][] grid) {
final long sum = Arrays.stream(grid).flatMapToInt(Arrays::stream).asLongStream().sum();
return canPartition(grid, sum) || canPartition(reversed(grid), sum) ||
canPartition(reversed(transposed(grid)), sum) || canPartition(transposed(grid), sum);
}
private boolean canPartition(int[][] grid, long sum) {
long topSum = 0;
Set<Integer> seen = new HashSet<>();
for (int i = 0; i < grid.length; ++i) {
topSum += Arrays.stream(grid[i]).asLongStream().sum();
final long botSum = sum - topSum;
Arrays.stream(grid[i]).forEach(seen::add);
if (topSum - botSum == 0 || topSum - botSum == grid[0][0] ||
topSum - botSum == grid[0][grid[0].length - 1] || topSum - botSum == grid[i][0])
return true;
if (grid[0].length > 1 && i > 0 && seen.contains((int) (topSum - botSum)))
return true;
}
return false;
}
private int[][] transposed(int[][] grid) {
int[][] res = new int[grid[0].length][grid.length];
for (int i = 0; i < grid.length; ++i)
for (int j = 0; j < grid[0].length; ++j)
res[j][i] = grid[i][j];
return res;
}
private int[][] reversed(int[][] grid) {
return Arrays.stream(grid).collect(Collectors.collectingAndThen(Collectors.toList(), list -> {
Collections.reverse(list);
return list.toArray(new int[0][]);
}));
}
}
// Accepted solution for LeetCode #3548: Equal Sum Grid Partition II
package main
import "slices"
// https://space.bilibili.com/206214
func canPartitionGrid(grid [][]int) bool {
total := 0
for _, row := range grid {
for _, x := range row {
total += x
}
}
// 能否水平分割
check := func(a [][]int) bool {
m, n := len(a), len(a[0])
f := func() bool {
has := map[int]bool{0: true} // 0 对应不删除数字
s := 0
for i, row := range a[:m-1] {
for j, x := range row {
s += x
// 第一行,不能删除中间元素
if i > 0 || j == 0 || j == n-1 {
has[x] = true
}
}
// 特殊处理只有一列的情况,此时只能删除第一个数或者分割线上那个数
if n == 1 {
if s*2 == total || s*2-total == a[0][0] || s*2-total == row[0] {
return true
}
continue
}
if has[s*2-total] {
return true
}
// 如果分割到更下面,那么可以删第一行的元素
if i == 0 {
for _, x := range row {
has[x] = true
}
}
}
return false
}
// 删除上半部分中的一个数
if f() {
return true
}
slices.Reverse(a)
// 删除下半部分中的一个数
return f()
}
// 水平分割 or 垂直分割
return check(grid) || check(rotate(grid))
}
// 顺时针旋转矩阵 90°
func rotate(a [][]int) [][]int {
m, n := len(a), len(a[0])
b := make([][]int, n)
for i := range b {
b[i] = make([]int, m)
}
for i, row := range a {
for j, x := range row {
b[j][m-1-i] = x
}
}
return b
}
# Accepted solution for LeetCode #3548: Equal Sum Grid Partition II
class Solution:
def canPartitionGrid(self, grid: list[list[int]]) -> bool:
summ = sum(map(sum, grid))
def canPartition(grid: list[list[int]]) -> bool:
topSum = 0
seen = set()
for i, row in enumerate(grid):
topSum += sum(row)
botSum = summ - topSum
seen |= set(row)
if topSum - botSum in (0, grid[0][0], grid[0][-1], row[0]):
return True
if len(grid[0]) > 1 and i > 0 and topSum - botSum in seen:
return True
return False
return (canPartition(grid) or
canPartition(grid[::-1]) or
canPartition(list(zip(*grid))[::-1]) or
canPartition(list(zip(*grid))))
// Accepted solution for LeetCode #3548: Equal Sum Grid Partition II
// Rust example auto-generated from java reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (java):
// // Accepted solution for LeetCode #3548: Equal Sum Grid Partition II
// class Solution {
// public boolean canPartitionGrid(int[][] grid) {
// final long sum = Arrays.stream(grid).flatMapToInt(Arrays::stream).asLongStream().sum();
// return canPartition(grid, sum) || canPartition(reversed(grid), sum) ||
// canPartition(reversed(transposed(grid)), sum) || canPartition(transposed(grid), sum);
// }
//
// private boolean canPartition(int[][] grid, long sum) {
// long topSum = 0;
// Set<Integer> seen = new HashSet<>();
// for (int i = 0; i < grid.length; ++i) {
// topSum += Arrays.stream(grid[i]).asLongStream().sum();
// final long botSum = sum - topSum;
// Arrays.stream(grid[i]).forEach(seen::add);
// if (topSum - botSum == 0 || topSum - botSum == grid[0][0] ||
// topSum - botSum == grid[0][grid[0].length - 1] || topSum - botSum == grid[i][0])
// return true;
// if (grid[0].length > 1 && i > 0 && seen.contains((int) (topSum - botSum)))
// return true;
// }
// return false;
// }
//
// private int[][] transposed(int[][] grid) {
// int[][] res = new int[grid[0].length][grid.length];
// for (int i = 0; i < grid.length; ++i)
// for (int j = 0; j < grid[0].length; ++j)
// res[j][i] = grid[i][j];
// return res;
// }
//
// private int[][] reversed(int[][] grid) {
// return Arrays.stream(grid).collect(Collectors.collectingAndThen(Collectors.toList(), list -> {
// Collections.reverse(list);
// return list.toArray(new int[0][]);
// }));
// }
// }
// Accepted solution for LeetCode #3548: Equal Sum Grid Partition II
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #3548: Equal Sum Grid Partition II
// class Solution {
// public boolean canPartitionGrid(int[][] grid) {
// final long sum = Arrays.stream(grid).flatMapToInt(Arrays::stream).asLongStream().sum();
// return canPartition(grid, sum) || canPartition(reversed(grid), sum) ||
// canPartition(reversed(transposed(grid)), sum) || canPartition(transposed(grid), sum);
// }
//
// private boolean canPartition(int[][] grid, long sum) {
// long topSum = 0;
// Set<Integer> seen = new HashSet<>();
// for (int i = 0; i < grid.length; ++i) {
// topSum += Arrays.stream(grid[i]).asLongStream().sum();
// final long botSum = sum - topSum;
// Arrays.stream(grid[i]).forEach(seen::add);
// if (topSum - botSum == 0 || topSum - botSum == grid[0][0] ||
// topSum - botSum == grid[0][grid[0].length - 1] || topSum - botSum == grid[i][0])
// return true;
// if (grid[0].length > 1 && i > 0 && seen.contains((int) (topSum - botSum)))
// return true;
// }
// return false;
// }
//
// private int[][] transposed(int[][] grid) {
// int[][] res = new int[grid[0].length][grid.length];
// for (int i = 0; i < grid.length; ++i)
// for (int j = 0; j < grid[0].length; ++j)
// res[j][i] = grid[i][j];
// return res;
// }
//
// private int[][] reversed(int[][] grid) {
// return Arrays.stream(grid).collect(Collectors.collectingAndThen(Collectors.toList(), list -> {
// Collections.reverse(list);
// return list.toArray(new int[0][]);
// }));
// }
// }
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.