給定兩個數組,編寫函數計算它們的交集。
示例:nums1 = [1,2,2,1], nums2 = [2,2] → 返回 [2]
要求:結果元素唯一,順序不限。
public int[] intersection(int[] nums1, int[] nums2) {
ArrayList list = new ArrayList<>();
for (int i = 0; i < nums1.length; i++) {
for (int j = 0; j < nums2.length; j++) {
if (nums1[i] == nums2[j] && !list.contains(nums1[i])) {
list.add(nums1[i]);
}
}
}
int[] result = new int[list.size()];
for (int i = 0; i < list.size(); i++) result[i] = list.get(i);
return result;
}
複雜度:時間 O(m×n),空間 O(min(m,n))。缺點:list.contains 為 O(k),總體接近 O(m×n×k),大數據極慢。
public int[] intersection(int[] nums1, int[] nums2) {
Set set1 = new HashSet<>();
for (int n : nums1) set1.add(n);
Set resultSet = new HashSet<>();
for (int n : nums2) {
if (set1.contains(n)) resultSet.add(n);
}
int[] result = new int[resultSet.size()];
int i = 0;
for (int n : resultSet) result[i++] = n;
return result;
}
複雜度:時間 O(m+n),空間 O(m+n)。優勢:HashSet 查找/插入 O(1),自動去重,代碼簡潔。
public int[] intersection(int[] nums1, int[] nums2) {
Set set1 = Arrays.stream(nums1).boxed().collect(Collectors.toSet());
return Arrays.stream(nums2)
.filter(set1::contains)
.distinct()
.mapToInt(Integer::intValue)
.toArray();
}
特點:函數式風格,可讀性強,性能與解法二相當 (常數因子稍大)。
public int[] intersection(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
List list = new ArrayList<>();
int i = 0, j = 0;
while (i < nums1.length && j < nums2.length) {
if (nums1[i] < nums2[j]) i++;
else if (nums1[i] > nums2[j]) j++;
else {
if (list.isEmpty() || list.get(list.size()-1) != nums1[i]) {
list.add(nums1[i]);
}
i++; j++;
}
}
return list.stream().mapToInt(Integer::intValue).toArray();
}
複雜度:時間 O(m log m + n log n),空間 O(1) (不計結果)。適用:內存受限、數據已排序、或需輸出有序交集。
public int[] intersection(int[] nums1, int[] nums2) {
// 假設數值範圍 0-1000
boolean[] seen = new boolean[1001];
for (int n : nums1) seen[n] = true;
List list = new ArrayList<>();
for (int n : nums2) {
if (seen[n]) {
list.add(n);
seen[n] = false; // 防止重複添加
}
}
return list.stream().mapToInt(Integer::intValue).toArray();
}
複雜度:時間 O(m+n),空間 O(Range)。極快但受數值範圍限制。
| 解法 | 時間複雜度 | 空間複雜度 | 適用場景 | 推薦指數 |
|---|---|---|---|---|
| 雙重循環 | O(m×n×k) | O(k) | 教學/極小數據 | ⭐ |
| HashSet (標準) | O(m+n) | O(m+n) | 通用首選 | ⭐⭐⭐⭐⭐ |
| Java 8 Stream | O(m+n) | O(m+n) | 代碼簡潔/函數式風格 | ⭐⭐⭐⭐ |
| 排序雙指針 | O(m log m + n log n) | O(1) | 內存受限/已排序 | ⭐⭐⭐ |
| 位圖/數組 | O(m+n) | O(Range) | 數值範圍小且已知 | ⭐⭐⭐⭐ (特定場景) |
「首先用 HashSet 存儲較小數組元素實現 O(1) 查找與去重,遍歷另一數組檢查交集收集到結果 Set,最後轉數組返回。時間 O(m+n),空間 O(m+n)。若內存極受限可排序雙指針 O(1) 空間;若數值範圍小用位圖極快。Java 8 Stream 可一行實現展示函數式思維。」