算法训练营Day7|哈希表part02

454.四数相加II 【来自四个数组的值相加】
  • 自我尝试
    • 思路: 因为题上要求返回int,即符合要求的元组数量。因此可以采用HashMap方法。具体思路为通过一个HashMap将前两个数组的和记录下来:key为和,value为出现次数。随后利用二数之和类似方法将剩下两个数组再次进行遍历,即检验(0-c-d)是否为HashMap里的一个key,是的话就说明我们找到了个符合要求的元组!累加下来,得出并返回最后的结果。
       
    • 代码:O(n^2)
      ​
      ​
      class Solution {
          public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
           // 1. 定义map,key为nums1,nums2的和,value为出现次数
           HashMap<Integer,Integer> hm = new HashMap<>();
           // 2. 遍历nums1, nums2来完善map
           for(int ele1:nums1){
               for(int ele2:nums2){
                   int tmp = ele1+ele2;
                   if(hm.containsKey(tmp)){
                       hm.put(tmp,hm.get(tmp)+1);
                   }else{
                       hm.put(tmp,1);
                   }
               }
           }
          // 3. 声明一个int count,来返回结果
           int count = 0;
          // 4. 遍历nums3, nums4, 使用(-nums3[i]-nums4[j]==map.get(key)?); 累加count的结果
           for(int ele3:nums3){
               for(int ele4:nums4){
                   if(hm.containsKey(-ele3-ele4)){
                       count+=hm.get(-ele3-ele4);
                   }
               }
           }
           // 5. 返回
           return count;
      
          }
      }
      
      
  • 范例尝试
    • 思路: 与上相同
    • 代码
      class Solution {
          public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
           // 1. 定义map,key为nums1,nums2的和,value为出现次数
           HashMap<Integer,Integer> hm = new HashMap<>();
           // 2. 遍历nums1, nums2来完善map
           for(int ele1:nums1){
               for(int ele2:nums2){
                   int tmp = ele1+ele2;
                   // 如果存在返回,不存在就返回0
                   hm.put(tmp,hm.getOrDefault(tmp,0)+1);
               }
           }
          // 3. 声明一个int count,来返回结果
           int count = 0;
          // 4. 遍历nums3, nums4, 使用(-nums3[i]-nums4[j]==map.get(key)?); 累加count的结果
           for(int ele3:nums3){
               for(int ele4:nums4){
                  count+=hm.getOrDefault(-ele3-ele4,0);
               }
           }
           // 5. 返回
           return count;
      
          }
      }
    • 收获
      • Hashmap的方法: getOrDefault(key, defaultVal)。 这个方法首先尝试get某个key,如果key不存在于map,那就返回一个默认值。通过这样的方式,可以省去个if-else判断。


383. 赎金信 
  • 自我尝试
    • 思路: 与字母异同位思路类似。看一个string A,是否能由string B里的char所拼出来,核心就是统计stirng A char数量后,在遍历string B char做差,如果有大于0的余下来,则表明无法完全由string B 拼接出来。
    • 代码
      class Solution {
          public boolean canConstruct(String ransomNote, String magazine) {
              int[] count = new int[26];
              for(int i=0; i<ransomNote.length(); i++){
                  count[ransomNote.charAt(i)-'a']++;
              }
              for(int j=0;j<magazine.length();j++){
                  count[magazine.charAt(j)-'a']--;
              }
              for(int ele:count){
                  if(ele>0){
                      return false;
                  }
              }
              return true;
          }
      }
    • 收获
      • 再次强调: string的方法为charAt(index)而非charsAt(index)

