zoukankan      html  css  js  c++  java
  • [Leetcode] 560. Subarray Sum Equals K | 和为K的子数组

    Given an array of integers and an integer k, you need to find the total number of continuous subarrays whose sum equals to k.

    Example 1:

    Input:nums = [1,1,1], k = 2
    Output: 2
    

    Note:

    1. The length of the array is in range [1, 20,000].
    2. The range of numbers in the array is [-1000, 1000] and the range of the integer k is [-1e7, 1e7].

    给了一个整数数组nums和一个整数k,让求连续子数组中和为k的子数组个数。

    这道题用到了一个叫累加和快速求子集和的方法。即如果我们想快速求出一个数组的子数组的和,可以通过O(n2)的方式,先新建一个累加和数组,然后根据以下代码:

    for (int i = 0; i < sums.length; i++) {
      sums[i] // 代表子数组nums[0:i],两边都是闭区间
      for (int j = i - 1; j >= 0; j--) {
        sums[i] - sums[j] // j从i-1开始循环,代表以nums[i]为终点的子数组的和
      }
    }
    

    如数组nums为[1, 3, 4, 6],累加和数组sums为[1, 4, 8, 14],假设i = 3,则在累加和方法中能求出[1, 3, 4, 6]、[3, 4, 6]、[4, 6]、[6]这四个子数组之和。

    解法一

    通过累加和方法,时间复杂度为O(n2)。

    public class Solution {
        public int subarraySum(int[] nums, int k) {
            int count = 0;
            int[] sum = new int[nums.length + 1];
            sum[0] = 0;
            for (int i = 1; i <= nums.length; i++)
                sum[i] = sum[i - 1] + nums[i - 1];
            for (int start = 0; start < nums.length; start++) {
                for (int end = start + 1; end <= nums.length; end++) {
                    if (sum[end] - sum[start] == k)
                        count++;
                }
            }
            return count;
        }
    }
    

    解法二

    但是在讨论区中比较推崇是O(n)的HashMap+累加和的方法。

    public class Solution {
        public int subarraySum(int[] nums, int k) {
            int sum = 0, result = 0;
            Map<Integer, Integer> preSum = new HashMap<>();
            preSum.put(0, 1);
            
            for (int i = 0; i < nums.length; i++) {
                sum += nums[i];
                if (preSum.containsKey(sum - k)) {
                    result += preSum.get(sum - k);
                }
                preSum.put(sum, preSum.getOrDefault(sum, 0) + 1);
            }
            
            return result;
        }
    }
    

    我们可以这样理解:

    假设j >= i,连续子数组nums[i:j]的和为k,那么nums[0:i - 1]的和即为sums[j] - k。在上面解法中,我们即是以sum - k为hashmap的key值,因为我们是从0开始遍历的,在遍历的过程,如果存在当前i位置之前的累积和,也就是说如果preSum这个map中已经存有sum - k了,假设出现了n次,那么和为k的子数组一定也有n个。

    也就是说在当前的i之前,已经有nums[0:p]、nums[0:q]、nums[0:m]的累加和为sum - k了,一共有n个,那么和为k的连续子数组有多少个呢?nums[p + 1, i]、nums[q + 1, i]、nums[m + 1, i],一样有n个。

    除了上一点之外,因为sums累加和是从0开始的累加和,而题意要求的是可以是从0开始,也可以是从任意位置开始的累加和。我们初始化一个(0,1) 就是代表sum - k = 0,即从0开始加到当前数正好等于k,默认为1次。

    参考资料:

    Java Solution, PreSum + HashMap

  • 相关阅读:
    IntelliJ IDEA 14.03 java 中文文本处理中的编码格式设置
    应聘感悟
    STL string分析
    CUDA SDK VolumeRender 分析 (1)
    BSP
    CUDA SDK VolumeRender 分析 (3)
    CUDA SDK VolumeRender 分析 (2)
    Windows软件发布时遇到的一些问题
    Ten Commandments of Egoless Programming (转载)
    复习下光照知识
  • 原文地址:https://www.cnblogs.com/9plus/p/12250387.html
Copyright © 2011-2022 走看看