基于leetcode的算法训练:Day4

2.6 和为k的子数组

题目描述:给定一个整数数组和一个整数 k **,**请找到该数组中和为 k 的连续子数组的个数。

题目链接:剑指 Offer II 010. 和为 k 的子数组 - 力扣(LeetCode)

题目难度:✨✨✨

超时不看的暴力WA

也是一道暴力不可破的题目,暴力题解如下:

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        //找到和为k的连续子数组的个数
        int len=nums.size();
        vector<int>preSum(len,0);
        for(int i=0;i<len;i++){
            if(i){
                preSum[i]=preSum[i-1]+nums[i];
            }else{
                preSum[i]=nums[i];
            }
        }
        int ans=0;
        for(int i=0;i<len;i++){
            for(int j=i;j<len;j++){
                if(preSum[j]-preSum[i]+nums[i]==k){
                    ans++;
                }
            }
        }
        return ans;
    }
};

参考题解

思路:

  • hashmap+前缀和
  • 遍历数组,求该index下的前缀和为preSum,则只需要计算index之前和为preSum-k的个数即可,用哈希表存前缀和为preSum的个数
  • 计算完上述后更新哈希表,遍历下一个index+1

代码:

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        //找到和为k的连续子数组的个数
        int ans=0;
        int len=nums.size();
        int preSum=0;
        unordered_map<int,int>mp;
        mp[0]=1;
        for(int i=0;i<len;i++){
            preSum+=nums[i];
            int target=preSum-k;
            if(mp.find(target)!=mp.end()){
                ans+=mp[target];
            }
            //更新hash
            if(mp.find(preSum)==mp.end()){
                mp[preSum]=1;
            }else{
                mp[preSum]+=1;
            }
        }
        return ans;
    }
};

2.7 0和1个数相同的子数组

题目描述:给定一个二进制数组 nums , 找到含有相同数量的 01 的最长连续子数组,并返回该子数组的长度。

题目链接剑指 Offer II 011. 0 和 1 个数相同的子数组 - 力扣(LeetCode)

题目难度:✨✨✨

抖机灵不看的WA案例:

不考虑全部通过的话,其实每次考虑min(0的前缀个数,1的前缀个数)就可以覆盖掉大部分的样例

class Solution {
public:
    int findMaxLength(vector<int>& nums) {
        //找到具有相同数量的01最长连续子数组
        int len=nums.size();
        vector<int>count_one(len,0);
        for(int i=0;i<len;i++){
            if(i==0){
                count_one[i]=nums[i];
            }else{
                count_one[i]=nums[i]+count_one[i-1];
            }
        }
        int ans=0;
        for(int i=0;i<len;i++){
            int temp=min(count_one[i],i+1-count_one[i]);
            temp*=2;
            if(temp>ans){
                //printf("i=%d,count_one=%d count_zero=%d\n",i,count_one[i],i+1-count_one[i]);
                ans=temp;
            }
        }
        return ans;
    }
};

官方题解

不得不说……还是很棒的题解,所以看完之后需要自己复现一下

思路

  • 利用unordered_map存储最早出现的和为cnt的下标preIndex
  • 将原始数组中的0视作-1,将原问题转化为求和为0的最长子数组,那么前缀和相等的下标们相减得到的最长长度即为答案(说明中间部分和为0)

代码

class Solution {
public:
    int findMaxLength(vector<int>& nums) {
        int len=nums.size();
        int ans=0;//最大长度
        unordered_map<int,int>mp;//存储最早的前缀和为cnt的index
        int cnt=0;
        mp[cnt]=-1;
        for(int i=0;i<len;i++){
            if(nums[i]==1){
                cnt+=1;
            }else{
                cnt-=1;
            }
            if(mp.find(cnt)!=mp.end()){
                int preIndex=mp[cnt];
                ans=max(ans,i-preIndex);
            }else{
                mp[cnt]=i;
            }
            
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值