每日一道leetcode(2026.03.26):等和矩阵分割 II

每日一道leetcode(2026.03.26):等和矩阵分割 II

  • [1. 题目](#1. 题目)
  • [2. 分析](#2. 分析)
  • [3. 代码实现](#3. 代码实现)
  • [4. 总结](#4. 总结)

1. 题目

给你一个由正整数组成的 m x n 矩阵 grid。你的任务是判断是否可以通过 一条水平或一条垂直分割线 将矩阵分割成两部分,使得:

  • 分割后形成的每个部分都是 非空 的。
  • 两个部分中所有元素的和 相等 ,或者总共 最多移除一个单元格 (从其中一个部分中)的情况下可以使它们相等。
  • 如果移除某个单元格,剩余部分必须保持 连通 。
    如果存在这样的分割,返回 true;否则,返回 false。

注意: 如果一个部分中的每个单元格都可以通过向上、向下、向左或向右移动到达同一部分中的其他单元格,则认为这一部分是 连通 的。

示例 1:

输入: grid = [[1,4],[2,3]]

输出: true

解释:

在第 0 行和第 1 行之间进行水平分割,结果两部分的元素和为 1 + 4 = 5 和 2 + 3 = 5,相等。因此答案是 true。

2. 分析

这天这道题是昨天等和矩阵分割 I的升级版,题目依然很好理解,一开始我觉着应该挺简单,但是看标签,觉着肯定有坑在等着我,已经做好了提交后超时的心理准备。

还是沿着昨天的思路,先计算出所有的元素之和,然后移动下标,计算每行每列的和之后,对两部分的和值进行对应的加减,下面为了便于叙述,我只描述纵向移动的过程,横向移动以此类推。

如果是移动到了某个位置,两边的和值相等,那么皆大欢喜,直接返回true即可,如果是上边大于下边,则需要判断上边的所有元素中是否有一个元素等于上下的差值。这里就得分情况判断了,如果上面只有一行,那么只能移除两端的那两个元素,否则会影响连通性,如果有多行,则可以移除上面的任意一个元素。还有更极端的,如果原始输入是nx1或者1xn,这里分割后上面就是一列,那么只能移除上下两端的元素了。如果是一端只有一个元素了,那么是否需要做补充判断呢,应该是不需要的,移除后一端和值就变成0了,永远不会相等了。

按照这个大体的思路,有了如下实现。

3. 代码实现

java 复制代码
class Solution {
    public boolean canPartitionGrid(int[][] grid) {
        // 计算所有的和
        long sum = 0;
        // 记录每行的元素和位置
        List<List<Integer>> rows = new ArrayList<>();
        // 每列
        List<List<Integer>> cols = new ArrayList<>();
        // 每行之和
        long[] rowSums = new long[grid.length];
        // 每列之和
        long[] colSums = new long[grid[0].length];

        Set<Integer> set = new HashSet<>();
        // 每行之和
        List<Set<Integer>> rowSet = new ArrayList<>();
        // 每列之和
        List<Set<Integer>> colSet = new ArrayList<>();
        // 最大值
        int max = 0;
        // 最小值
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < grid.length; i++) {
            rows.add(new ArrayList<>());
            rowSet.add(new HashSet<>());
            for (int j = 0; j < grid[i].length; j++) {
                if (cols.size() < j + 1) {
                    cols.add(new ArrayList<>());
                    colSet.add(new HashSet<>());
                }
                int val = grid[i][j];
                sum += val;
                rows.get(i).add(val);
                rowSums[i] += val;
                cols.get(j).add(val);
                colSums[j] += val;
                set.add(val);
                rowSet.get(i).add(val);
                colSet.get(j).add(val);
                max = Math.max(max, val);
                min = Math.min(min, val);
            }
        }
        return moveAndCheck(rows, rowSums, set, rowSet, sum, max, min) || moveAndCheck(cols, colSums, set, colSet, sum, max, min);
    }

    public boolean moveAndCheck(List<List<Integer>> eleList, long[] sumArray, Set<Integer> set, List<Set<Integer>> numSet, long sum, int max, int min) {
        long up = 0;
        long down = sum;
        for (int i = 0; i < eleList.size(); i++) {
            // 计算第i行的和
            up += sumArray[i];
            down -= sumArray[i];
            if (up == down) {
                return true;
            } else if (up > down) {
                // 判断上方是否有一个元素等于差值
                long diff = up - down;
                if (diff < min || diff > max || !set.contains((int) diff)) {
                    continue;
                }
                if (existDiff(eleList, 0, i, numSet, diff)) {
                    return true;
                }
            } else {
                // 判断下方是否有一个元素等于差值
                long diff = down - up;
                if (diff < min || diff > max || !set.contains((int) diff)) {
                    continue;
                }
                if (existDiff(eleList, i + 1, eleList.size() - 1, numSet, diff)) {
                    return true;
                }
                // 继续移动
            }
        }
        return false;
    }

    public boolean existDiff(List<List<Integer>> eleList, int from, int to, List<Set<Integer>> numSet, long diff) {
        // 左边或者右边只剩下一行或一列时,只能移除掉端上的一个元素,否则会影响连通性
        if (from == to) {
            List<Integer> ele = eleList.get(from);
            return ele.get(0) == diff || ele.get(ele.size() - 1) == diff;
        } else if (eleList.get(0).size() == 1) {
            // 原始输入只有一行时
            return eleList.get(from).get(0) == diff || eleList.get(to).get(0) == diff;
        } else if (eleList.size() == 1) {
            // 原始输入只有一列时
            return eleList.get(0).get(from) == diff || eleList.get(0).get(to) == diff;
        }
        // 存在多行多列时,所有的元素都可以移除,不影响连通性
        for (int i = from; i <= to; i++) {
            if (numSet.get(i).contains((int) diff)) {
                return true;
            }
        }
        return false;
    }
}

4. 总结

勉强通过了,过程中肯定遇到了计算超时的问题,做了部分优化。官方的题解使用到了矩阵旋转,这个我暂时没想到。过程中,有想过正向和方向移动来减少对排除元素的遍历,可能会对性能上还有部分优化,有兴趣的朋友可以试试。还是以上下移动为例,当出现不相等时,仅判断上面大于下面的情况,把上面的所有元素假如到集合中,可以快速定位到是否存在等于差值的元素,再补充一个从下往上移动的遍历,仅需要判断下面大于上面的情况,下方是否存在等于差值的元素。

相关推荐
平凡灵感码头2 小时前
C语言 printf 数据打印格式速查表
c语言·开发语言·算法
哔哔龙2 小时前
Android OpenCV 实战:图片轮廓提取与重叠轮廓合并处理
android·算法
hz_zhangrl2 小时前
CCF-GESP 等级考试 2026年3月认证C++三级真题解析
c++·算法·程序设计·gesp·gesp2026年3月·gesp c++三级
x_xbx2 小时前
LeetCode:1. 两数之和
数据结构·算法·leetcode
x_xbx2 小时前
LeetCode:49. 字母异位词分组
算法·leetcode·职场和发展
玲娜贝儿--努力学习买大鸡腿版2 小时前
hot 100 刷题记录(1)
数据结构·python·算法
123过去2 小时前
pixiewps使用教程
linux·网络·测试工具·算法·哈希算法
深圳市快瞳科技有限公司3 小时前
低空经济下,鸟类识别算法与无人机硬件的兼容性优化策略
算法·无人机
努力中的编程者3 小时前
二叉树(C语言底层实现)
c语言·开发语言·数据结构·c++·算法