加载中...
返回

难题本 | LeetCode363. 矩形区域不超过 K 的最大数值和

难题本为数不多的Hard题~

题目

给你一个 m x n 的矩阵 matrix 和一个整数 k ,找出并返回矩阵内部矩形区域的不超过 k 的最大数值和。

题目数据保证总会存在一个数值和不超过 k 的矩形区域。

示例1

  • 输入: matrix = [[1,0,1],[0,-2,3]], k = 2
  • 输出: 2
  • 解释: 蓝色边框圈出来的矩形区域 [[0, 1], [-2, 3]] 的数值和是 2,且 2 是不超过 k 的最大数字(k = 2)。

示例2

  • 输入: matrix = [[2,2,-1]], k = 3
  • 输出: 3

数据范围

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 100
  • -100 <= matrix[i][j] <= 100
  • -105 <= k <= 105

分析

我们要得到每一个小矩形,则可以:

  1. 遍历上下界
  2. 遍历左右界

只分析遍历上下界的情况,当我们得到了一组确定的上下界之后,我们可以得到很多个矩形区域:

可以看到,这个矩形区域由给定的上下界和 几个连续的列 组成。

在这个矩形区域中,我们的总和不能超过 k 。只要我们求出每一列的总和,则可以将原问题转化为:

给定一个整数数组和一个整数 k,计算该数组的最大区间和,要求区间和不超过 k

问题一、 如何快速求出每一列的总和呢?

我们在最外层遍历上边界,对于递增的下边界来说,只需要在上一轮的结果中加上当前这一行的元素,即可得到每一列的总和。

问题二、 如何快速求出不超过 k 的区间和呢?

区间和不超过 k ,转化为公式如下:

对于区间 s 、区间右端 r 和区间左端 l ,使得 prefix_sum[r] - prefix_sum[l - 1] <= k

我们使用了前缀和 prefix_sum ,且区间左右都是闭合的。

在本题中,我们可以从左向右遍历,计算出新的前缀和 prefix_sum[r] ,同时,我们使用一个 有序集合 保存以前计算过的所有前缀和即 prefix_sum[0 ~ l] ,从集合中快速查找是否存在一个元素满足上面的式子即可。

说到有序集合,不得不提 set ,原式可以变化为 prefix_sum[l - 1] >= prefix_sum[r] - k ,即我们要找的元素正是 set.lower_bound(prefix_sum[r] - k)

AC代码

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
        int upper, lower;
        int row = matrix.size();
        int col = matrix[0].size();
        int ans = INT_MIN;

        for (upper = 0; upper < row; upper++)
        {
            vector<int> col_sum(col);
            for (lower = upper; lower < row; lower++)
            {
                for (int c = 0; c < col; c++)
                {
                    col_sum[c] += matrix[lower][c];
                }

                int right = 0;
                set<int> s = { 0 };
                set<int>::iterator left;
                // for each right-pos
                for (int r = 0; r < col; r++)
                {
                    // right --> prefix_sum[r]
                    right += col_sum[r];
                    // right - left <= k
                    // left >= right - k
                    left = s.lower_bound(right - k);
                    if (left != s.end())
                    {
                        ans = max(ans, right - *left);
                    }
                    s.insert(right);
                }
            }
        }

        return ans;
    }
};

在上面的代码中,注意:

  • 每列的和 col_sum 是固定了上边界之后才开始计算的,故变量定义在第一层循环内;
  • 有序集合初始需要一个 0 ,否则计算前缀和的时候无法考虑 prefix_sum[r] 本身;

参考资料

[1] 力扣官方题解.矩形区域不超过 K 的最大数值和[EB/OL].2021-04-21

https://leetcode-cn.com/problems/max-sum-of-rectangle-no-larger-than-k/solution/ju-xing-qu-yu-bu-chao-guo-k-de-zui-da-sh-70q2/

10 comments
Anonymous
Markdown is supported
@mpv945
mpv945commentedalmost 3 years ago

添加图片,如果使用外部图床的http链接 。图片无法点击放大,你那边怎么解决的?

@SGS4ever
SGS4evercommentedalmost 3 years ago

@mpv945
添加图片,如果使用外部图床的http链接 。图片无法点击放大,你那边怎么解决的?

我的博客没有使用图床,所以没办法帮到你~

@Celetherin
Celetherincommentedover 2 years ago

您好,我也是使用的stack主题,我在照着您的方法添加返回顶部按钮时,遇到了按钮虽然出现、也能够点击,但无法实现实际上的返回顶部功能的问题,我没有任何的代码知识,不知道您有没有解决方法?
另外,也是想提醒一下其他需要这篇教程的朋友,最新版的stack主题,添加返回按钮的组件应该在layouts/partials/sidebar/right.html, 在layouts/_default/single.html中添加代码会导致出现两个右边栏。

@jsjcjsjc
jsjcjsjccommentedover 2 years ago

请教一下博主,如何优雅的给stack主题添加广告哈?
我只想在左或者右侧边栏底部,或者每篇文章底部添加一个小小的广告,但是默认似乎的满屏广告哈~~
感谢

@SGS4ever
SGS4evercommentedover 2 years ago
@ClimbingMouse
ClimbingMousecommentedabout 2 years ago

你好,按照你的方法设置页面载入动画,这个动画不会停止咋办啊

@46fafa
46fafacommentedabout 2 years ago

博主你好,请问一下主页布局修改哪里的代码如何作用于整个网页,我发现修改后的布局只存在主页和前两篇文章,其他部分还是没修改的样子

@4kohakunushi
4kohakunushicommentedover 1 year ago

你好,关于左侧栏图标高亮我这里存在一些问题想请教你。我取消了原本主页直接抓取post的内容在中间显示的版块,这个部分改成了其他东西,与此同时新增了一个抓取post信息的与links、search等目录并列的一个目录,现在的问题是这些部分虽然都能正常显示,但是对应的抓取post的那个目录无法选中以后高亮,应该修改增加什么才能让它也可以选中后高亮呢?

@SGS4ever
SGS4evercommentedover 1 year ago

首先我只能基于本文使用的Stack版本来尝试解答,因为没看过当前的Stack主题的代码~
我重新翻了下此前写的关于高亮的内容,理论上只要你的post页面的标题在menu配置中即可高亮。如果post页面是你站点的根路径,那应该可以参考我的文章里写的方法,修改下active的触发逻辑~

@4kohakunushi
你好,关于左侧栏图标高亮我这里存在一些问题想请教你。我取消了原本主页直接抓取post的内容在中间显示的版块,这个部分改成了其他东西,与此同时新增了一个抓取post信息的与links、search等目录并列的一个目录,现在的问题是这些部分虽然都能正常显示,但是对应的抓取post的那个目录无法选中以后高亮,应该修改增加什么才能让它也可以选中后高亮呢?

@sansan-cc
sansan-cccommented3 months ago

感谢博主的建站帖子,有很大的帮助。

有朋自远方来,不亦说乎?