两个数组中的交集
1.问题描述
-
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]说明:
- 输出结果中的每个元素一定是唯一的。
- 我们可以不考虑输出结果的顺序。
2.求解
哈希表法
- 将一个数组存储到哈希表中,遍历另一个数组找出交集
- 注意题目中要求输出的不能有重复元素,于是使用set集合存储交集,最后转化成int数组返回
代码如下
/*
* 执行用时:3 ms, 在所有 Java 提交中击败了95.82% 的用户
* 内存消耗:38.9 MB, 在所有 Java 提交中击败了71.86% 的用户
* */
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> set = new HashSet<>();
if(nums1 == null || nums2 == null || nums1.length == 0 || nums2.length == 0){
return null;
}
Map<Integer,Integer> map = new HashMap<>();
for(int x : nums1){
map.put(x,x);
}
for(int x : nums2){
if(map.containsKey(x)){
set.add(x);
}
}
int[] ans = new int[set.size()];
int i = 0;
for(int x : set){
ans[i] = x;
i++;
}
return ans;
}
- 时间复杂度、空间复杂度均为O(m+n)
ps:java8中引入了流的操作,因此我们可以简化最后的返回结果,直接将set使用stream转化成int数组
return set.stream().mapToInt(i -> i).toArray();
其中stream()方法是将结构转化为流
mapToInt()方法是将特定函数应用此流然后返回IntStream,最后我们再对IntStream进行toArray操作当然就得到一个int数组了
-
流的高级操作
public int[] intersection(int[] nums1, int[] nums2) { Set<Integer> set = Arrays.stream(nums1).boxed().collect(Collectors.toSet()); return Arrays.stream(nums2).distinct().filter(set::contains).toArray(); }- 第一行将nums1转换成了流,然后进行装箱操作(转换为对象),最后再用collect收集为Set
- 第二行将nums2转换成了流,然后进行去重,增加了一个过滤方法要求必须是set的contains方法返回true的元素,最后再转换成数组
排序+双指针
- 先对两个数组进行排序,然后在用两个指针进行比较,找寻相同元素
/*
* 执行用时:5 ms, 在所有 Java 提交中击败了28.20% 的用户
* 内存消耗:38.6 MB, 在所有 Java 提交中击败了87.56% 的用户
* */
public int[] intersection(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
List<Integer> list = new ArrayList<>();
int i = 0, j = 0;
int index = 0;
while (i < nums1.length && j < nums2.length) {
if (nums1[i] == nums2[j]) {
if (index == 0 || nums1[i] != list.get(index - 1)) {
list.add(nums1[i]);
index++;
}
i++;
j++;
} else if (nums1[i] < nums2[j]) {
i++;
} else {
j++;
}
}
return list.stream().mapToInt(Integer::valueOf).toArray();
}
- 这里傻了,用了list,转换造成性能开销,直接用一个大小为两个数组之和的数组最后切割下可能更好
又用int数组试了一下
/*
* 执行用时:1 ms, 在所有 Java 提交中击败了99.97% 的用户
* 内存消耗:38.9 MB, 在所有 Java 提交中击败了68.68% 的用户
* */
public int[] intersection(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
int i = 0, j = 0;
int index = 0;
int[] ans = new int[nums1.length + nums2.length];
while (i < nums1.length && j < nums2.length) {
if (nums1[i] == nums2[j]) {
if (index == 0 || nums1[i] != ans[index - 1]) {
ans[index] = nums1[i];
index++;
}
i++;
j++;
} else if (nums1[i] < nums2[j]) {
i++;
} else {
j++;
}
}
return Arrays.copyOfRange(ans, 0, index);
}
果然速度快了相当多,这里注意下无法对int型数组进行切割,但是可以使用Arrays.copyofRange()方法复制一个新数组
排序+二分搜索
/*
* 执行用时:2 ms, 在所有 Java 提交中击败了99.48% 的用户
* 内存消耗:38.6 MB, 在所有 Java 提交中击败了90.99% 的用户
* */
public int[] intersection(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
int[] ans = new int[nums1.length + nums2.length];
int index = 0;
for (int x : nums2) {
if (binarySearch(nums1, x)) {
if (index == 0 || x != ans[index - 1]) {
ans[index] = x;
index++;
}
}
}
return Arrays.copyOfRange(ans, 0, index);
}
boolean binarySearch(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return true;
}
if (nums[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return false;
}
- 二分搜索可以只对一个数组排序,然后遍历另一个数组,进行搜索,但是需要使用set去重,于是这里我直接对两个数组都进行了排序

来试一试java8新特性-流
浙公网安备 33010602011771号