LeetCode題解——四數之和
LeetCode題解——四數之和
我的LeetCode程式碼集:https://github.com/cnamep001/LeetCode
原題連結:https://leetcode-cn.com/problems/4sum/description/
思路一:用Set集合來過濾重複元素
用一個雜湊表儲存陣列中兩個數的和,以及形成這個和可能的索引組合的List。雖然我們的Set集合能夠自動幫我們過濾掉重複的List,但是過濾的前提是我們得到的List必須是有序的。比如(0, 1, -1, 0)和(0, 0, -1, 1)這一組資料,對於Set集合來說是不重複的,而(-1, 0, 0, 1)和(-1, 0, 0, 1)這組資料,對於Set集合來說才是重複的
在形成雜湊表的時候,我們能夠保證第一個索引小於第二個索引,但是當我們在雜湊表中尋找target - key的時候,如何保證兩個索引陣列形成的List是有序的呢?我們只需要讓第一個陣列的較大索引小於第二個陣列的較小索引即可。
這個思路的時間複雜度分析挺複雜的。首先,排序過程的時間複雜度一定是O(nlogn),其中n為nums陣列的長度。而形成雜湊表的時間複雜度是O(n ^ 2)級別的。而遍歷雜湊表形成結果的過程的時間複雜度不好算,這和每兩個數的和對應的List的大小有關。而空間複雜度還是很明瞭的,我們儲存了一個雜湊表,而雜湊表的鍵存的是兩個數的和,這兩個數的組合可能產生的和是O(n ^ 2)級別的,因此空間複雜度是O(n ^ 2)級別的。
實現程式碼:
package com.m.four_sum.solution1; import java.util.*; public class Solution1 { public List<List<Integer>> fourSum(int[] nums, int target) { Set<List<Integer>> listSet = new HashSet<>(); int n = nums.length; Arrays.sort(nums); HashMap<Integer, List<Integer[]>> hashMap = new HashMap<>(); for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { int num = nums[i] + nums[j]; Integer[] pair = {i, j}; if (hashMap.containsKey(num)) { hashMap.get(num).add(pair); } else { List<Integer[]> list = new ArrayList<>(); list.add(pair); hashMap.put(num, list); } } } for (Integer integer : hashMap.keySet()) { if (hashMap.containsKey(target - integer)) { List<Integer[]> list1 = hashMap.get(integer); List<Integer[]> list2 = hashMap.get(target - integer); for (Integer[] pair1 : list1) { int index1 = pair1[0]; int index2 = pair1[1]; for (Integer[] pair2 : list2) { int index3 = pair2[0]; int index4 = pair2[1]; if (index2 < index3) { List<Integer> list = new ArrayList<>(); list.add(nums[index1]); list.add(nums[index2]); list.add(nums[index3]); list.add(nums[index4]); listSet.add(list); } } } } } return new ArrayList<>(listSet); } }
LeetCode解題報告:
思路二:用雜湊表HashMap
我們用一個雜湊表來儲存陣列中出現的所有元素及其出現的次數。
我們總共分五種情況:
(1)四個數都相同。
(2)三個數相同。
(3)兩個數相同,另外兩個數也相同。
(4)兩個數相同,另外兩個數不相同。
(5)四個數都不相同
實現程式碼:
package com.m.four_sum.solution2;
import java.util.*;
public class Solution2 {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> listList = new ArrayList<>();
int n = nums.length;
HashMap<Integer, Integer> hashMap = new HashMap<>();
for (int i = 0; i < n; i++) {
if (hashMap.containsKey(nums[i])) {
hashMap.put(nums[i], hashMap.get(nums[i]) + 1);
} else {
hashMap.put(nums[i], 1);
}
}
if (target % 4 == 0 &&
hashMap.containsKey(target / 4) &&
hashMap.get(target / 4) >= 4) {
addToListList(target / 4, target / 4,
target / 4, target / 4, listList);
}
ArrayList<Integer> arrayList = new ArrayList<>();
for (Integer integer : hashMap.keySet()) {
arrayList.add(integer);
}
Collections.sort(arrayList);
for (int i = 0; i < arrayList.size(); i++) {
for (int j = i + 1; j < arrayList.size(); j++) {
if (arrayList.get(i) * 3 + arrayList.get(j) ==
target && hashMap.get(arrayList.get(i)) >= 3) {
addToListList(arrayList.get(i), arrayList.get(i),
arrayList.get(i), arrayList.get(j), listList);
}
if (arrayList.get(i) + arrayList.get(j) * 3 == target &&
hashMap.get(arrayList.get(j)) >= 3) {
addToListList(arrayList.get(i), arrayList.get(j), arrayList.get(j),
arrayList.get(j), listList);
}
}
}
for (int i = 0; i < arrayList.size(); i++) {
for (int j = i + 1; j < arrayList.size(); j++) {
if (arrayList.get(i) * 2 + arrayList.get(j) * 2 == target &&
hashMap.get(arrayList.get(i)) >= 2 && hashMap.get(arrayList.get(j)) >= 2) {
addToListList(arrayList.get(i), arrayList.get(i),
arrayList.get(j), arrayList.get(j), listList);
}
}
}
for (int i = 0; i < arrayList.size(); i++) {
for (int j = i + 1; j < arrayList.size(); j++) {
for (int k = j + 1; k < arrayList.size(); k++) {
if (arrayList.get(i) * 2 + arrayList.get(j) + arrayList.get(k) == target &&
hashMap.get(arrayList.get(i)) >= 2) {
addToListList(arrayList.get(i), arrayList.get(i),
arrayList.get(j), arrayList.get(k), listList);
}
if (arrayList.get(i) + arrayList.get(j) * 2 + arrayList.get(k) ==
target && hashMap.get(arrayList.get(j)) >= 2) {
addToListList(arrayList.get(i), arrayList.get(j),
arrayList.get(j), arrayList.get(k), listList);
}
if (arrayList.get(i) + arrayList.get(j) + arrayList.get(k) * 2 ==
target && hashMap.get(arrayList.get(k)) >= 2) {
addToListList(arrayList.get(i), arrayList.get(j),
arrayList.get(k), arrayList.get(k), listList);
}
int num = target - arrayList.get(i) - arrayList.get(j) - arrayList.get(k);
if (num > arrayList.get(k) && hashMap.containsKey(num)) {
addToListList(arrayList.get(i), arrayList.get(j),
arrayList.get(k), num, listList);
}
}
}
}
return listList;
}
private void addToListList(int num1, int num2, int num3,
int num4, List<List<Integer>> listList) {
List<Integer> list = new ArrayList<>();
list.add(num1);
list.add(num2);
list.add(num3);
list.add(num4);
listList.add(list);
}
}
LeetCode解題報告:
思路三:迴圈
先排序,再四重迴圈遍歷求解。迴圈次數實在是有點多,我都不知道怎麼給迴圈變數命名了,好在LeetCode中並沒有超時,還是獲得了通過。
時間複雜度為O(n ^ 4),其中n為nums陣列的長度。空間複雜度為O(1)。
實現程式碼:
package com.m.four_sum.solution3;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Solution3 {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> listList = new ArrayList<>();
int n = nums.length;
Arrays.sort(nums);
for (int i = 0; i < n; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
for (int j = i + 1; j < n; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
for (int k = j + 1; k < n; k++) {
if (k > j + 1 && nums[k] == nums[k - 1]) {
continue;
}
for (int m = k + 1; m < n; m++) {
if (m > k + 1 && nums[m] == nums[m - 1]) {
continue;
}
if (nums[i] + nums[j] + nums[k] + nums[m] == target) {
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[k]);
list.add(nums[m]);
listList.add(list);
}
}
}
}
}
return listList;
}
}
LeetCode解題報告: