i007.vip

i007.vip

优先队列-降维打击

04.算法训练

和相同的二元子数组

力扣官方题解L6

发布于 1 天前27.8k官方数组哈希表前缀和滑动窗口CC++C#GoJavaJavaScript

方法一:哈希表

思路及算法

假设原数组的前缀和数组为 \textit{sum},且子数组 (i,j] 的区间和为 \textit{goal},那么 \textit{sum}[j]-\textit{sum}[i]=\textit{goal}。因此我们可以枚举 j ,每次查询满足该等式的 i 的数量。

具体地,我们用哈希表记录每一种前缀和出现的次数,假设我们当前枚举到元素 \textit{nums}[j],我们只需要查询哈希表中元素 \textit{sum}[j]-\textit{goal} 的数量即可,这些元素的数量即对应了以当前 j 值为右边界的满足条件的子数组的数量。最后这些元素的总数量即为所有和为 \textit{goal} 的子数组数量。

在实际代码中,我们实时地更新哈希表,以防止出现 i \geq j 的情况。

代码

class Solution {
public:
    int numSubarraysWithSum(vector<int>& nums, int goal) {
        int sum = 0;
        unordered_map<int, int> cnt;
        int ret = 0;
        for (auto& num : nums) {
            cnt[sum]++;
            sum += num;
            ret += cnt[sum - goal];
        }
        return ret;
    }
};

复杂度分析

  • 时间复杂度:O(n),其中 n 为给定数组的长度。对于数组中的每个元素,我们至多只需要插入到哈希表中中一次。
  • 空间复杂度:O(n),其中 n 为给定数组的长度。哈希表中至多只存储 O(n) 个元素。

方法二:滑动窗口

思路及算法

注意到对于方法一中每一个 j,满足 \textit{sum}[j]-\textit{sum}[i]=\textit{goal} 的 i 总是落在一个连续的区间中,i 值取区间中每一个数都满足条件。并且随着 j 右移,其对应的区间的左右端点也将右移,这样我们即可使用滑动窗口解决本题。

具体地,我们令滑动窗口右边界为 \textit{right},使用两个左边界 \textit{left}_1 和 \textit{left}_2 表示左区间 [\textit{left}_1,\textit{left}_2),此时有 \textit{left}_2-\textit{left}_1 个区间满足条件。

在实际代码中,我们需要注意 \textit{left}_1 \leq \textit{left}_2 \leq \textit{right} + 1,因此需要在代码中限制 \textit{left}_1 和 \textit{left}_2 不超出范围。

代码

class Solution {
public:
    int numSubarraysWithSum(vector<int>& nums, int goal) {
        int n = nums.size();
        int left1 = 0, left2 = 0, right = 0;
        int sum1 = 0, sum2 = 0;
        int ret = 0;
        while (right < n) {
            sum1 += nums[right];
            while (left1 <= right && sum1 > goal) {
                sum1 -= nums[left1];
                left1++;
            }
            sum2 += nums[right];
            while (left2 <= right && sum2 >= goal) {
                sum2 -= nums[left2];
                left2++;
            }
            ret += left2 - left1;
            right++;
        }
        return ret;
    }
};

复杂度分析

  • 时间复杂度:O(n),其中 n 为给定数组的长度。我们至多只需要遍历一次该数组。
  • 空间复杂度:O(1)。我们只需要常数的空间保存若干变量。

发表回复