1. 题目描述
2. 解题思路
交集,意味着要对两个数组具有 “全局观”,“全局观”在程序中的一种体现方法就是统计,因此我可以利用哈希表,分别统计两个数组中每个元素的出现次数,然后取小值构建新的数组。
由于在之前的做题中发现哈希表其实对时间性能的影响较大,在某些情况下使用数组进行代替可以大大提高运行速度,在本题目数组中的元素范围是0到1000,因此我可以构建一个1001长度的数组,用于统计对应下标元素的出现次数。
虽然使用数组代替哈希表的方法确实是可以提高效率的,但数据看起来还是不够优。有方法可以让我只统计一个数组的元素出现个数吗?其实是可以的,我们可以统计长度最短的数组,然后遍历另一数组,在动态更新元素出现个数统计的哈希表的同时构建返回数组。
既然数组代替哈希表这个想法是行得通的,那么我们再把上面的思想使用数组进行实现,就可以得到时间更优的解法。
3. 代码实现
3.1 哈希表 统计
public int[] intersect(int[] nums1, int[] nums2) {
ArrayList<Integer> list = new ArrayList<>();
Hashtable<Integer, Integer> count1 = count(nums1);
Hashtable<Integer, Integer> count2 = count(nums2);
Set<Integer> keySet = count1.keySet();
for (Integer integer : keySet) {
if(count2.containsKey(integer)){
int value = count1.get(integer)<count2.get(integer)?count1.get(integer):count2.get(integer);
for (int i = 0; i < value; i++) {
list.add(integer);
}
}
}
return list.stream().mapToInt(Integer::valueOf).toArray();
}
public Hashtable<Integer, Integer> count(int[] nums){
Hashtable<Integer, Integer> hashtable = new Hashtable<>();
for (int num : nums) {
if(hashtable.putIfAbsent(num,1)!=null) {
hashtable.put(num, hashtable.putIfAbsent(num, 1) + 1);
}
}
return hashtable;
}
3.2 数组 统计
public int[] intersect(int[] nums1, int[] nums2) {
ArrayList<Integer> list = new ArrayList<>();
int[] count1 = count(nums1);
int[] count2 = count(nums2);
for (int i = 0; i < count1.length; i++) {
for (int j = 0; j < Math.min(count1[i], count2[i]); j++) {
list.add(i);
}
}
return list.stream().mapToInt(Integer::valueOf).toArray();
}
public int[] count(int[] nums) {
int[] c = new int[1001];
for (int num : nums)
c[num] = c[num] + 1;
return c;
}
3.3 哈希表 统计 改进
public int[] intersect(int[] nums1, int[] nums2) {
if (nums2.length < nums1.length)
return intersect(nums2, nums1);
HashMap<Integer, Integer> map = new HashMap<>();
for (int i : nums1) {
map.put(i, map.getOrDefault(i, 0) + 1);
}
int[] ans = new int[nums1.length];
int index = 0;
for (int i : nums2) {
if (map.containsKey(i)) {
ans[index++] = i;
if (map.get(i) == 1)
map.remove(i);
else
map.put(i, map.get(i) - 1);
}
}
return Arrays.copyOfRange(ans, 0, index);
}
3.4 数组 统计 改进
public int[] intersect(int[] nums1, int[] nums2) {
if (nums2.length < nums1.length)
return intersect(nums2, nums1);
int[] count = new int[1001];
for (int i : nums1) {
count[i]++;
}
int[] ans = new int[nums1.length];
int index = 0;
for (int i : nums2) {
if (count[i] > 0) {
ans[index++] = i;
count[i]--;
}
}
return Arrays.copyOfRange(ans, 0, index);
}
虽然空间性能表现一般,但这是时间性能表现最优的解法。
3.5 对比
在第一和第二种方法中看似使用了嵌套循环,但实际上该嵌套循环的目的是用于构建返回数组,其时间复杂度是线性的,因此四种方法的时间复杂度都是O(n)。对于空间复杂度而言,哈希表的方法是O(n),而数组的方法是O(1),但其实对于实际空间而言,哈希表占用的空间会更小,因为n必定的小于等于常数1001的。