每日一道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. 总结

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

相关推荐
Dillon Dong1 小时前
【风电控制】TI TMS320F28379D 双CPU架构解析与任务分布设计
嵌入式硬件·算法·变流器·风电控制
小羊在睡觉6 小时前
力扣84. 柱状图中最大的矩形
后端·算法·leetcode·golang·go
3DVisionary7 小时前
蓝光三维扫描:医疗制造的精度焦虑怎么解
人工智能·算法·制造·蓝光三维扫描·医疗制造·三维检测·义齿检测
好评笔记7 小时前
机器学习面试八股——常用损失函数
人工智能·深度学习·算法·机器学习·校招
weixin_468466857 小时前
全局与局部注意力机制新手实战指南
人工智能·python·深度学习·算法·自然语言处理·transformer·注意力机制
sheeta19987 小时前
LeetCode 每日一题笔记 日期:2026.05.29 题目:3300. 最小元素
笔记·leetcode
_日拱一卒7 小时前
LeetCode:994腐烂的橘子
java·数据结构·算法·leetcode·深度优先
珂朵莉MM8 小时前
第七届全球校园人工智能算法精英大赛-算法巅峰赛产业命题赛第3赛季优化题--束搜索
人工智能·算法
Omics Pro8 小时前
首个!外源天然产物综合性代谢图谱
数据库·人工智能·算法·机器学习·r语言
voidmort9 小时前
3. 微调(Fine-tuning)与强化学习(RL)的核心思想
python·深度学习·算法