LeetCode每日一题 1074. 元素和为目标值的子矩阵数量 手写hash

题目描述

原题链接

给出矩阵 matrix 和目标值 target,返回元素总和等于目标值的非空子矩阵的数量。

子矩阵 x1, y1, x2, y2 是满足 x1 <= x <= x2 且 y1 <= y <= y2 的所有单元 matrix[x][y] 的集合。

如果 (x1, y1, x2, y2) 和 (x1', y1', x2', y2') 两个子矩阵中部分坐标不同(如:x1 != x1'),那么这两个子矩阵也不同。

在这里插入图片描述

示例1

输入:matrix = [[0,1,0],[1,1,1],[0,1,0]], target = 0
输出:4
解释:四个只含 0 的 1x1 子矩阵。

示例2

输入:matrix = [[1,-1],[-1,1]], target = 0
输出:5
解释:两个 1x2 子矩阵,加上两个 2x1 子矩阵,再加上一个 2x2 子矩阵。

解题思路

三种方法
1、朴素遍历
2、stl哈希优化(结果时间还增加了。。)
3、手写hash 64ms!

class Solution {
public:
    int s[110][110];
    int h[211]; // hash,开放寻址法,开输入两到三倍的第一个质数,并用该质数作为mod
    int cnt[211];

    int find(int x)
    {
        int t = (x % 211 + 211) % 211;
        while(h[t] != 0x3f3f3f3f && h[t] != x)
        {
            t ++;
            if(t == 211)t = 0;
        }
        return t;
    }

    int numSubmatrixSumTarget(vector<vector<int>>& matrix, int target) {
        int n = matrix.size();
        int m = matrix[0].size();
        for(int i = 1 ; i <= n ; i ++)
            for(int j = 1 ; j <= m ; j ++)
                s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + matrix[i-1][j-1];

        int res = 0;
        // 朴素版 750ms
        // for(int i = 1 ; i <= n ; i ++)
        //     for(int j = 1 ; j <= m ; j ++)
        //         for(int q = i ; q <= n ; q ++)
        //             for(int w = j ; w <= m ; w ++)
        //                 if(target == s[q][w] + s[i-1][j-1] - s[i-1][w] - s[q][j-1])
        //                     res ++;

        //STL优化 1100ms
        // unordered_map <int , int> mp;
        // for(int top = 1 ; top <= n ; top ++)
        //     for(int down = top ; down <= n ; down ++)
        //     {
        //         mp.clear();
        //         mp[0] ++;
        //         for(int right = 1 ; right <= m ; right ++)
        //         {
        //             int t = s[down][right] - s[top-1][right];
        //             res += mp[t - target];
        //             mp[t] ++;
        //         }
        //     }

        // 手写hash 64ms
        for(int top = 1 ; top <= n ; top ++)
            for(int down = top ; down <= n ; down ++)
            {
                memset(h , 0x3f , sizeof  h);
                memset(cnt , 0 , sizeof cnt);

                h[find(0)] = 0;
                cnt[find(0)] ++;
                for(int right = 1 ; right <= m ; right ++)
                {
                    int t = s[down][right] - s[top-1][right];
                    if(h[find(t-target)] != 0x3f3f3f3f)
                        res += cnt[find(t - target)];
                    h[find(t)] = t;
                    cnt[find(t)] ++;
                }
            }
        
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值