数据结构-线性表(数组)-线性前缀和+哈希表 930 && 974 && 525

930和相同的二元子数组 同560题

  • 思路
    求连续子数组,一般考虑前缀和。需要查找再想到哈希表。
    sum[i]表示数组nums中0~i的前缀和,假设子数组[j,i+1]和为gal,也就是sum[j]-sum[i] = gal;子数组长度为j-i;所以遍历nums,查看当前值前缀和在哈希表中存在的个数x,就说明当前值为结尾的子数组和为gal的子数组个数为x个
  • 代码解析
class Solution {
public:
    int numSubarraysWithSum(vector<int>& nums, int goal) {
        int len = nums.size();
        unordered_map<int,int> hash_table;
        int left = 0;
        int res = 0;
        for(int i = 0; i<len; ++i){
            ++hash_table[left];
            left += nums[i];
            res += hash_table[left - goal];
        }
        return res;
    }
};
  • 总结学习
    1:通常情况下,涉及连续子数组问题的时候,使用前缀和来解决。
    2:查找问题,考虑哈希表,且遍历时,先对当前值在哈希表中查找,然后再根据题目要求是否添加进 入哈希表
    3:哈希表value值存key出现次数 当前位置下标。

974和可被 K 整除的子数组

  • 思路
    根据同余定理,遍历数组nums,把前缀和对K的余数存入哈希表中,判断当前位置前缀和对k求余的余数为key值的个数。
    细节:1. hash[0] = 1是为了处理 k = 2 [2,3,2,…] 这种情况
    2.当nums中有负数,进行求余要rem = (left%k+k)%k
    原因:
    拿K = 4为例,求出某个前缀和为 -1,-1 % K 应该为 3,但有的编程语言 -1 % K = -1
    这个 -1,要加上 K,转成正 3。
    为什么 preSum 值为 -1 和 3 需要归为同一类?
    因为:-1 和 3 分别模 4 的结果看似不相等,但前缀和之差:(-1)-(3)等于4。4 % K = 0,即所形成的子数组满足元素和被 4 整除。所以前缀和 -1 和 3 其实是等价的。
    最后处理负数的时候,讲解的前缀和之差是不是应该为(-1)-(3)?靠后的前缀和b余为-1,既b=n2k+(-1),靠前的前缀和a余为3,既a=n1k+3,所以b-a=(n2-n1)*k + (-1)-(3) 感觉这样更好理解一点

  • 代码

class Solution {
public:
    int subarraysDivByK(vector<int>& nums, int k) {
        int len = nums.size();
        int left = 0,rem = 0,res = 0;
        unordered_map<int,int> hash;
        hash[0] = 1;
        for(int i = 0;i<len;++i){
            left += nums[i];
            rem = (left%k+k)%k;//rem = left%k有什么区别 就是负数的情况为甚要这么处理
            if(hash.count(rem)) res += hash[rem];  
            ++hash[rem];
        }
        return res;
    }
};
  • 总结学习
    1:C++ 负数求余
    2:数学知识吧 对于思路中的 负余数a加k==正余数b 则也符合同余定理

525. 连续数组

给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。

第二遍没做出来

  • 用什么方法?为什么用这个方法?
    求符合某条件的子数组最长长度,考虑转化为前缀和来统计满足某条件的子数组,前缀和下标求子数组长度。然后根据题目只有两种元素(0 1)把0转换成-1,当两个元素前缀和相同时,说明这两个元素(前开后闭)为边界的区间的子数组 01个数相同。
  • 代码
class Solution {
public:
    int findMaxLength(vector<int>& nums) {
        int len = nums.size();
        unordered_map<int,int> hash;
        int sum = 0;
        int maxlen = 0;
        hash[0] = -1;
        for(int i = 0;i<len;i++){
            sum += nums[i]>0?1:-1;
            if(hash.count(sum)){
                int temp = hash[sum];
                maxlen = max(maxlen,i-temp);
            }else{
                hash[sum] = i;
            }
        }
        return maxlen;
    }
};
  • 学到了什么?
    使用前缀和统计子数组时,一定要先搞清楚子数组长度与前缀和下标的关系!!!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值