leecode哈希表更新
This commit is contained in:
parent
84ad855669
commit
0eb1de8bcf
|
|
@ -0,0 +1,180 @@
|
|||
package com.markilue.leecode.hashtable;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @BelongsProject: Leecode
|
||||
* @BelongsPackage: com.markilue.leecode.hashtable
|
||||
* @Author: dingjiawen
|
||||
* @CreateTime: 2022-09-08 12:24
|
||||
* @Description: TODO 力扣18题:四数之和
|
||||
* 给你一个由 n 个整数组成的数组nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组[nums[a], nums[b], nums[c], nums[d]](若两个四元组元素一一对应,则认为两个四元组重复):
|
||||
* 1)0 <= a, b, c, d< n
|
||||
* 2)a、b、c 和 d 互不相同
|
||||
* 3)nums[a] + nums[b] + nums[c] + nums[d] == target
|
||||
* 你可以按 任意顺序 返回答案 。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class FourSum {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {2, 2, 2, 2, 2};
|
||||
int target = 8;
|
||||
System.out.println(fourSum1(nums, target));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
int[] nums = {1,0,-1,0,-2,2};
|
||||
int target = 0;
|
||||
System.out.println(fourSum1(nums, target));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
int[] nums = {-1,0,1,2,-1,-4};
|
||||
int target = -1;
|
||||
System.out.println(fourSum1(nums, target));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3() {
|
||||
int[] nums = {1,-2,-5,-4,-3,3,3,5};
|
||||
int target = -11;
|
||||
System.out.println(fourSum1(nums, target));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test4() {
|
||||
int[] nums = {1000000000,1000000000,1000000000,1000000000};
|
||||
int target = -294967296;
|
||||
System.out.println(1000000000+1000000000);
|
||||
System.out.println(-294967296-(1000000000+1000000000));
|
||||
System.out.println(fourSum1(nums, target));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 本人思路:这里如果还想使用双指针法,时间复杂度会是O(n^3),考虑还是使用hash法
|
||||
* 维护一个hash表<两数之和,list<两数>> 如何避免两数重复? 先排序在加入,但是有出现了问题:虽然不重复,但是会存在覆盖问题
|
||||
* 如下面的实现所示
|
||||
*
|
||||
* @param nums
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public List<List<Integer>> fourSum(int[] nums, int target) {
|
||||
if (nums.length < 4) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Arrays.sort(nums);
|
||||
HashMap<Integer, List<Integer>> map = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
if (i > 0 && nums[i] == nums[i - 1]) {
|
||||
continue;
|
||||
}
|
||||
for (int j = i + 1; j < nums.length; j++) {
|
||||
if (j > i + 1 && nums[j] == nums[j - 1]) {
|
||||
continue;
|
||||
}
|
||||
map.put(nums[i] + nums[j], new ArrayList<>(Arrays.asList(nums[i], nums[j])));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
List<List<Integer>> lists = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
if (i > 0 && nums[i] == nums[i - 1]) {
|
||||
continue;
|
||||
}
|
||||
for (int j = i + 1; j < nums.length; j++) {
|
||||
if (j > i + 1 && nums[j] == nums[j - 1]) {
|
||||
continue;
|
||||
}
|
||||
if (map.containsKey(target - nums[i] - nums[j])) {
|
||||
map.get(target - nums[i] - nums[j]).add(nums[i]);
|
||||
map.get(target - nums[i] - nums[j]).add(nums[j]);
|
||||
lists.add(map.get(target - nums[i] - nums[j]));
|
||||
map.get(target - nums[i] - nums[j]).remove(3);
|
||||
map.get(target - nums[i] - nums[j]).remove(4);
|
||||
}
|
||||
map.put(nums[i] + nums[j], new ArrayList<>(Arrays.asList(nums[i], nums[j])));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Collection<List<Integer>> values = map.values();
|
||||
for (List<Integer> value : values) {
|
||||
lists.add(value);
|
||||
}
|
||||
|
||||
|
||||
return lists;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码思想录思路:还是使用双指针法,在外面在套一层循环,将四数问题转化为3数问题
|
||||
* 如下所示
|
||||
* 速度超过49.9%,内存超过93.76%
|
||||
* @param nums
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public List<List<Integer>> fourSum1(int[] nums, int target) {
|
||||
if (nums.length < 4) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Arrays.sort(nums);
|
||||
|
||||
List<List<Integer>> lists = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
|
||||
if (i > 0 && nums[i] == nums[i - 1]) {
|
||||
continue;
|
||||
}
|
||||
for (int j = i + 1; j < nums.length; j++) {
|
||||
|
||||
if (j > i + 1 && nums[j] == nums[j - 1]) {
|
||||
continue;
|
||||
}
|
||||
int mid = j + 1;
|
||||
int right = nums.length - 1;
|
||||
|
||||
while (mid < right) {
|
||||
//解决int超过限制的问题
|
||||
long sum = (long) nums[i] + nums[j] + nums[mid] + nums[right];
|
||||
if (sum < target) {
|
||||
mid++;
|
||||
} else if (sum > target) {
|
||||
right--;
|
||||
} else {
|
||||
lists.add(new ArrayList<>(Arrays.asList(nums[i], nums[j], nums[mid], nums[right])));
|
||||
while (mid < right && nums[mid] == nums[mid + 1]) {
|
||||
mid++;
|
||||
}
|
||||
while (mid < right && nums[right] == nums[right - 1]) {
|
||||
right--;
|
||||
}
|
||||
mid++;
|
||||
right--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return lists;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
package com.markilue.leecode.hashtable;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* @BelongsProject: Leecode
|
||||
* @BelongsPackage: com.markilue.leecode.hashtable
|
||||
* @Author: dingjiawen
|
||||
* @CreateTime: 2022-09-08 09:09
|
||||
* @Description:
|
||||
* TODO leecode454题:四数相加II:
|
||||
* 给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:
|
||||
* 1) 0 <= i, j, k, l < n
|
||||
* 2) nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class FourSumCount {
|
||||
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
|
||||
int[] nums1 = {1, 2};
|
||||
int[] nums2 = {-2, -1};
|
||||
int[] nums3 = {-1, 2};
|
||||
int[] nums4 = {0, 2};
|
||||
System.out.println(fourSumCount1(nums1, nums2, nums3, nums4));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2(){
|
||||
|
||||
int[] nums1 = {1, 2};
|
||||
int[] nums2 = {-2, -1};
|
||||
int[] nums3 = {0, 2};
|
||||
int[] nums4 = {0, 2};
|
||||
System.out.println(fourSumCount1(nums1, nums2, nums3, nums4));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1(){
|
||||
|
||||
int[] nums1 = {0};
|
||||
int[] nums2 = {0};
|
||||
int[] nums3 = {0};
|
||||
int[] nums4 = {0};
|
||||
System.out.println(fourSumCount1(nums1, nums2, nums3, nums4));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 自己的思路:
|
||||
* 1)使用递归来解决,把四数相加转换为三数相加转为两数相加,这种方式时间复杂度直接O(n^4)
|
||||
* 2)构建两个hash表,分别遍历两个数组,时间复杂度O(n^2)
|
||||
* 以下是第二种思路,hashset暂时还有问题没有解决,如test2的问题
|
||||
* @param nums1
|
||||
* @param nums2
|
||||
* @param nums3
|
||||
* @param nums4
|
||||
* @return
|
||||
*/
|
||||
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
|
||||
|
||||
|
||||
//构建一个hash表,
|
||||
HashSet<Integer> set1 = new HashSet<>();
|
||||
|
||||
for (int i = 0; i < nums1.length; i++) {
|
||||
for (int j = 0; j < nums2.length; j++) {
|
||||
set1.add(nums1[i]+nums2[j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HashSet<Integer> set2 = new HashSet<>();
|
||||
|
||||
for (int i = 0; i < nums3.length; i++) {
|
||||
for (int j = 0; j < nums4.length; j++) {
|
||||
set2.add(nums3[i]+nums4[j]);
|
||||
}
|
||||
}
|
||||
|
||||
int count=0;
|
||||
for (Integer integer : set1) {
|
||||
if(set2.contains(0-integer)){
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码思想录的思路:
|
||||
* 2)构建两个hash表<两数之和,这两数之和出现的次数>,分别遍历两个数组,时间复杂度O(n^2)
|
||||
* 速度击败20.33%,内存击败13.78%
|
||||
* @param nums1
|
||||
* @param nums2
|
||||
* @param nums3
|
||||
* @param nums4
|
||||
* @return
|
||||
*/
|
||||
public int fourSumCount1(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
|
||||
|
||||
//构建一个hash表<两数之和,这两数之和出现的次数>
|
||||
HashMap<Integer, Integer> map1 = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < nums1.length; i++) {
|
||||
for (int j = 0; j < nums2.length; j++) {
|
||||
map1.put(nums1[i]+nums2[j],map1.getOrDefault(nums1[i]+nums2[j],0)+1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HashMap<Integer, Integer> map2 = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < nums3.length; i++) {
|
||||
for (int j = 0; j < nums4.length; j++) {
|
||||
map2.put(nums3[i]+nums4[j],map2.getOrDefault(nums3[i]+nums4[j],0)+1);
|
||||
}
|
||||
}
|
||||
|
||||
int count=0;
|
||||
for (Integer integer : map1.keySet()) {
|
||||
if(map2.containsKey(0-integer)){
|
||||
count+=map1.get(integer)*map2.get(0-integer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 官方的思路:
|
||||
* 2)构建一个hash表<两数之和,这两数之和出现的次数>,分别遍历两个数组,时间复杂度O(n^2)
|
||||
* 速度击败28.59%,内存击败91.98% 时间空间复杂度均为O(n^2)
|
||||
* @param nums1
|
||||
* @param nums2
|
||||
* @param nums3
|
||||
* @param nums4
|
||||
* @return
|
||||
*/
|
||||
public int fourSumCount2(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
|
||||
|
||||
//构建一个hash表<两数之和,这两数之和出现的次数>
|
||||
HashMap<Integer, Integer> map1 = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < nums1.length; i++) {
|
||||
for (int j = 0; j < nums2.length; j++) {
|
||||
map1.put(nums1[i]+nums2[j],map1.getOrDefault(nums1[i]+nums2[j],0)+1);
|
||||
}
|
||||
}
|
||||
|
||||
int count=0;
|
||||
|
||||
for (int i = 0; i < nums3.length; i++) {
|
||||
for (int j = 0; j < nums4.length; j++) {
|
||||
if(map1.containsKey(0-nums3[i]-nums4[j])){
|
||||
count+=map1.get(0-nums3[i]-nums4[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package com.markilue.leecode.hashtable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @BelongsProject: Leecode
|
||||
* @BelongsPackage: com.markilue.leecode.hashtable
|
||||
* @Author: dingjiawen
|
||||
* @CreateTime: 2022-09-08 10:49
|
||||
* @Description:
|
||||
* TODO 力扣15题:三数之和:
|
||||
* 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
|
||||
* 你返回所有和为 0 且不重复的三元组。
|
||||
* 注意:答案中不可以包含重复的三元组。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class ThreeSum {
|
||||
|
||||
/**
|
||||
* 这道题使用哈希法的思路:
|
||||
* 使用两层循环,先计算出a+b,最后再遍历一遍找到-a-b的值,最后再进行去重,整体时间复杂度是O(n^2),但是仍然是比较费时的操作,因为去重比较麻烦
|
||||
* 这里可以使用双指针法:先对数组进行整体的排序,作为一个有序的数组,使用头尾指针,寻找中间的数据,时间复杂度O(n^2)
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public List<List<Integer>> threeSum(int[] nums) {
|
||||
|
||||
if(nums.length<3){
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
Arrays.sort(nums);
|
||||
|
||||
List<List<Integer>> lists = new ArrayList<>();
|
||||
|
||||
|
||||
for (int left = 0; left < nums.length - 2; left++) {
|
||||
|
||||
if(nums[left]>0){
|
||||
break;
|
||||
}
|
||||
//避免重复
|
||||
if(left>0&&nums[left]==nums[left-1]){
|
||||
continue;
|
||||
}
|
||||
|
||||
//定义尾指针
|
||||
int right= nums.length-1;
|
||||
//定义中间指针
|
||||
int mid =left+1;
|
||||
while (mid<right){
|
||||
int sum=nums[left]+nums[mid]+nums[right];
|
||||
if(sum>0){
|
||||
right--;
|
||||
}else if(sum<0){
|
||||
mid++;
|
||||
}else {
|
||||
//sum==0
|
||||
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(nums[left],nums[mid],nums[right]));
|
||||
//判断一下左右避免重复
|
||||
while (mid<right&&nums[mid+1]==nums[mid]) {
|
||||
mid++;
|
||||
}
|
||||
while (mid<right&&nums[right-1]==nums[right]) {
|
||||
right--;
|
||||
}
|
||||
mid++;
|
||||
right--;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return lists;
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue