diff --git a/src/leetcode/0219.contains-duplicate-ii/assets/brute-force.svg b/src/leetcode/0219.contains-duplicate-ii/assets/brute-force.svg deleted file mode 120000 index ac3ae01a..00000000 --- a/src/leetcode/0219.contains-duplicate-ii/assets/brute-force.svg +++ /dev/null @@ -1 +0,0 @@ -../../0001.two-sum/assets/brute-force.svg \ No newline at end of file diff --git a/src/leetcode/0219.contains-duplicate-ii/assets/hash-table.svg b/src/leetcode/0219.contains-duplicate-ii/assets/hash-table.svg deleted file mode 120000 index 98cef81d..00000000 --- a/src/leetcode/0219.contains-duplicate-ii/assets/hash-table.svg +++ /dev/null @@ -1 +0,0 @@ -../../0001.two-sum/assets/hash-table.svg \ No newline at end of file diff --git a/src/leetcode/0219.contains-duplicate-ii/index.md b/src/leetcode/0219.contains-duplicate-ii/index.md index 5a12a56f..a604ba38 100644 --- a/src/leetcode/0219.contains-duplicate-ii/index.md +++ b/src/leetcode/0219.contains-duplicate-ii/index.md @@ -9,7 +9,7 @@ 这个方法比较直接, 就是遍历数组, 并遍历后面的每个元素, 判断它们是否重复. -![brute-force](assets/brute-force.svg) +![brute-force](../0001.two-sum/assets/brute-force.svg) 因为有两层遍历, 这个方法的时间复杂度是 `O(n^2)`. @@ -22,7 +22,7 @@ 同样是需要遍历整个数组, 我们可以使用哈稀表缓存一下访问过的元素, 以加快查找元素的时间. 这个哈稀表用于记录元素值到它在数组中的索引值之间的关系. -![hash-table](assets/hash-table.svg) +![hash-table](../0001.two-sum/assets/hash-table.svg) 这个方法的时间复杂度是 `O(nlogn)`. diff --git a/src/leetcode/0349.intersection-of-two-arrays/index.md b/src/leetcode/0349.intersection-of-two-arrays/index.md index 4656e41f..6aa8f316 100644 --- a/src/leetcode/0349.intersection-of-two-arrays/index.md +++ b/src/leetcode/0349.intersection-of-two-arrays/index.md @@ -4,7 +4,7 @@ 这是一个搜索问题, 这个问题的解法就比较多了. -## 并行双指针 +## 并行双指针 Parallel Two Pointers 这个也比较符合[并行双指针](../../two-pointers/parallel.md)的使用场景, 遍历两个数组或链表, 用它能很快地计算集合的交集和并集. diff --git a/src/leetcode/0350.intersection-of-two-arrays-ii/assets/hash-table.svg b/src/leetcode/0350.intersection-of-two-arrays-ii/assets/hash-table.svg deleted file mode 120000 index 98cef81d..00000000 --- a/src/leetcode/0350.intersection-of-two-arrays-ii/assets/hash-table.svg +++ /dev/null @@ -1 +0,0 @@ -../../0001.two-sum/assets/hash-table.svg \ No newline at end of file diff --git a/src/leetcode/0350.intersection-of-two-arrays-ii/index.md b/src/leetcode/0350.intersection-of-two-arrays-ii/index.md index b1b24033..e9f21362 100644 --- a/src/leetcode/0350.intersection-of-two-arrays-ii/index.md +++ b/src/leetcode/0350.intersection-of-two-arrays-ii/index.md @@ -24,7 +24,7 @@ 在 [0349. 两个数组的交集 Intersection of Two Arrays](../0349.intersection-of-two-arrays/index.md) 有提到过, `HashSet` 可以用来处理不包含重复元素的集合, 而 `HashMap` 可以用来处理包含有重复元素的集合. -![hash-table](assets/hash-table.svg) +![hash-table](../0001.two-sum/assets/hash-table.svg) ```rust {{#include src/main.rs:41:70 }} diff --git a/src/leetcode/0532.k-diff-pairs-in-an-array/index.md b/src/leetcode/0532.k-diff-pairs-in-an-array/index.md index a770b02e..e5981a86 100644 --- a/src/leetcode/0532.k-diff-pairs-in-an-array/index.md +++ b/src/leetcode/0532.k-diff-pairs-in-an-array/index.md @@ -1,3 +1,53 @@ # 0532.数组中的数对 K-diff Pairs in an Array [问题描述](../problems/0532.k-diff-pairs-in-an-array/content.html) + +这是一个查找问题, 先思考一下处理查找问题的常用手段: + +- 哈稀表或者 HashSet +- BitSet +- 排序后二分查找 +- 排序后快慢型双指针遍历 + +## 哈稀表 Hash Table + +使用哈稀表 HashMap 来统计整数值及其次数; 用集合 HashSet 来存放的有序数对, 并去掉重复的. + +![hash-table](../0001.two-sum/assets/hash-table.svg) + +这种方法可以支持无序数组. + +```rust +{{#include src/main.rs:8:42 }} +``` + +## 二分查找法 Binary Search + +基本的思路是: + +- 先给数组排序 +- 开始遍历数组 +- 根据题目条件, 确定目标的元素的值; 使用二分查找法搜索目标元素 +- 再根据要求, 判断目标元素是否合适, 比如两者索引值不能相同 + +```rust +{{#include src/main.rs:133:181 }} +``` + +## 快慢型双指针 Fast-Slow Two Pointers + +[这个方法](../../two-pointers/fast-slow.md)的效率是最高的, 也最节省内存. + +解决问题之前依然要先给数组排序. + +![fast-slow two-pointers](../../two-pointers/assets/fast-slow.svg) + +这个题目中, 双指针的命中条件是 `nums[fast] - nums[slow] = k;`, 只需要围绕这个核心条件做判断即可. + +```rust +{{#include src/main.rs:183:233 }} +``` + +## 相关问题 + +- [0349. 两个数组的交集 Intersection of Two Arrays](../0349.intersection-of-two-arrays/index.md) diff --git a/src/leetcode/0532.k-diff-pairs-in-an-array/src/main.rs b/src/leetcode/0532.k-diff-pairs-in-an-array/src/main.rs index b1bb99af..4cb51c74 100644 --- a/src/leetcode/0532.k-diff-pairs-in-an-array/src/main.rs +++ b/src/leetcode/0532.k-diff-pairs-in-an-array/src/main.rs @@ -5,7 +5,7 @@ use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; -// 哈稀表 +// 哈稀表来计数 pub fn find_pairs1(nums: Vec, k: i32) -> i32 { assert!(!nums.is_empty()); @@ -14,6 +14,7 @@ pub fn find_pairs1(nums: Vec, k: i32) -> i32 { map.entry(num).and_modify(|count| *count += 1).or_insert(1); } + // 使用集合来去重. let mut set = HashSet::new(); for &num in &nums { // k = diff - num; @@ -40,9 +41,34 @@ pub fn find_pairs1(nums: Vec, k: i32) -> i32 { set.len() as i32 } -// 给数组排序后二分查找, 使用集合来去掉重复的 pair. +// 哈稀表来计数, 对数组排序 pub fn find_pairs2(nums: Vec, k: i32) -> i32 { assert!(!nums.is_empty()); + let mut nums = nums; + nums.sort(); + + let mut map = HashMap::new(); + for num in &nums { + map.entry(num).and_modify(|count| *count += 1).or_insert(1); + } + + // 使用集合来去重. + let mut set = HashSet::new(); + for &num in &nums { + let expected = num + k; + if let Some(count) = map.get(&expected) { + if (expected > num) || ((expected == num) && (*count > 1)) { + set.insert(vec![num, expected]); + } + } + } + + set.len() as i32 +} + +// 给数组排序后二分查找, 使用集合来去掉重复的 pair. +pub fn find_pairs3(nums: Vec, k: i32) -> i32 { + assert!(!nums.is_empty()); // 先排序 let mut nums = nums; @@ -60,7 +86,7 @@ pub fn find_pairs2(nums: Vec, k: i32) -> i32 { } // 排序后二分查找, 不使用额外内存. -pub fn find_pairs3(nums: Vec, k: i32) -> i32 { +pub fn find_pairs4(nums: Vec, k: i32) -> i32 { assert!(!nums.is_empty()); // 先排序 @@ -105,7 +131,7 @@ pub fn find_pairs3(nums: Vec, k: i32) -> i32 { } // 排序后二分查找, 不使用额外内存. 根据 k == 0 做优化 -pub fn find_pairs4(nums: Vec, k: i32) -> i32 { +pub fn find_pairs5(nums: Vec, k: i32) -> i32 { assert!(!nums.is_empty()); // 先排序 @@ -154,8 +180,8 @@ pub fn find_pairs4(nums: Vec, k: i32) -> i32 { count } -// 快慢型二分查找 -pub fn find_pairs5(nums: Vec, k: i32) -> i32 { +// 快慢型双指针 +pub fn find_pairs6(nums: Vec, k: i32) -> i32 { let len = nums.len(); if len <= 1 { return 0; @@ -171,7 +197,7 @@ pub fn find_pairs5(nums: Vec, k: i32) -> i32 { let mut count = 0; // 遍历整个数组. - while slow < len && fast < len { + while fast < len { // 两个指针不能重复, 因为题目要求: `i != j`. if fast == slow { fast += 1; @@ -193,9 +219,11 @@ pub fn find_pairs5(nums: Vec, k: i32) -> i32 { } } Ordering::Less => { + // 两个元素间的差值太小了, 移动 fast 指针 fast += 1; } Ordering::Greater => { + // 两个元素间的差值太大了, 移动 slow 指针 slow += 1; } } @@ -226,11 +254,15 @@ fn main() { check_solution(find_pairs3); check_solution(find_pairs4); check_solution(find_pairs5); + check_solution(find_pairs6); } #[cfg(test)] mod tests { - use super::{check_solution, find_pairs1, find_pairs2, find_pairs3, find_pairs4, find_pairs5}; + use super::{ + check_solution, find_pairs1, find_pairs2, find_pairs3, find_pairs4, find_pairs5, + find_pairs6, + }; #[test] fn test_find_pairs1() { @@ -256,4 +288,9 @@ mod tests { fn test_find_pairs5() { check_solution(find_pairs5); } + + #[test] + fn test_find_pairs6() { + check_solution(find_pairs6); + } }