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解题报告: