• 【LeetCode】560. 和为K的子数组(前缀和+哈希表)


    题目链接

    https://leetcode-cn.com/problems/subarray-sum-equals-k/

    题目描述

    给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。

    示例 1 :
    输入:nums = [1,1,1], k = 2
    输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
    
    说明 : 数组的长度为 [
    1, 20,000]。 数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-1e7, 1e7]。

    解题思路

    1.暴力枚举

    数组、字符串的题目,通常可以尝试使用暴力枚举的方式。从数组中每个下标开始,不断向后累加数组元素,当累加数组元素和等于K,则将ans++。

    该方法的时间复杂度为O(n2)。

    2.前缀和

    这次最初的想法是想使用滑动窗口,当滑动窗口的值 < K,则将滑动窗口扩张,即将滑动窗口右侧边界右移;当滑动窗口的值 > K;则收缩滑动窗口,即将滑动窗口的左边界右移动。当时由于本题中数组元素的值可以出现负数,而我想到的滑动窗口法适用于数组中的元素要么全部大于0,要么全部小于0。所以此法行不通。

    前缀和思路:

    通过前缀和的想法,把问题转变为

    有几种i、j的取值,可以使得使得从第 i 到 j 项的子数组的求和 == k。

    有几种i、j的取值,可以使得前缀和数组之差 == K。

    所以本体的解法在于,先求出所有前缀和数组中的值,然后在前缀和数组中寻找i、j两个下标对应的值满足i < j && == K。

    时间复杂度还是O(n2)。可以参考LC 两数之和 利用哈希表进行优化。

    以下这张图是对前缀和的理解:

    3.前缀和优化

    我们的目标是要求出前缀和数组中某两个元素之差为K,这个目标与LC中两数之和类似,在LC两数之和中,要求我们在数组中找出某两个元素和为P;等价于当其中一个元素为x,数组中是否存在p-x这个元素,这显然可以采用map进行处理,本题同理。

    AC代码

    1.暴力枚举法(超时)

     1 class Solution {
     2 public:
     3     int subarraySum(vector<int>& nums, int k) {
     4         int cnt = 0;
     5         for(int i = 0; i < nums.size(); i ++){
     6             int sum = 0;
     7             for(int j = i; j < nums.size(); j ++){
     8                 sum += nums[j];
     9                 if(sum == k){
    10                     cnt ++;
    11                 }
    12             }
    13         }
    14         return cnt;
    15     }
    16 };

    2.前缀和(超时)

     1 class Solution {
     2 public:
     3     int subarraySum(vector<int>& nums, int k) {
     4         vector<int> presum(nums.size()+1);
     5         for(int i = 1; i < presum.size(); i++) presum[i] = presum[i-1]+nums[i-1]; //计算前缀和数组的值
     6         int ans = 0;
     7         for(int i = 1; i < presum.size(); i++) //双重for循环计算前缀和数组中某两个元素差值为K
     8         {
     9             for(int j = i; j < presum.size(); j++)
    10             {
    11                 if(presum[j] - presum[i-1] == k) ans++;
    12             }
    13         }
    14         return ans;
    15     }
    16 };

    3.前缀和优化

     1 class Solution {
     2 public:
     3     int subarraySum(vector<int>& nums, int k) {
     4         if(nums.size()==1 && nums[0] == k) return 1;
     5         if(nums.size() == 1 && nums[0] != k) return 0;
     6         vector<int> presum(nums.size()+1);
     7         presum[0]= 0;
     8         for(int i = 1; i < presum.size(); i++)
     9         {
    10             presum[i] = presum[i-1] + nums[i-1];
    11         }
    12         map<int,int> mp;
    13         int ans = 0;
    14         for(int i = 0; i < presum.size(); i++)
    15         {
    16             if(mp[presum[i] - k])
    17             {
    18                 ans += mp[presum[i] - k];
    19             }
    20             mp[presum[i]]++; //该行代码必须在if判断语句之后,否则当出现K=0时,不能通过测试用例,例如[-1,-1,1],0 在循环内部,每条语句的顺序都至关重要
    21         }
    22         return ans;
    23     }
    24 };
  • 相关阅读:
    Python机器学习-分类
    Python2.x和Python3.x的区别
    cut命令
    uniq 命令
    sort命令
    KMP算法
    Trie树
    做10年Windows程序员与做10年Linux程序员的区别
    c语言内存模型
    C语言的一个关键字——static
  • 原文地址:https://www.cnblogs.com/XDU-Lakers/p/12899825.html
Copyright © 2020-2023  润新知