Leetcode 363 - Max Sum of Rectangle No Larger Than K(前缀和+二分)

66 篇文章 0 订阅
27 篇文章 0 订阅

题意

给一个矩阵,求矩阵内最大的和,并且该和不超过k。

思路

我们先考虑求最大子矩形和。
时间复杂度是 O(n3) 的。其基本思路就是降维。我们枚举L和R,分别代表起始列和终止列的起点和终点,这是 O(n2) 的,然后降维后,转化成了一个一维数组,求一维数组的最大区间和即可。时间复杂度 O(n) 。所以求最大子矩阵的面积是 O(n3) 的。

然后对于这道题,我们可以用相同的思路去做,但是转化成了一个一维数组后,我们需要做的就是求最大子区间的和,并且子区间的和不超过k。

假设我们有一个大小为n的一维数组,其基本思想是维护前缀和+二分查找。

我们假设到当前点的前缀和为 si ,我们不能超过的和为k,那么我们去前缀和里面二分查找一下最小的x,并且 xsik 的值。这里注意有两个点:

  1. 如果数组的数全部为正数,我们的前缀和本身就是排好序的,如果是负数的话,那么我们二分查找利用的性质是排好序,所以我们用一个set来维护前缀和。因为set的插入时间复杂度是 O(logn) ,所以我们求每一行的第k大的时间复杂度近似于 O(n(logn)2)
  2. 我们在二分查找的时候,最小会返回set里面最小的那个元素,即如果我们本身需要的 x2 即可,假设set里面最小的为2,那么返回的结果实际上是 si2 。这时候是实际上需要的就 si 即可。所以我们每次在set里面插入0,保证只取 si 的情况能够被考虑到。

时间复杂度 O(m2n(logn)2)

代码

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int>>& a, int k) {
        int m = a.size(); bool flag = false; int ans = INT_MIN;
        if (m) {
            //m^2nlogn(so need to swap m, n)
            int n = a[0].size();
            //use preh to maintain the 1D array
            if (m > n) {swap(m, n); flag = true;}
            for (int l = 0; l < m; l++) {
                vector<int> preh(n, 0);
                for (int r = l; r < m; r++) {
                    int sum = 0;
                    //pres.insert(0) to make sure that we can get the pres[j], otherwise, it's always pres[j] - pres[pos]
                    set<int> pres; pres.insert(0);
                    for (int j = 0; j < n; j++) {
                        preh[j] += flag ? a[j][r] : a[r][j];
                        sum += preh[j];
                        int x = sum - k;
                        auto it = pres.lower_bound(x);
                        if (it != pres.end()) ans = max(ans, sum - *it);
                        pres.insert(sum);
                    }
                }
            }
            return ans;
        }
        return 0;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值