leetcode 4405.统计子矩阵

这道题其实就是运用二维前缀和进行计算的。

如果说要进行暴力,那就是四重循环来凑活:

复制代码
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<cmath> 
#include<vector>
#include<algorithm>
#include<stack>
#include<queue>
#include<sstream>
#include<map>
#include<limits.h>
#include<set>
#define MAX 505
#define _for(i,a,b) for(int i=a;i<(b);i++)
#define ALL(x) x.begin(),x.end()
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
int arr[MAX][MAX];
int b[MAX][MAX];
LL n, m, counts, num;
void qianzhuihe() {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            b[i][j] = b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1] + arr[i][j];
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin >> n >> m >> num;
    _for(i, 1, n+1) {
        _for (j, 1, m + 1) {
            cin >> arr[i][j];
        }
    }
    qianzhuihe();
    for (int x1 = 1; x1 <= n; x1++) {
        for (int y1 = 1; y1 <= m; y1++) {//定下一个固定点
            for (int x2 = x1; x2 <= n; x2++) {
                for (int y2 = y1; y2 <= m; y2++) {
                    if (b[x2][y2] - b[x1 - 1][y2] - b[x2][y1 - 1] + b[x1-1][y1-1] <= num)
                        counts++;
                }//依次遍历其他的子矩阵
            }
        }
    }
    cout << counts;
    return 0;
}

所以我们需要进行优化才行:

这里我们的优化用到了双指针的思路。

那么,到底为什么需要这样用呢?我接下来就讲一讲具体的思路:

首先,我们知道,在对于矩阵进行遍历的时候,我们是有四个边界的,也就是上界下界,左界右界一共就这4个边界,要想让时间复杂度降低的话,我们思考怎么才能减少一层循环才行。

假设,我们把上下两个边界进行了固定,那么剩下的左右边界移动,这个时候是不是就是在这一个小边界里进行了遍历呢?也就是说,我们把这个问题转变成了动态的一维前缀和问题了。

也就是说,如果上下边界固定住了,假如上边界是1,下边界是2,这个时候这两个边界之间是不是就只剩下了一行数据了呢?这样是不是一维的前缀和考虑了呢?显然是的。但是,如果说上下边界分别是4,1的话,中间不就是有3行了吗?这样该怎么办呢?我们类比着,将着每一列的数加起来,这样不就变成了一列一个数了吗?这样不就变相的转变成了一维数组的问题了么?

其实这样就已经可以了,我们这个时候定义两个指针,进行一前一后的遍历,显然要比我们一直遍历要高效,也就是左指针和右指针。双指针能够根据判断当前的权值是否能够达到题目中的条件做出判断,如果说此时的权值要大,说明我们需要缩小现在的区间,让左指针向着右指针的方向靠拢。

有人问,为啥不是右指针开始往后找呢?这里我们的右指针其实也是从跟左指针一样的初始位置,你如果这样认为,那有可能是其他的双指针题目让你把右指针放在了最后面,其实这样也行,不妨尝试一下。我们就只按照现在这个思路说。

上代码:

复制代码
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<cmath> 
#include<vector>
#include<algorithm>
#include<stack>
#include<queue>
#include<sstream>
#include<map>
#include<limits.h>
#include<set>
#define MAX 505
#define _for(i,a,b) for(int i=a;i<(b);i++)
#define ALL(x) x.begin(),x.end()
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
int arr[MAX][MAX];
int b[MAX][MAX];
LL n, m, counts, num;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin >> n >> m >> num;
    _for(i, 1, n+1) {
        _for (j, 1, m + 1) {
            cin >> arr[i][j];
            arr[i][j] += arr[i - 1][j];
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = i; j <= n; j++) {
            for (int l = 1, r = 1, sum = 0; r <= m; r++) {
                sum += arr[j][r] - arr[i - 1][r];
                while (sum > num) {
                    sum -= arr[j][l] - arr[i - 1][l];
                    l++;
                }
                counts += r - l + 1;
            }
        }
    }
    cout << counts << endl;
    return 0;
}
相关推荐
hetao173383711 分钟前
2025-12-25~26 hetao1733837的刷题记录
c++·笔记·算法
bbq粉刷匠24 分钟前
Java二叉树基础提升
java·数据结构·算法
nju_spy34 分钟前
12月力扣每日一题(划分dp + 单调栈 + 堆 + 会议安排)
算法·leetcode·二分查找·动态规划·滑动窗口·单调栈·最大堆
智算菩萨35 分钟前
【Python机器学习】支持向量机(SVM)完全指南:从理论到实践的深度探索
算法·机器学习·支持向量机
中國龍在廣州38 分钟前
2025,具身智能正在惩罚“持有者”
人工智能·深度学习·算法·自然语言处理·chatgpt
爱学习的capoo42 分钟前
电气控制与PLC考点(自用)
算法
byzh_rc1 小时前
[算法设计与分析-从入门到入土] 递归
数据库·人工智能·算法·机器学习·支持向量机
Yuer20251 小时前
WebRTC 实时语音交互如何支持“可中断”?为什么状态机(FSM)是绕不开的方案
算法·rust·webrtc·fsm
CoderCodingNo1 小时前
【GESP】C++五级真题(数论、埃氏筛思想考点) luogu-B3969 [GESP202403 五级] B-smooth 数
开发语言·c++·算法
思成Codes1 小时前
数据结构: 权值线段树——线段树系列(提供模板)
数据结构·算法