Leetcode——560. 和为 K 的子数组

文章介绍了如何在LeetCode题目中解决计算整数数组中和为k的子数组个数的问题,首先提到暴力求解方法,然后通过前缀和和哈希表优化算法降低时间复杂度。
摘要由CSDN通过智能技术生成

560. 和为 K 的子数组 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/subarray-sum-equals-k/description/

题目描述:

给你一个整数数组 nums 和一个整数 k ,请你统计并返回该数组中和为 k 的子数组的个数 。子数组是数组中元素的连续非空序列

题目解析:

 根据题目我们可以得知本题要求我们找到和为 k 的非空连续子序列的个数并将个数返回。

例如:假设nums:{1,2,2,3}  k : 3

我们可以从中找出三组和为 k 的数组,但是因为题目要求的是连续且非空所以只有1,3两组符合题意,结果返回 2。

暴力求解:

直接根据题目的要求挨个求和判断结果是否为 k ;

class Solution {
    public int subarraySum(int[] nums, int k) {
        //用来记录符合题意的数组个数
        int count = 0;
        int len = nums.length;
        //直接暴力求和
        for (int i = 0; i < len; i++) {
            int tmp = 0;
            for (int j = i; j < len; j++) {
                tmp += nums[j];
                if (tmp == k) {
                    count++;
                }
            }
        }
        return count;
    }
}

它好歹是个中等难度的题这道题用暴力解法可以通过是我没有想到的。

前缀和优化:

虽然暴力解法可以通过但是用时是非常长的,因为题目并只要求我们返回符合题意的数组数目,所以我们可以利用前缀和来对暴力解法进行优化:

  • 第一步:先求出每个位置的前缀和;
  • 第二步:找出前缀和数组中值为 k 的个数;
  • 第三步:前缀和数组中的每位两两相减找出差为 k 的个数;
  • 第四步:返回第二步和第三步找出的数目之和;

class Solution {
    public int subarraySum(int[] nums, int k) {
        int l = 0;
        int r = 0;
        int len = nums.length;
        //用来统计符合题意的数组个数
        int count = 0;
        //利用循环来求出前缀和数组
        for (int i = 0; i < len; i++) {
            if (i != 0) {
                nums[i] = nums[i] + nums[i-1];
            }
            //判断改位是否等于k
            if (nums[i] == k) {
                count++;
            }
        }
        //使前缀和数组中的每位两两相减找出差为 k 的个数
        for (int i = 0; i < len; i++) {
            for (int j = i+1; j < len; j++) {
                if (nums[j] - nums[i] == k) {
                    count++;
                }
            }
        }
        return count;
    }
}

前缀和+哈希表优化:

上面的优化感觉是负优化,但其实是为了这一步做的铺垫我们可以利用公式: Xi - k = Y 来进行优化,Xi 表示前缀和数组的第 i 位;只要我们知道第 i 位之前有多少个值为 Y 的数就行了。所以我们可以引入哈希表来存储第 i 位之前的数;

class Solution {
    public int subarraySum(int[] nums, int k) {
        int count = 0;
        //创建一个哈希表 来存储第 i 位之前的数
        Map<Integer, Integer> hash = new HashMap<>();
        //此处存储一个 0 是必须的,
        //因为有可能第 i 位刚好等于 k;
        hash.put(0, 1);
        //此处利用sum来优化了前缀和数组。
        int sum = 0;
        int len = nums.length;
        for (int i = 0; i < len; i++) {
            //求第i位的前缀和
            sum += nums[i];
            //判断哈希表中是否有符合题意的 Y ;
            //如果没有就将第i位的前缀和放入哈希表
            if (hash.containsKey(sum-k)) {
                int tmp = hash.get(sum-k);
                count += tmp;
            }
            if (hash.containsKey(sum)) {
                int tmp = hash.get(sum);
                hash.put(sum,tmp+1);
            }
            else {
                hash.put(sum,1);
            }
        }
        return count;
    }
}

感谢浏览

  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 17
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值