文章目录
题目
标题和出处
标题:两个数组的交集
出处:349. 两个数组的交集
难度
3 级
题目描述
要求
给定两个数组 nums1 \texttt{nums1} nums1 和 nums2 \texttt{nums2} nums2,返回两个数组的交集。结果中的每个元素必须是唯一的,可以按任意额顺序返回结果。
示例
示例 1:
输入: nums1 = [1,2,2,1], nums2 = [2,2] \texttt{nums1 = [1,2,2,1], nums2 = [2,2]} nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2] \texttt{[2]} [2]
示例 2:
输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] \texttt{nums1 = [4,9,5], nums2 = [9,4,9,8,4]} nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [9,4] \texttt{[9,4]} [9,4]
解释: [4,9] \texttt{[4,9]} [4,9] 也是正确答案。
数据范围
- 1 ≤ nums1.length, nums2.length ≤ 1000 \texttt{1} \le \texttt{nums1.length, nums2.length} \le \texttt{1000} 1≤nums1.length, nums2.length≤1000
- 0 ≤ nums1[i], nums2[i] ≤ 1000 \texttt{0} \le \texttt{nums1[i], nums2[i]} \le \texttt{1000} 0≤nums1[i], nums2[i]≤1000
解法一
思路和算法
两个数组的交集为在两个数组中都出现的元素集合。由于结果中的每个元素只出现一次,因此不需要考虑每个元素在两个数组中的出现次数,只需要考虑在两个数组中都出现的元素。
为了快速判断一个元素是否在数组中出现,且不考虑元素的出现次数,可以使用两个哈希集合分别存储两个数组中的元素。得到两个哈希集合之后,遍历其中任意一个哈希集合,判断其中的每个元素是否在另一个哈希集合中出现,如果一个元素在两个哈希集合中都出现,则该元素在两个数组的交集内,将该元素添加到结果数组中。
实现方面,计算交集时可以遍历较小的哈希集合,则可以遍历较少的元素。
代码
java
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> set1 = new HashSet<Integer>();
Set<Integer> set2 = new HashSet<Integer>();
for (int num : nums1) {
set1.add(num);
}
for (int num : nums2) {
set2.add(num);
}
int[] intersectionArr = set1.size() <= set2.size() ? getIntersection(set1, set2) : getIntersection(set2, set1);
return intersectionArr;
}
public int[] getIntersection(Set<Integer> set1, Set<Integer> set2) {
Set<Integer> intersectionSet = new HashSet<Integer>();
for (int num : set1) {
if (set2.contains(num)) {
intersectionSet.add(num);
}
}
int[] intersectionArr = new int[intersectionSet.size()];
int index = 0;
for (int num : intersectionSet) {
intersectionArr[index] = num;
index++;
}
return intersectionArr;
}
}
复杂度分析
-
时间复杂度: O ( m + n ) O(m + n) O(m+n),其中 m m m 和 n n n 分别是数组 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2 的长度。需要使用 O ( m + n ) O(m + n) O(m+n) 的时间遍历两个数组将元素添加到对应的哈希集合中,然后使用 O ( min ( m , n ) ) O(\min(m, n)) O(min(m,n)) 的时间遍历较小的哈希集合计算交集以及将交集元素填入结果数组,因此时间复杂度是 O ( m + n + min ( m , n ) ) = O ( m + n ) O(m + n + \min(m, n)) = O(m + n) O(m+n+min(m,n))=O(m+n)。
-
空间复杂度: O ( m + n ) O(m + n) O(m+n),其中 m m m 和 n n n 分别是数组 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2 的长度。空间复杂度主要取决于两个哈希集合,两个哈希集合分别需要 O ( m ) O(m) O(m) 和 O ( n ) O(n) O(n) 的空间,因此空间复杂度是 O ( m + n ) O(m + n) O(m+n)。
解法二
思路和算法
解法一的空间复杂度较高,可以使用排序和双指针的做法降低空间复杂度。
首先将两个数组升序排序,排序之后的数组满足相等的元素在数组中的相邻位置,因此可以跳过相等的元素值,确保每个元素值只遍历一次。
用 index 1 \textit{index}_1 index1 和 index 2 \textit{index}_2 index2 分别表示数组 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2 的下标,初始时 index 1 = index 2 = 0 \textit{index}_1 = \textit{index}_2 = 0 index1=index2=0。从左到右遍历两个数组,如果当前元素与前一个元素相等则跳过当前元素。对于两个数组中遍历到的元素,比较元素大小,执行相应操作。
-
如果 nums 1 [ index 1 ] = nums 2 [ index 2 ] \textit{nums}_1[\textit{index}_1] = \textit{nums}_2[\textit{index}_2] nums1[index1]=nums2[index2],则当前元素在两个数组中都出现,因此在两个数组的交集内,将当前元素添加到结果中,将 index 1 \textit{index}_1 index1 和 index 2 \textit{index}_2 index2 同时向右移动一位。
-
如果 nums 1 [ index 1 ] < nums 2 [ index 2 ] \textit{nums}_1[\textit{index}_1] < \textit{nums}_2[\textit{index}_2] nums1[index1]<nums2[index2],则 nums 1 [ index 1 ] \textit{nums}_1[\textit{index}_1] nums1[index1] 不在数组 nums 2 \textit{nums}_2 nums2 中出现,因此不在两个数组的交集中,将 index 1 \textit{index}_1 index1 向右移动一位。
-
如果 nums 1 [ index 1 ] > nums 2 [ index 2 ] \textit{nums}_1[\textit{index}_1] > \textit{nums}_2[\textit{index}_2] nums1[index1]>nums2[index2],则 nums 2 [ index 2 ] \textit{nums}_2[\textit{index}_2] nums2[index2] 不在数组 nums 1 \textit{nums}_1 nums1 中出现,因此不在两个数组的交集中,将 index 2 \textit{index}_2 index2 向右移动一位。
当 index 1 \textit{index}_1 index1 和 index 2 \textit{index}_2 index2 分别在两个数组的下标范围中时,重复上述操作,直到至少有一个下标超出数组的下标范围,此时不存在更多的同时在两个数组中出现的元素,可以得到交集的全部元素。
由于两个数组都按升序排序,当 nums 1 [ index 1 ] ≠ nums 2 [ index 2 ] \textit{nums}_1[\textit{index}_1] \ne \textit{nums}_2[\textit{index}_2] nums1[index1]=nums2[index2] 时都是将较小的元素对应的下标向右移动,因此较小的元素值一定不在另一个数组中出现,否则另一个数组中的下标在遍历到该元素值时不可能继续向右移动。因此上述做法不会遗漏掉交集内的任何元素。
代码
java
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
List<Integer> intersectionList = new ArrayList<Integer>();
Arrays.sort(nums1);
Arrays.sort(nums2);
int length1 = nums1.length, length2 = nums2.length;
int index1 = 0, index2 = 0;
while (index1 < length1 && index2 < length2) {
if (index1 > 0) {
while (index1 < length1 && nums1[index1] == nums1[index1 - 1]) {
index1++;
}
}
if (index2 > 0) {
while (index2 < length2 && nums2[index2] == nums2[index2 - 1]) {
index2++;
}
}
if (index1 < length1 && index2 < length2) {
if (nums1[index1] == nums2[index2]) {
intersectionList.add(nums1[index1]);
index1++;
index2++;
} else if (nums1[index1] < nums2[index2]) {
index1++;
} else {
index2++;
}
}
}
int size = intersectionList.size();
int[] intersectionArr = new int[size];
for (int i = 0; i < size; i++) {
intersectionArr[i] = intersectionList.get(i);
}
return intersectionArr;
}
}
复杂度分析
-
时间复杂度: O ( m log m + n log n ) O(m \log m + n \log n) O(mlogm+nlogn),其中 m m m 和 n n n 分别是数组 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2 的长度。对两个数组排序分别需要 O ( m log m ) O(m \log m) O(mlogm) 和 O ( n log n ) O(n \log n) O(nlogn) 的时间,使用双指针遍历两个数组计算交集需要 O ( m + n ) O(m + n) O(m+n) 的时间,将交集元素填入结果数组需要 O ( min ( m , n ) ) O(\min(m, n)) O(min(m,n)) 的时间,因此时间复杂度是 O ( m log m + n log n + m + n + min ( m , n ) ) = O ( m log m + n log n ) O(m \log m + n \log n + m + n + \min(m, n)) = O(m \log m + n \log n) O(mlogm+nlogn+m+n+min(m,n))=O(mlogm+nlogn)。
-
空间复杂度: O ( log m + log n + min ( m , n ) ) O(\log m + \log n + \min(m, n)) O(logm+logn+min(m,n)),其中 m m m 和 n n n 分别是数组 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2 的长度。空间复杂度主要取决于排序的递归调用栈空间以及存储交集元素的临时数组。