leetcode-master/problems/0349.两个数组的交集.md

291 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20210924105952.png" width="1000"/>
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
> 如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费!
## 349. 两个数组的交集
[力扣题目链接](https://leetcode-cn.com/problems/intersection-of-two-arrays/)
题意:给定两个数组,编写一个函数来计算它们的交集。
![349. 两个数组的交集](https://img-blog.csdnimg.cn/20200818193523911.png)
**说明:**
输出结果中的每个元素一定是唯一的。
我们可以不考虑输出结果的顺序。
## 思路
这道题目主要要学会使用一种哈希数据结构unordered_set这个数据结构可以解决很多类似的问题。
注意题目特意说明:**输出结果中的每个元素一定是唯一的,也就是说输出的结果的去重的, 同时可以不考虑输出结果的顺序**
这道题用暴力的解法时间复杂度是$O(n^2)$,那来看看使用哈希法进一步优化。
那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html)
但是要注意,**使用数组来做哈希的题目,是因为题目都限制了数值的大小。**
而这道题目没有限制数值的大小,就无法使用数组来做哈希表了。
**而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。**
此时就要使用另一种结构体了set 关于setC++ 给提供了如下三种可用的数据结构:
* std::set
* std::multiset
* std::unordered_set
std::set和std::multiset底层实现都是红黑树std::unordered_set的底层实现是哈希表 使用unordered_set 读写效率是最高的并不需要对数据进行排序而且还不要让数据重复所以选择unordered_set。
思路如图所示:
![set哈希法](https://img-blog.csdnimg.cn/2020080918570417.png)
C++代码如下:
```CPP
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result_set; // 存放结果
unordered_set<int> nums_set(nums1.begin(), nums1.end());
for (int num : nums2) {
// 发现nums2的元素 在nums_set里又出现过
if (nums_set.find(num) != nums_set.end()) {
result_set.insert(num);
}
}
return vector<int>(result_set.begin(), result_set.end());
}
};
```
## 拓展
那有同学可能问了遇到哈希问题我直接都用set不就得了用什么数组啊。
直接使用set 不仅占用空间比数组大而且速度要比数组慢set把数值映射到key上都要做hash计算的。
不要小瞧 这个耗时,在数据量大的情况,差距是很明显的。
## 其他语言版本
Java
```Java
import java.util.HashSet;
import java.util.Set;
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) {
return new int[0];
}
Set<Integer> set1 = new HashSet<>();
Set<Integer> resSet = new HashSet<>();
//遍历数组1
for (int i : nums1) {
set1.add(i);
}
//遍历数组2的过程中判断哈希表中是否存在该元素
for (int i : nums2) {
if (set1.contains(i)) {
resSet.add(i);
}
}
int[] resArr = new int[resSet.size()];
int index = 0;
//将结果几何转为数组
for (int i : resSet) {
resArr[index++] = i;
}
return resArr;
}
}
```
Python3
```python
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
return list(set(nums1) & set(nums2)) # 两个数组先变成集合,求交集后还原为数组
```
Go
```go
func intersection(nums1 []int, nums2 []int) []int {
m := make(map[int]int)
for _, v := range nums1 {
m[v] = 1
}
var res []int
// 利用count>0实现重复值只拿一次放入返回结果中
for _, v := range nums2 {
if count, ok := m[v]; ok && count > 0 {
res = append(res, v)
m[v]--
}
}
return res
}
```
```golang
//优化版利用set减少count统计
func intersection(nums1 []int, nums2 []int) []int {
set:=make(map[int]struct{},0)
res:=make([]int,0)
for _,v:=range nums1{
if _,ok:=set[v];!ok{
set[v]=struct{}{}
}
}
for _,v:=range nums2{
//如果存在于上一个数组中则加入结果集并清空该set值
if _,ok:=set[v];ok{
res=append(res,v)
delete(set, v)
}
}
return res
}
```
javaScript:
```js
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var intersection = function(nums1, nums2) {
// 根据数组大小交换操作的数组
if(nums1.length < nums2.length) {
const _ = nums1;
nums1 = nums2;
nums2 = _;
}
const nums1Set = new Set(nums1);
const resSet = new Set();
// for(const n of nums2) {
// nums1Set.has(n) && resSet.add(n);
// }
// 循环 比 迭代器快
for(let i = nums2.length - 1; i >= 0; i--) {
nums1Set.has(nums2[i]) && resSet.add(nums2[i]);
}
return Array.from(resSet);
};
```
TypeScript:
版本一(正常解法):
```typescript
function intersection(nums1: number[], nums2: number[]): number[] {
let resSet: Set<number> = new Set(),
nums1Set: Set<number> = new Set(nums1);
for (let i of nums2) {
if (nums1Set.has(i)) {
resSet.add(i);
}
}
return Array.from(resSet);
};
```
版本二(秀操作):
```typescript
function intersection(nums1: number[], nums2: number[]): number[] {
return Array.from(new Set(nums1.filter(i => nums2.includes(i))))
};
```
Swift
```swift
func intersection(_ nums1: [Int], _ nums2: [Int]) -> [Int] {
var set1 = Set<Int>()
var set2 = Set<Int>()
for num in nums1 {
set1.insert(num)
}
for num in nums2 {
if set1.contains(num) {
set2.insert(num)
}
}
return Array(set2)
}
```
PHP:
```php
class Solution {
/**
* @param Integer[] $nums1
* @param Integer[] $nums2
* @return Integer[]
*/
function intersection($nums1, $nums2) {
if (count($nums1) == 0 || count($nums2) == 0) {
return [];
}
$counts = [];
$res = [];
foreach ($nums1 as $num) {
$counts[$num] = 1;
}
foreach ($nums2 as $num) {
if (isset($counts[$num])) {
$res[] = $num;
}
unset($counts[$num]);
}
return $res;
}
}
```
Rust:
```rust
use std::collections::HashSet;
impl Solution {
pub fn intersection(nums1: Vec<i32>, nums2: Vec<i32>) -> Vec<i32> {
let mut resultSet: HashSet<i32> = HashSet::with_capacity(1000);
let nums1Set: HashSet<i32> = nums1.into_iter().collect();
for num in nums2.iter() {
if nums1Set.contains(num) {
resultSet.insert(*num);
}
}
let ret: Vec<i32> = resultSet.into_iter().collect();
ret
}
}
```
## 相关题目
* 350.两个数组的交集 II
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>