在HashMap中存储和和频率的直觉

时间:2017-07-14 12:00:28

标签: java algorithm hashmap

我们得到了一个整数数组和另一个数字k,我们需要找到其总和等于k的连续子数组的总数。我在LeetCode上找到了以下有趣的代码片段:

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

我喜欢有效的解决方案,所以我试图理解它;但我有两个问题:

  1. 将当前sum及其frequency存储在HashMap中的直觉是什么?
  2. 我们检测到的子阵列是连续的保证是什么?
  3. 示例输入:[1,1,1]和k = 2;
    输出:2

3 个答案:

答案 0 :(得分:3)

在我们扫描nums[]数组时,map将包含我们看过特定sum的次数(sum表示从头开始对数字求和到目前为止)。

现在,在任何给定时间点if,如果我们看到map包含sum-k X次,当前总和为sum,我们就知道,我们发现了X个不同的子数组,其总和为k。这是因为sum包含从开头到当前点的总和,map通过从开头到开始到某个点的总和来编制索引。如果map包含大于1的值,则表示某个总和多次发生(如果num[]为零或负数,则可能发生)。找到的子阵列来自于这个&#34;某些&#34;指向我们当前的位置,所以它必须是连续的。

答案 1 :(得分:1)

尼斯算法。

让我们从简单的事实开始:sum(1, i) = sum(1, j) + sum(j + 1, i)(我这里不使用Java,这是通常的数学符号) 对于任何ij都是如此。

我们需要找到所有sum(j+1, i)等于k

找到sum(1, i) = sum(1, j) + ksum(1, i) -k = sum(1, j)

是一样的

在您的计划中sum(1, i)sum变量。因此,我们需要检查我们是否有jsum -k = sum(1, j)为真。希望我们在sum(1, j)中将所有map作为键。

我们检查map.containsKey(sum - k),如果确实如此,则会有j这样的 for (int num : nums) { sum += num; count += map.getOrDefault(sum - k, 0); map.compute(sum, (key, value) -> (value == null) ? 1 : value + 1); } 给我们所需的金额。

需要使用map中的值来计算获得此类总和的不同方式。

PS:BTW如果所有值都是非负值,则有更好的算法。它不需要额外的内存。

PPS:如果您使用Java 8,我也会对您的代码进行一些改进

{{1}}

答案 2 :(得分:0)

3个关键事项:

  • 第一个键是0
  • 仅当关键字count已在地图中时,
  • 才会增加sum - k
  • 用频率来计算每个总和

我将其分为3个案例:

1st:数字大于零

每个键的频率等于1 那么计数增加了多少?只有当密钥已经存在于地图中时,它才会增加。 钥匙都是以前的总和。因此条件if (map.containsKey(sum - k))的当前关键字是sum - k。如果sum - k是一个关键字,则意味着之前的总和(sum - k)和当前总和之间是和,等于k的元素(原因k + (sum - k) = sum - 我们当前的值) 。所以我们可以增加count - 我们找到了子数组。

第二名:数字大于等于零。
所以现在我们可以在它们之间放置零。它没有多大区别,但您可以想象如果我们增加count会发生什么,在下一步中我们的nums数组中会有0。 在这种情况下,我们会再次增加count

包含零,我们的频率会发生变化。想象一下这个例子: subarraySum({0, 0, 0, 7, 0}, 7);结果为8。 请记住,第一个键是0.所以当我们迭代时,我们在7,我们有一个地图(0: 4)。现在sum = 77 - 7 = 0,我们有3个,所以这个时间计数增加了这个频率。现在我们从数组中选取最后一个元素 - 0。此键的值仍为4. sum - k仍然相同,所以我们的count再次增加了4。

第3名:整数
我认为你明白了这一点;)这次负数也可能增加一些频率。 如果我们在地图中有关键sum - key,则表示在之前的总和(sum - k)之间,现在我们有了整数,总计为k(导致k + (sum - k) = sum - 我们的当前值)。如果是这样,让我们​​按频率增加计数。