给定两个数组 nums1
和 nums2
,返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2] 输出:[2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4] 输出:[9,4] 解释:[4,9] 也是可通过的
提示:
1 <= nums1.length, nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 1000
解法1:两个集合
使用哈希集合存储元素,可以在 O(1) 的时间内判断一个元素是否在集合中,从而降低时间复杂度。假设数组 nums1
和 nums2
的长度分别是 m 和 n。
首先使用两个哈希集合分别存储两个数组中的元素,然后遍历较小的集合,判断其中的每个元素是否在另一个集合中,如果元素也在另一个集合中,则将该元素添加到返回值。该方法的时间复杂度为 O(m+n)。
Java版:
int数组转set:
首先使用Arrays.stream(intArray)
将int
数组转换为IntStream
,然后使用boxed()
方法将IntStream
中的int
值装箱成Integer
对象,最后使用collect(Collectors.toSet())
收集成一个Set
。
set转int数组:
使用Java 8的stream API将Set转换为int数组。可以使用stream()方法将Set转换为流,然后使用mapToInt()方法将流中的元素转换为int类型,最后使用toArray()方法将流中的元素收集到int数组中。
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
// 确保 nums1 是长度较短的数组
if (nums1.length > nums2.length) {
intersection(nums2, nums1);
}
// int[] -> set
Set<Integer> set1 = Arrays.stream(nums1).boxed().collect(Collectors.toSet());
Set<Integer> set2 = Arrays.stream(nums2).boxed().collect(Collectors.toSet());
ArrayList<Integer> ans = new ArrayList<>();
for (Integer i : set1) {
if (set2.contains(i)) {
ans.add(i);
}
}
// ArrayList -> int[]
return ans.stream().mapToInt(Integer::intValue).toArray();
}
}
Python版:
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
if len(nums1) > len(nums2):
self.intersection(nums2, nums1)
set1 = set(nums1)
set2 = set(nums2)
return [x for x in set1 if x in set2]
复杂度分析
- 时间复杂度:O(m+n),其中 m 和 n 分别是两个数组的长度。使用两个集合分别存储两个数组中的元素需要 O(m+n) 的时间,遍历较小的集合并判断元素是否在另一个集合中需要 O(min(m,n)) 的时间,因此总时间复杂度是 O(m+n)。
- 空间复杂度:O(m+n),其中 m 和 n 分别是两个数组的长度。空间复杂度主要取决于两个集合。
解法2: 排序 + 双指针
如果两个数组是有序的,则可以使用双指针的方法得到两个数组的交集。
首先对两个数组进行排序,然后使用两个指针遍历两个数组。可以预见的是加入答案的数组的元素一定是递增的,为了保证加入元素的唯一性,我们需要额外记录变量 pre 表示上一次加入答案数组的元素。
初始时,两个指针分别指向两个数组的头部。每次比较两个指针指向的两个数组中的数字,如果两个数字不相等,则将指向较小数字的指针右移一位,如果两个数字相等,且该数字不等于 pre ,将该数字添加到答案并更新 pre 变量,同时将两个指针都右移一位。当至少有一个指针超出数组范围时,遍历结束。
Java版:
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
int m = nums1.length;
int n = nums2.length;
int l = 0;
int r = 0;
int[] ans = new int[Math.min(m, n)];
int i = 0;
while (l < m && r < n) {
while (l < m && r < n && nums1[l] == nums2[r]) {
if (i == 0 || ans[i - 1] != nums1[l]) {
ans[i++] = nums1[l];
}
l++;
r++;
}
while (l < m && r < n && nums1[l] < nums2[r]) {
l++;
}
while (l < m && r < n && nums2[r] < nums1[l]) {
r++;
}
}
return Arrays.copyOfRange(ans, 0, i);
}
}
Python版:
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
nums1.sort()
nums2.sort()
m = len(nums1)
n = len(nums2)
ans = []
l, r = 0, 0
while l < m and r < n:
while l < m and r < n and nums1[l] == nums2[r]:
if len(ans) == 0 or ans[-1] != nums1[l]:
ans.append(nums1[l])
l += 1
r += 1
while l < m and r < n and nums1[l] < nums2[r]:
l += 1
while l < m and r < n and nums2[r] < nums1[l]:
r += 1
return ans
复杂度分析
- 时间复杂度:O(mlogm+nlogn),其中 m 和 n 分别是两个数组的长度。对两个数组排序的时间复杂度分别是 O(mlogm) 和 O(nlogn),双指针寻找交集元素的时间复杂度是 O(m+n),因此总时间复杂度是 O(mlogm+nlogn)。
- 空间复杂度:O(logm+logn),其中 m 和 n 分别是两个数组的长度。空间复杂度主要取决于排序使用的额外空间。