【前缀+Hash】与【双指针】的区别

注:双指针法俗称“滑动窗口”,但我不喜欢这个名称,因为这给人感觉是一个固定长度的窗口在(数组上)滑动,而实际上该方法中的“窗口”长度不是固定的,更像个手风琴或弹簧。

例题

前缀+Hash:560. 和为K的子数组

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

示例 1 :

1输入:nums = [1,1,1], k = 2
2输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。

题解:

 1class Solution {
 2public:
 3    int subarraySum(vector<int>& nums, int k) {
 4        unordered_map<int, int> hash = { {0, 1} };
 5        int sum = 0;
 6        int count = 0;
 7
 8        for (const auto& n : nums) {
 9            sum += n;
10            int pre = sum - k;
11            if (hash.count(pre)) {
12                count += hash.at(pre);
13            }
14            hash[sum]++;
15        }
16        return count;
17    }
18};

其他例题:

双指针:209. 长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:

1输入:s = 7, nums = [2,3,1,2,4,3]
2输出:2
3解释:子数组 [4,3] 是该条件下的长度最小的子数组。

题解:

 1class Solution {
 2public:
 3    int minSubArrayLen(int s, vector<int>& nums) {
 4        const size_t n = nums.size();
 5        int sum = 0;
 6        size_t start = 0;
 7        size_t end = 0; //inclusive, which effects calculation of length
 8        size_t len = ULLONG_MAX;
 9
10        for (; end < n; ++end) {
11            sum += nums[end];
12            while (sum >= s) {
13                len = min(len, end - start + 1); // here
14                sum -= nums[start];
15                start++;
16            }
17        }
18        if (len == ULLONG_MAX) {
19            return 0;
20        }
21        return len;
22    }
23};

其他例题:

使用场景

  • 前缀+Hash:
    • 求数量(How many)
    • 长串与子串有数学上的联系
    • 输入一般为带负数的整数数组
  • 双指针:
    • 求唯一(Which one),如最大/最小
    • 数学联系不明显/不重要
    • 输入一般为正整数数组/字符串

(据说)双指针法可有效处理多种较为复杂的【子字符串匹配】问题~


差分数列
从一段 Android 源码说开去