找回密码
 立即注册
首页 业界区 安全 代码随想录第六天 | 哈希表part02

代码随想录第六天 | 哈希表part02

懵径 2025-6-1 21:20:44
454.四数相加II
建议:本题是 使用map 巧妙解决的问题,好好体会一下 哈希法 如何提高程序执行效率,降低时间复杂度,当然使用哈希法 会提高空间复杂度,但一般来说我们都是舍空间 换时间, 工业开发也是这样。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0454.四数相加II.html
题目感想:
1.由于给了我们四个数组,并且是要求四个数字相加起来等于0,那么就可以先双层for循环AB两个数组,得出可能出现得结果以及出现次数,然后去双层for循环CD两个数组,看看是否有和此刻得CD中位置的相加等于0的,有则将那个AB出现的次数统计到sum里面去;
  1. class Solution {
  2.     public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
  3.         int res = 0;
  4.         Map<Integer, Integer> map = new HashMap<Integer, Integer>();
  5.         //统计两个数组中的元素之和,同时统计出现的次数,放入map
  6.         for (int i : nums1) {
  7.             for (int j : nums2) {
  8.                 int sum = i + j;
  9.                 map.put(sum, map.getOrDefault(sum, 0) + 1);
  10.             }
  11.         }
  12.         //统计剩余的两个元素的和,在map中找是否存在相加为0的情况,同时记录次数
  13.         for (int i : nums3) {
  14.             for (int j : nums4) {
  15.                 res += map.getOrDefault(0 - i - j, 0);
  16.             }
  17.         }
  18.         return res;
  19.     }
  20. }
复制代码

  • 赎金信
    建议:本题 和 242.有效的字母异位词 是一个思路 ,算是拓展题
    题目链接/文章讲解:https://programmercarl.com/0383.赎金信.html
    题目感想:
    1.统计杂志里面的字母以及出现的次数,然后遍历赎金信挨个去数组里面进行删除,之后再遍历这个字母数组,看看是否有小于0的,有则不能组成,没有则可以组成
  1. class Solution {
  2.     public boolean canConstruct(String ransomNote, String magazine) {
  3.         // shortcut
  4.         if (ransomNote.length() > magazine.length()) {
  5.             return false;
  6.         }
  7.         // 定义一个哈希映射数组
  8.         int[] record = new int[26];
  9.         // 遍历
  10.         for(char c : magazine.toCharArray()){
  11.             record[c - 'a'] += 1;
  12.         }
  13.         for(char c : ransomNote.toCharArray()){
  14.             record[c - 'a'] -= 1;
  15.         }
  16.         // 如果数组中存在负数,说明ransomNote字符串中存在magazine中没有的字符
  17.         for(int i : record){
  18.             if(i < 0){
  19.                 return false;
  20.             }
  21.         }
  22.         return true;
  23.     }
  24. }
复制代码

  • 三数之和
    建议:本题虽然和 两数之和 很像,也能用哈希法,但用哈希法会很麻烦,双指针法才是正解,可以先看视频理解一下 双指针法的思路,文章中讲解的,没问题 哈希法很麻烦。
    题目链接/文章讲解/视频讲解:https://programmercarl.com/0015.三数之和.html
    题目感想:
    1.给了目标值然后让你去数组里面找到三个数字加起来能到达,首先我们先排序,这样便于后面去重操作,然后我们需要有三个指针,第一个指针定义第一个桩的位置,然后剩下的两个指针就和之前找两数之和一样,两个指针分布在边界两边,和目标值比较之后进行移动,直到两个指针重合或者找到目标值;
    2.这里需要注意的是三个指针不能出现重复的情况,首先我们是排好序的数组了,明确这一点才能理解接下来的去重操作,然后我们需要去重,这里有一点就是,我们是和当前这个元素的后面的元素去比较然后去重呢,还是和前一个元素比较呢,这里我们选择和前一个元素去比较,如果和自己后一个元素去比较就会导致把开头所有重复的元素都排除了,这里说的不重复的三元组,但是三元组内可以有重复的元素,为了不导致遗漏,所以和他前面的元素比较,这里加个大于0的判断;
    3.然后就是对于后面两个AB指针的去重,这里我想到了一个很好理解的方法,就是,你理解为,我确定下来一个三元组后,保存之后,将AB指针移动向中间移动相同的值上,再左右各移动一位;
    4.需要先保存后去重,因为如果先去重那就会导致一些合法的保存不下来,就漏解了;
  1. class Solution {
  2.     public List<List<Integer>> threeSum(int[] nums) {
  3.         List<List<Integer>> result = new ArrayList<>();
  4.         Arrays.sort(nums);
  5.         // 找出a + b + c = 0
  6.         // a = nums[i], b = nums[left], c = nums[right]
  7.         for (int i = 0; i < nums.length; i++) {
  8.             // 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
  9.             if (nums[i] > 0) {
  10.                 return result;
  11.             }
  12.             if (i > 0 && nums[i] == nums[i - 1]) {  // 去重a
  13.                 continue;
  14.             }
  15.             int left = i + 1;
  16.             int right = nums.length - 1;
  17.             while (right > left) {
  18.                 int sum = nums[i] + nums[left] + nums[right];
  19.                 if (sum > 0) {
  20.                     right--;
  21.                 } else if (sum < 0) {
  22.                     left++;
  23.                 } else {
  24.                     result.add(Arrays.asList(nums[i], nums[left], nums[right]));
  25.                     // 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
  26.                     while (right > left && nums[right] == nums[right - 1]) right--;
  27.                     while (right > left && nums[left] == nums[left + 1]) left++;
  28.                     right--;
  29.                     left++;
  30.                 }
  31.             }
  32.         }
  33.         return result;
  34.     }
  35. }
