前缀和+哈希表

一维数组模板:

unordered_map mp;
mp[0] = 1;
int sum = 0;
for(auto i : nums){  //这里假设数组为nums
    sum += i;
    if(mp.count())
    mp[sum] ++;
}    

二维数组模板

//这里假设二维数组为nums
int n = nums.size(), m = nums[0].size();
vector> sum(n + 1, vector(m + 1));
for(int i = 1; i <= n; i ++)
    for(int j = 1; j <= m; j ++)
        sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + nums[i - 1][j - 1];   //这里是计算二维数组的前缀和, 如果不是太懂的可以自己换一个图,这样更直观一点
for(int i = 1; i <= n; i ++){
    for(int j = i; j <= n; j ++){
        int ans = 0;
        unordered_map mp;
        mp[0] = 1;
        for(int k = 1; k <= m; k ++){
            ans = sum[j][k] - sum[i - 1][k];
            if(mp.count())        
            mp[ans] ++;
        }
    }
}

例题1:和相同的二元子数组(力扣930 中等)

题目链接:930. 和相同的二元子数组 - 力扣(LeetCode) (leetcode-cn.com)icon-default.png?t=M1L8https://leetcode-cn.com/problems/binary-subarrays-with-sum/

题目:给你一个二元数组nums,和一个整数goal,请你统计并返回有多少个和为goal的非空子数组。子数组是数组的一段连续部分。

示例 1:

输入:nums = [ 1, 0, 1, 0, 1], goal = 2

输出:4

解释:有4个满足题目要求的子数组:[ 1, 0, 1]、[ 1, 0, 1, 0]、[ 0, 1, 0, 1]、[ 1, 0, 1] 

示例 2:

输入:nums = [0, 0, 0, 0, 0], goal = 0

输出:15 

提示:

  • 1 <= nums.length <= 3 * 10^4
  • nums[i]不是0就是1
  • 0 <= goal <= nums.length

题目分析:将前缀和存入到哈希表中,如果在哈希表找到了当前前缀和前去目标值,说明存在非空数组的和为目标值。

代码:

class Solution {
public:
    int numSubarraysWithSum(vector& nums, int goal) {
        unordered_map mp;
        int cnt = 0, sum = 0;
        mp[0] = 1; // 这里是前缀和为了能加上第一个数
        for(auto i : nums){
            sum += i;
            if(mp.count(sum - goal))    //如果能找到当前前缀和减去目标值,说明存在数组
                cnt += mp[sum - goal];
            mp[sum] ++; //将前缀和存入哈希表
        }
        return cnt;
    }
};

 例题 2:连续的子数组和(力扣523  中等)

题目链接:523. 连续的子数组和 - 力扣(LeetCode) (leetcode-cn.com)icon-default.png?t=M1L8https://leetcode-cn.com/problems/continuous-subarray-sum/

 题目:给你一个整数数组nums和一个整数k,编写一个函数来判断该数组是否含有同时满足下述条件的连续子数组:

  • 子数组大小至少为2,且
  • 子数组元素和为k的倍数

如果存在,返回true;否则,返回false。

如果存在一个整数n,令整数x符合x = n * k,则称x是k的一个倍数。0始终视为k的一个倍数。

示例 1:

输入:nums = [ 23, 2, 4, 6, 7],  k = 6

输出:true

解释:[2, 4]是一个大小为2的子数组,并且和为6

示例 2:

输入:nums = [ 23, 2, 6, 4, 7],  k = 6

输出:true

解释:[ 23, 2, 6, 4, 7]是大小为5的子数组,并且和为42。42是6的倍数,因为42 = 7 * 6且7是一个整数

示例 3:

输入:nums = [ 23, 2, 6, 4, 7]

输出:false

提示:

  • 1 <= nums.length <= 10 ^ 5
  • 0 <= nums[i] <= 10 ^ 9
  • 0 <= sum(nums[i]) <= 2^31 - 1
  • 1 <= k <= 2^31 - 1

题目分析:将前缀和对k取模后的值和其所在的位置存入在哈希表中,在哈希表中寻找是否存在有与当前前缀和取模后相等的值,如果存在判断当前位置与寻找到的位置的差是否大于2.

代码:

class Solution {
public:
    bool checkSubarraySum(vector& nums, int k) {
        unordered_map mp;  //第一个int用来存储数据,第二个用来存储位置
        mp[0] = -1; //为加上第一个数数nums[0],0是-1
        int sum = 0;
        for(int i = 0; i < nums.size(); i ++){
            sum = (sum + nums[i]) % k;//这里不对k取模后面的数据会超int, 如果用long long,不能对k取模
            if(mp.count(sum)){
                int pos = mp[sum];
                if(i - pos >= 2)
                    return true;
            }
            else
                mp[sum] = i; // 这里加上else是因为0也是k的倍数
        }
        return false;
    }
};

例题 3:元素和为目标值的子矩阵数量(力扣1074   困难)

题目链接:1074. 元素和为目标值的子矩阵数量 - 力扣(LeetCode) (leetcode-cn.com)icon-default.png?t=M1L8https://leetcode-cn.com/problems/number-of-submatrices-that-sum-to-target/

题目:给出矩阵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子矩阵。 

示例 3:

输入:matrix = [ [ 904]], target = 0

输出:0 

提示:

  • 1 <= matrix.length <= 100
  • 1 <= matrix[0].length <= 100
  • -1000 <= matrix[i][j] <= 1000
  • -10^8 <= target <= 10^8 

题目分析:用一个二维数组来存储数组的前缀和,在循环中将前缀和存入到哈希表中,找出所有满足题目要求的数并将它们相加。

代码:

class Solution {
public:
    int numSubmatrixSumTarget(vector>& matrix, int target) {
        int n = matrix.size(), m = matrix[0].size();
        vector> sum(n + 1, vector(m + 1));  //定义二维前缀和数组
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++)
                sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + matrix[i - 1][j - 1];  //前缀和计算
        int cnt = 0; //统计满足题目要求的个数
        for(int i = 1; i <= n; i ++){
            for(int j = i; j <= n; j ++){  //这里两个循环是为了计算竖立的矩阵
                unordered_map mp; //这里不用写mp[0] = 1,因为后面有一个判断的 
                //mp[0] = 1;  这里和后面的判断ans == target可以选择一个写
                int ans = 0;
                for(int k = 1; k <= m; k ++){
                    ans = sum[j][k] - sum[i - 1][k];
                    if(ans == target)   cnt ++;
                    if(mp.count(ans - target)) cnt += mp[ans - target];
                    mp[ans] ++;
                }
            }
        }
        return cnt;
    }

};

 

你可能感兴趣的:(散列表,leetcode,算法)