维护每个元素的出现次数(Python/Java/C++/Go)
本质是 1. 两数之和。
遍历 $\textit{nums}_1$ 中的数,问题变成:
- 设 $x = \textit{nums}_1[i]$,计算 $\textit{nums}_2$ 中有多少个数等于 $\textit{tot} - x$。
用哈希表维护 $\textit{nums}_2$ 中每个元素的出现次数,即可 $\mathcal{O}(1)$ 获知。
注:遍历 $\textit{nums}_1$ 中的数,是因为数据范围显示 $\textit{nums}_1$ 的最大长度比 $\textit{nums}_2$ 的小,遍历 $\textit{nums}_1$ 相比遍历 $\textit{nums}_2$ 时间复杂度更低。
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 每个元素的出现次数
self.cnt[self.nums2[index]] -= 1
self.nums2[index] += val
self.cnt[self.nums2[index]] += 1
def count(self, tot: int) -> int:
ans = 0
for x in self.nums1:
ans += self.cnt[tot - x]
return ans
class FindSumPairs:
def __init__(self, nums1: List[int], nums2: List[int]):
self.nums2 = nums2
self.cnt1 = Counter(nums1)
self.cnt2 = Counter(nums2)
def add(self, index: int, val: int) -> None:
# 维护 nums2 每个元素的出现次数
self.cnt2[self.nums2[index]] -= 1
self.nums2[index] += val
self.cnt2[self.nums2[index]] += 1
def count(self, tot: int) -> int:
ans = 0
for x, c1 in self.cnt1.items():
ans += c1 * self.cnt2[tot - x]
return ans
class FindSumPairs {
private final int[] nums1;
private final int[] nums2;
private final Map<Integer, Integer> cnt = new HashMap<>();
public FindSumPairs(int[] nums1, int[] nums2) {
this.nums1 = nums1;
this.nums2 = nums2;
for (int x : nums2) {
cnt.merge(x, 1, Integer::sum);
}
}
public void add(int index, int val) {
// 维护 nums2 每个元素的出现次数
cnt.merge(nums2[index], -1, Integer::sum);
nums2[index] += val;
cnt.merge(nums2[index], 1, Integer::sum);
}
public int count(int tot) {
int ans = 0;
for (int x : nums1) {
ans += cnt.getOrDefault(tot - x, 0);
}
return ans;
}
}
class FindSumPairs {
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 x : nums2) {
cnt[x]++;
}
}
void add(int index, int val) {
// 维护 nums2 每个元素的出现次数
cnt[nums2[index]]--;
nums2[index] += val;
cnt[nums2[index]]++;
}
int count(int tot) {
int ans = 0;
for (int x : nums1) {
ans += cnt[tot - x];
}
return ans;
}
};
type FindSumPairs struct {
nums1 []int
nums2 []int
cnt map[int]int
}
func Constructor(nums1, nums2 []int) FindSumPairs {
cnt := map[int]int{}
for _, x := range nums2 {
cnt[x]++
}
return FindSumPairs{nums1, nums2, cnt}
}
func (p *FindSumPairs) Add(index, val int) {
// 维护 nums2 每个元素的出现次数
p.cnt[p.nums2[index]]--
p.nums2[index] += val
p.cnt[p.nums2[index]]++
}
func (p *FindSumPairs) Count(tot int) (ans int) {
for _, x := range p.nums1 {
ans += p.cnt[tot-x]
}
return
}
复杂度分析
- 时间复杂度:初始化是 $\mathcal{O}(m)$,$\texttt{add}$ 是 $\mathcal{O}(1)$,$\texttt{count}$ 是 $\mathcal{O}(n)$。其中 $n$ 是 $\textit{nums}_1$ 的长度,$m$ 是 $\textit{nums}_2$ 的长度。
- 空间复杂度:$\mathcal{O}(m+q)$。其中 $q$ 是 $\texttt{add}$ 的调用次数。代码没有删除哈希表中出现次数等于 $0$ 的元素。
相似题目
分类题单
- 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
- 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
- 单调栈(基础/矩形面积/贡献法/最小字典序)
- 网格图(DFS/BFS/综合应用)
- 位运算(基础/性质/拆位/试填/恒等式/思维)
- 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
- 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
- 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
- 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
- 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
- 链表、二叉树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA/一般树)
- 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)
欢迎关注 B站@灵茶山艾府