1.知识点
hashMap,相向双指针
2.刷题
454.四数相加II
LeetCode链接 454. 四数相加 II - 力扣(LeetCode)
题目描述
方法1:HashMap
将4个数组分为2组
package daimasuixiangshuati.day07_haxibiao;
import java.util.HashMap;
/**
* @Author LeiGe
* @Date 2023/10/14
* @Description todo
*/
public class SiShuXiangJiaII454_2 {
/**
* 方法1-hashmap
* 0.将4个数组分为2部分,nums1和nums2是一组,nums3和nums4是一组
* 1.通过两层遍历计算第一组的元素之和,和出现的频次(hashmap,key:两个数组中的元素之和,value:出现的频次)
* 2.再通过两层遍历,计算第二组的元素之和,在map中找是否存在相加为0的情况,同时记录次数
*
* @param nums1
* @param nums2
* @param nums3
* @param nums4
* @return
*/
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
HashMap<Integer, Integer> map = new HashMap<>();
// 第1组两数的和
int sum1;
// 第2组两数的和
int sum2;
int count = 0;
//1.先统计两个数组的和以及和的总次数
for (int num1 : nums1) {
for (int num2 : nums2) {
sum1 = num1 + num2;
if (map.containsKey(sum1)) {
map.put(sum1, map.get(sum1) + 1);
} else {
map.put(sum1, 1);
}
}
}
//2.统计剩余两个数组的和,在map中找是否存在相加为0的情况,同时记录次数
for (int num3 : nums3) {
for (int num4 : nums4) {
sum2 = num3 + num4;
if (map.containsKey(-sum2)) {
count += map.get(-sum2);
}
}
}
return count;
}
}
时间复杂度:O(N^2)
空间复杂度:O(N^2)
383.赎金信
LeetCode链接 383. 赎金信 - 力扣(LeetCode)
题目描述
方法1:数组作为散列表
package daimasuixiangshuati.day07_haxibiao;
/**
* @Author LeiGe
* @Date 2023/10/14
* @Description todo
*/
public class ShuJinXin383_2 {
/**
* 方法1-散列表-数组解决
* 1.将ransomNote的元素放入数组中,下标表示每个元素,数组的值表示出现这个元素出现的次数
* 2.遍历magazine,如果出现了ransomNote的元素,就将次数减一
* 3.最后遍历数组,判断元素是不是都为0,如果不为0,则为false
*
* @param ransomNote
* @param magazine
* @return
*/
public static boolean canConstruct(String ransomNote, String magazine) {
int[] ints = new int[26];
//1.将ransomNote的元素放入数组中,下标表示每个元素,数组的值表示出现这个元素出现的次数
// 统计需要的字符以及字符的个数
for (int i = 0; i < ransomNote.length(); i++) {
int i1 = ransomNote.charAt(i) - 'a';
ints[i1] = ints[i1] + 1;
}
//2.遍历magazine,如果出现了ransomNote的元素,就将次数减一
// 统计提供个字符已经字符的个数
for (int i = 0; i < magazine.length(); i++) {
int i1 = magazine.charAt(i) - 'a';
ints[i1] = ints[i1] - 1;
}
//3.最后遍历数组,判断元素是不是都为0,如果不为0,则为false
for (int anInt : ints) {
// 如果需要的字符的个数大于提供的,则magazine不能组成ransomNote
if (anInt > 0) {
return false;
}
}
return true;
}
}
时间复杂度:O(N)
空间复杂度:O(1)
方法2:方法1优化
package daimasuixiangshuati.day07_haxibiao;
/**
* @Author LeiGe
* @Date 2023/10/14
* @Description todo
*/
public class ShuJinXin383_3 {
/**
* 方法2-数组解决-优化
* 优化点:本质上是将步骤2和步骤3合并起来,减少一遍遍历
*
* @param ransomNote
* @param magazine
* @return
*/
public static boolean canConstruct(String ransomNote, String magazine) {
int[] arr = new int[26];
int temp;
// 统计提供的字符以及字符个数
for (int i = 0; i < magazine.length(); i++) {
temp = magazine.charAt(i) - 'a';
arr[temp]++;
}
// 遍历需要组成的字符串
for (int i = 0; i < ransomNote.length(); i++) {
temp = ransomNote.charAt(i) - 'a';
//对于金信中的每一个字符都在数组中查找,找到对应的减1,否则找不到返回false
if (arr[temp] > 0) {
// 如果这个字符有提供的,则用掉一个
arr[temp]--;
} else {
// 如果这个字符没有提供,直接组合不出ransomNote
return false;
}
}
return true;
}
}
15.三数之和
LeetCode链接 15. 三数之和 - 力扣(LeetCode)
题目描述
方法1:排序+双指针
package daimasuixiangshuati.day07_haxibiao;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @Author LeiGe
* @Date 2023/10/14
* @Description todo
*/
public class SanShuZhiHe15_2 {
/**
* 方法2-排序+双指针法
* 1. i:a left:b right:c
* 2.排序之后,abc的去重可以通过移动指针处理
*
* @param nums
* @return
*/
public static List<List<Integer>> threeSum(int[] nums) {
// 记录所有的结果
List<List<Integer>> result = new ArrayList<>();
//数组升序排序
Arrays.sort(nums);
//枚举a
for (int i = 0; i < nums.length; i++) {
// a大于0,则a肯定不符合结果
if (nums[i] > 0) {
return result;
}
//a去重:如果i位置和i-1位置一样,i后移
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
if (nums[i] + nums[left] + nums[right] > 0) {
right--;
} else if (nums[i] + nums[left] + nums[right] < 0) {
left++;
} else {
// 找到一组符合要求的组合,加入到结果集中
ArrayList<Integer> temps = new ArrayList<Integer>();
temps.add(nums[i]);
temps.add(nums[left]);
temps.add(nums[right]);
result.add(temps);
//c去重:如果right位置和right-1位置一样,right往左移动
while (right > left && nums[right] == nums[right - 1]) {
right--;
}
//b去重:如果left和left+1位置一样,left往右移动
while (right > left && nums[left] == nums[left + 1]) {
left++;
}
//找到一个答案,双指针收缩,寻找下一个答案
right--;
left++;
}
}
}
return result;
}
}
时间复杂度:O(N^2)
空间复杂度:O(1)
18.四数之和
LeetCode链接 18. 四数之和 - 力扣(LeetCode)
题目描述
方法1:排序+双指针
在三数之和的解法上再套一层循环,用于枚举a
package daimasuixiangshuati.day07_haxibiao;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @Author LeiGe
* @Date 2023/10/14
* @Description todo
*/
public class SiShuZhiHe18_2 {
/**
* 方法1:排序+双指针+參考三数之和
* 三数之和的解法上再套一层循环
* 1. i:a j:b left:c right:d
*
* @param nums
* @param target
* @return
*/
public List<List<Integer>> fourSum(int[] nums, int target) {
// 存放最后结果
List<List<Integer>> result = new ArrayList<>();
//升序排序
Arrays.sort(nums);
//枚举a
for (int i = 0; i < nums.length - 3; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
//枚举b
for (int j = i + 1; j < nums.length - 2; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
int left = j + 1;
int right = nums.length - 1;
while (left < right) {
long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
if (sum > target) {
right--;
} else if (sum < target) {
left++;
} else {
ArrayList<Integer> temps = new ArrayList<>();
temps.add(nums[i]);
temps.add(nums[j]);
temps.add(nums[left]);
temps.add(nums[right]);
result.add(temps);
//d去重:如果right位置和right-1位置一样,right往左移动
while (right > left && nums[right] == nums[right - 1]) {
right--;
}
//c去重:如果left和left+1位置一样,left往右移动
while (right > left && nums[left] == nums[left + 1]) {
left++;
}
//找到一个答案,双指针收缩,寻找下一个答案
right--;
left++;
}
}
}
}
return result;
}
}
时间复杂度:O(N^3)
空间复杂度:O(1)
3.小结
1.四数相加,赎金信 用哈希解法:hashMap用于记录之前出现过的数
2.三数之和,四数之和 先排序再用相向双指针,注意去重是如何实现的