复制代码

  • 四数之和
    建议: 要比较一下,本题和 454.四数相加II 的区别,为什么 454.四数相加II 会简单很多,这个想明白了,对本题理解就深刻了。 本题 思路整体和 三数之和一样的,都是双指针,但写的时候 有很多小细节,需要注意,建议先看视频。
    题目链接/文章讲解/视频讲解:https://programmercarl.com/0018.四数之和.html
    题目感想:
    1.和三数之后一个思路,就不多赘述了,主要要注意的值第二个桩点的去重逻辑:
  1. import java.util.*;
  2. public class Solution {
  3.     public List<List<Integer>> fourSum(int[] nums, int target) {
  4.         Arrays.sort(nums);  // 排序数组
  5.         List<List<Integer>> result = new ArrayList<>();  // 结果集
  6.         for (int k = 0; k < nums.length; k++) {
  7.             // 剪枝处理
  8.             if (nums[k] > target && nums[k] >= 0) {
  9.                 break;        // 此处的break可以等价于return result;
  10.             }
  11.             // 对nums[k]去重
  12.             if (k > 0 && nums[k] == nums[k - 1]) {
  13.                 continue;
  14.             }
  15.             for (int i = k + 1; i < nums.length; i++) {
  16.                 // 第二级剪枝
  17.                 if (nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) {
  18.                     break;        // 注意是break到上一级for循环,如果直接return result;会有遗漏
  19.                 }
  20.                 // 对nums[i]去重
  21.                 if (i > k + 1 && nums[i] == nums[i - 1]) {
  22.                     continue;
  23.                 }
  24.                 int left = i + 1;
  25.                 int right = nums.length - 1;
  26.                 while (right > left) {
  27.                     long sum = (long) nums[k] + nums[i] + nums[left] + nums[right];
  28.                     if (sum > target) {
  29.                         right--;
  30.                     } else if (sum < target) {
  31.                         left++;
  32.                     } else {
  33.                         result.add(Arrays.asList(nums[k], nums[i], nums[left], nums[right]));
  34.                         // 对nums[left]和nums[right]去重
  35.                         while (right > left && nums[right] == nums[right - 1]) right--;
  36.                         while (right > left && nums[left] == nums[left + 1]) left++;
  37.                         right--;
  38.                         left++;
  39.                     }
  40.                 }
  41.             }
  42.         }
  43.         return result;
  44.     }
  45.     public static void main(String[] args) {
  46.         Solution solution = new Solution();
  47.         int[] nums = {1, 0, -1, 0, -2, 2};
  48.         int target = 0;
  49.         List<List<Integer>> results = solution.fourSum(nums, target);
  50.         for (List<Integer> result : results) {
  51.             System.out.println(result);
  52.         }
  53.     }
  54. }
复制代码
上面代码中:
  1. // 对nums[i]去重
  2.                 if (i > k + 1 && nums[i] == nums[i - 1]) {
  3.                     continue;
  4.                 }
复制代码
其余代码思路同三数之和,这个i为什么要进行判断大于k+1呢,因为没有如果没比这个大,这个时候根本不需要去重这里,结束。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册