1865-找出和为指定值的下标对

Raphael Liu Lv10

给你两个整数数组 nums1nums2 ,请你实现一个支持下述两类查询的数据结构:

  1. 累加 ,将一个正整数加到 nums2 中指定下标对应元素上。
  2. 计数 ,统计满足 nums1[i] + nums2[j] 等于指定值的下标对 (i, j) 数目(0 <= i < nums1.length0 <= j < nums2.length)。

实现 FindSumPairs 类:

  • FindSumPairs(int[] nums1, int[] nums2) 使用整数数组 nums1nums2 初始化 FindSumPairs 对象。
  • void add(int index, int val)val 加到 nums2[index] 上,即,执行 nums2[index] += val
  • int count(int tot) 返回满足 nums1[i] + nums2[j] == tot 的下标对 (i, j) 数目。

示例:

**输入:**
["FindSumPairs", "count", "add", "count", "count", "add", "add", "count"]
[[[1, 1, 2, 2, 2, 3], [1, 4, 5, 2, 5, 4]], [7], [3, 2], [8], [4], [0, 1], [1, 1], [7]]
**输出:**
[null, 8, null, 2, 1, null, null, 11]

**解释:**
FindSumPairs findSumPairs = new FindSumPairs([1, 1, 2, 2, 2, 3], [1, 4, 5, 2, 5, 4]);
findSumPairs.count(7);  // 返回 8 ; 下标对 (2,2), (3,2), (4,2), (2,4), (3,4), (4,4) 满足 2 + 5 = 7 ,下标对 (5,1), (5,5) 满足 3 + 4 = 7
findSumPairs.add(3, 2); // 此时 nums2 = [1,4,5, _ **4**_,5,4]
findSumPairs.count(8);  // 返回 2 ;下标对 (5,2), (5,4) 满足 3 + 5 = 8
findSumPairs.count(4);  // 返回 1 ;下标对 (5,0) 满足 3 + 1 = 4
findSumPairs.add(0, 1); // 此时 nums2 = [ _ **2**_ ,4,5,4,5,4]
findSumPairs.add(1, 1); // 此时 nums2 = [2, _ **5**_ ,5,4,5,4]
findSumPairs.count(7);  // 返回 11 ;下标对 (2,1), (2,2), (2,4), (3,1), (3,2), (3,4), (4,1), (4,2), (4,4) 满足 2 + 5 = 7 ,下标对 (5,3), (5,5) 满足 3 + 4 = 7

提示:

  • 1 <= nums1.length <= 1000
  • 1 <= nums2.length <= 105
  • 1 <= nums1[i] <= 109
  • 1 <= nums2[i] <= 105
  • 0 <= index < nums2.length
  • 1 <= val <= 105
  • 1 <= tot <= 109
  • 最多调用 addcount 函数各 1000

方法一:哈希表

提示 1

由于数组 nums}_1 的最大长度小于等于 nums}_2,因此对于 getPairs(tot) 操作,我们可以将 nums}_2 中的元素放入哈希映射中,枚举 nums}_1 中的元素 num,从而在哈希映射中找出键 tot} - \textit{num 对应的值。这些值的总和即为答案。

思路与算法

我们将数组 num}_1 和 nums}_2 存储下来,并且额外存储一份数组 nums}_2 中元素的哈希映射 cnt。

对于 add(index, val) 操作,我们将 cnt}[\textit{nums}_2[\textit{index}]] 减去 1,nums}_2[\textit{index}] 加上 val,再将更新后的 cnt}[\textit{nums}_2[\textit{index}]] 加上 1。

对于 getPairs(tot) 操作,我们枚举 nums}_1 中的元素 num,将答案累加 cnt}[\textit{tot} - \textit{num}],并返回最终的答案。

代码

[sol1-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class FindSumPairs {
private:
vector<int> nums1, nums2;
unordered_map<int, int> cnt;

public:
FindSumPairs(vector<int>& nums1, vector<int>& nums2) {
this->nums1 = nums1;
this->nums2 = nums2;
for (int num: nums2) {
++cnt[num];
}
}

void add(int index, int val) {
--cnt[nums2[index]];
nums2[index] += val;
++cnt[nums2[index]];
}

int count(int tot) {
int ans = 0;
for (int num: nums1) {
int rest = tot - num;
if (cnt.count(rest)) {
ans += cnt[rest];
}
}
return ans;
}
};
[sol1-Python3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class FindSumPairs:

def __init__(self, nums1: List[int], nums2: List[int]):
self.nums1 = nums1
self.nums2 = nums2
self.cnt = Counter(nums2)

def add(self, index: int, val: int) -> None:
_nums2, _cnt = self.nums2, self.cnt

_cnt[_nums2[index]] -= 1
_nums2[index] += val
_cnt[_nums2[index]] += 1

def count(self, tot: int) -> int:
_nums1, _cnt = self.nums1, self.cnt

ans = 0
for num in _nums1:
if (rest := tot - num) in _cnt:
ans += _cnt[rest]
return ans

复杂度分析

  • 时间复杂度:O(n + q_1 + (q_2 + 1)m),其中 n 和 m 分别是数组 nums}_1 和 nums}_2 的长度,q_1 和 q_2 分别是 add(index, val) 和 getPairs(tot) 操作的次数。

    • 初始化需要的时间为 O(n + m);

    • 单次 add(index, val) 操作需要的时间为 O(1);

    • 单次 getPairs(tot) 操作需要的时间为 O(m)。

    将它们分别乘以操作次数再相加即可得到总时间复杂度。

  • 空间复杂度:O(n + m + q_1)。数组 nums}_1 和 nums}_2 分别需要 O(n) 和 O(m) 的空间,哈希映射初始时需要 O(m) 的空间,每一次 add(index, val) 操作需要额外的 O(1) 空间。

    这里也可以选择在 add(index, val) 操作时将值减为 0 的键值对删除,使得哈希映射的空间恒定为 O(m) 而与 q_1 无关。

 Comments
On this page
1865-找出和为指定值的下标对