问题
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入: nums1 = \([1,2,2,1]\), nums2 = \([2,2]\)
输出: \([2,2]\)
示例 2:
输入: nums1 = \([4,9,5]\), nums2 = \([9,4,9,8,4]\)
输出: [4,9]
说明:
- 输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。
- 我们可以不考虑输出结果的顺序。
进阶:
- 如果给定的数组已经排好序呢?你将如何优化你的算法?
- 如果 nums1 的大小比 nums2 小很多,哪种方法更优?
- 如果 nums2 的元素存储在磁盘上,磁盘内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?
解法
问题比较简单。可以遍历两个数组,获得数字出现的频次,然后对比两个频次即可。或者可以直接排序两个数组,然后使用两个指针分别遍历数组即可。
解法
频次法
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
if(nums1.length > nums2.length) {
return intersect(nums2, nums1);
}
//这里使用hashmap,因为数字是不定长的。
Map<Integer, Integer> map1 = new HashMap<>(nums1.length);
for (Integer i: nums1) {
Integer count = map1.get(i);
if (count == null) {
map1.put(i, 1);
} else {
map1.put(i, count+1);
}
}
Map<Integer, Integer> map2 = new HashMap<>(nums2.length);
for (Integer i: nums2) {
Integer count = map2.get(i);
if (count == null) {
map2.put(i, 1);
} else {
map2.put(i, count+1);
}
}
Iterator iter = map1.entrySet().iterator();
List<Integer> result = new LinkedList();
//遍历两个频次map即可,这里使用小的那个map遍历。可以减少查询次数
while(iter.hasNext()) {
Map.Entry<Integer, Integer> entry = (Map.Entry) iter.next();
Integer key = entry.getKey();
Integer val1 = entry.getValue();
Integer val2 = map2.get(key);
if(val2 != null) {
int count = Math.min(val1, val2);
while (count-- > 0) {
result.add(key);
}
}
}
//最终生成结果,因为没有用从List到int[]的方便转换方法。
int[] res = new int[result.size()];
for(int m=0;m<res.length;m++)
{
res[m]=result.get(m);
}
return res;
}
}
排序遍历法
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
if(nums1.length > nums2.length) {
return intersect(nums2, nums1);
}
List<Integer> result = new LinkedList();
//排序两个数组
Arrays.sort(nums1);
Arrays.sort(nums2);
//遍历两个数组
for (int i = 0,j=0; i<nums1.length && j<nums2.length;) {
//相等则加入result
if (nums1[i] == nums2[j]) {
result.add(nums1[i]);
i++;
j++;
} else if (nums1[i] < nums2[j]){
// 这里注意只有其中一个往前推进。
i++;
} else {
j++;
}
}
int[] res = new int[result.size()];
for(int m=0;m<res.length;m++)
{
res[m]=result.get(m);
}
return res;
}
}