15. 三数之和 【同一个数组内的三数之和】
  • 自我尝试
    • 思路
      • 暴力法求解去重很麻烦
  • 范例尝试
    • 思路:双指针法!
      • 整体:首先以增序排列数组。随后通过两个指针(left,right)加一个loop base,在loop循环迭代中,俩指针sum与base的和与0相比做出偏移。即 若和大于0,需要减少sum,right指针向左偏移。同理,若和小于0,left指针向右偏移。特殊情况出现在当三数和恰好等于0的时候。添加这三个数,随即左右偏移进行去重处理!
        • headsup1:   base需要去重!不然会出现重复结果。base去重逻辑为当前是否与前面一个数相同。是nums[i] == nums[i-1],而非nums[i] == nums[i + 1]。原因为如果后者的话会跳过当前的数据pass
        • headsup2:再temp>0, temp<0时候没必要去重,因为仍会自动偏移。
        • headsup3:当三数和恰好为0时候,左右偏移去重后,记得确保左右的值与先前已不同。
    • 代码
      class Solution {
          public List<List<Integer>> threeSum(int[] nums) {
             // 1. 声明返回的数组,并排序数组
              List<List<Integer>> result = new ArrayList<>();
              Arrays.sort(nums);
             // 2. 从base:nums[0]开始遍历,声明两个指针:left,right。当base与left,right和小于0,left右移,right向左移,如果相等后,加入返回的数组,同时left与right都要去重在偏移前。
             for(int i=0;i<nums.length-2;i++){
                  // 2.0 break 条件
                  if(nums[i]>0){
                      break;
                  }
                  // 2.1 base去重
                  if(i>0 && nums[i]==nums[i-1]){
                      continue;
                  }
                  // 2.2 body
                  int left = i+1;
                  int right = nums.length -1;
                  while(left<right){
                      int temp = nums[i]+nums[left]+nums[right];
                      if(temp<0){
                          //说明left需要递增
                          left++;
                      }else if(temp>0){
                          right--;
                      }else{
                          result.add(Arrays.asList(nums[i],nums[left],nums[right]));
                          //2.3 做去重处理
                          while(left<right && nums[left]==nums[left+1]) left++;
                          while(left<right && nums[right]==nums[right-1]) right--;
                          //2.4 这俩仍要做!不然的话如果有重复的,以重复的值出现
                          left++;
                          right--;
                      }
                  }
             }
             // 2.3 返回
             return result;
          }
      }

    • 收获
      • array方法:
        • Arrays.sort(arr)这是给数组升序排序。
        • Arrays.asList(val1,val2...); 这是一个生成arraylist的方法 ;
          • Note1:Arrays.asList() 返回的是一个实现List接口的对象,但其实际上为一个特殊的ArrayList实例。

  • 范例尝试
    • 思路: 与三数之和类似。外面再套一层循环达到O(n^3)的复杂度。但注意相应的去重步骤略有改动。
      • Headsup1: 注意溢出的问题。
    • 代码
      class Solution {
          public List<List<Integer>> fourSum(int[] nums, int target) {
              //双指针法
              Arrays.sort(nums);
              List<List<Integer>> result = new ArrayList<>();
              for(int i =0; i<nums.length-3; i++){
                  if (nums[i] > 0 && nums[i] > target) {
                      return result;
                  }
                  if(i>0 && nums[i]==nums[i-1]){
                      continue;
                  }
                  for(int j=i+1; j<nums.length-2;j++){
                      // i+1 每次也要
                      if(j>i+1 && nums[j]==nums[j-1]){
                          continue;
                      }
                      int left = j+1;
                      int right = nums.length-1;
                      while(left<right){
                          int temp = nums[i]+nums[j]+nums[left]+nums[right];
                          if(temp<target){
                              left++;
                          }else if(temp>target){
                              right--;
                          }else{
                              result.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
                              while(left<right && nums[left]==nums[left+1]) left++;
                               while(left<right && nums[right]==nums[right-1]) right--;
                               left++;
                               right--;
                          }
                      }
                  }
              }
              return result;
          }
      }


总结

  • 三数之和与四数之和都是同一数组内求出不重复的元素和为target。双指针法要求它们先进行排序;而这点与使用HashMap的二数之和方法不同,因为二数之和要求返回元素下标。如果二数之和返回的是值,也可以采用双指针法。
  • 四数相加是有序且可重复,因而用HashMap来解决,降为O(n^2)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值