代码随想录算法训练营第七天字符串 java :454 四数相加II、15三数之和、18 四数之和

文章介绍了如何利用哈希表解决LeetCode中的四数相加II、三数之和以及四数之和问题,强调了去重逻辑在这些问题中的重要性,包括a、b、c、d的去重策略,并提供了AC代码示例。此外,还探讨了数组、集合(set)和映射(map)在不同场景下的使用选择。
摘要由CSDN通过智能技术生成

难点

  • 为什么使用哈希法
  • 为什么使用map结构,而不是数组和set
  • key用来存储什么,value用来存储什么

LeetCode454 四数相加II

题目

AC代码

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
     // 生成 temp 存放1+2 2+3
     int temp;
     //  生成res 用于存储 nums1 出现次数
     int res =0;
     //生成map
     Map <Integer,Integer> map= new HashMap<>();
     
     //进行循环遍历
     for(int i: nums1)
     {
         for(int j:nums2)
         {
             temp = i+j;
             if(map.containsKey(temp))
             {
                 map.put(temp,map.get(temp)+1);
             }
             else
             {
                 map.put(temp,1);
             }
         }
     }
     //a+b 如果包含 怎么 else 怎么样
     //c+d 
    for(int i:nums3)
    {
        for(int j:nums4)
        {
            temp=i+j;
            if(map.containsKey(0-temp))
            {
                res +=map.get(0-temp);
            }
        }
    }
     return res;

    }
}

LeetCode15三数之和

题目

去重逻辑的思考

a的去重

说道去重,其实主要考虑三个数的去重。 a, b ,c, 对应的就是 nums[i],nums[left],nums[right]
a 如果重复了怎么办,a是nums里遍历的元素,那么应该直接跳过去。
重点在于用 nums[i]== nums[i+1] 还是nums[i]==nums[i-1] 前者的话 是在三个数中 a,b,c 中不能去重复值
可是 1,1,2 是可以的 所以 所以前者不并不适用
我们要做的是 不能有重复的三元组,但三元组内的元素是可以重复的
那么应该这么写

if (i > 0 && nums[i] == nums[i - 1]) {
    continue;
}

b 与c的去重

就涉及到了去重的逻辑上要添加上对left和right的去重

while (left < right && nums[right] == nums[right + 1]) right--;
 while (left < right && nums[left] == nums[left - 1]) left++;

AC代码

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
    // 初始化 一个多维数组 result
    List<List<Integer>> result =new ArrayList<>(); 
    //进行排序
    Arrays.sort(nums);
    // for循环 
    for(int i=0;i<nums.length;i++)
    {
    //合理性判定 ,将A去重
      if(nums[i]>0)
      {
          return result;
      }
      if(i>0&& nums[i]==nums[i-1])
       {
           continue;
       }
    //左右初始化
    int left= i+1;
    int right=nums.length-1;
    //while(right>left) 
    while(right>left)
    {
        int sum =nums[i]+nums[left]+nums[right];
        if(sum >0)
        {
            right--;
        }
        else if(sum<0)
        {
            left++;
        }         
    // int sum
        
    // 将 bc 去重
       else{
     result.add(Arrays.asList(nums[i], nums[left], nums[right]));
       //将三元组加入result之后

         while(right>left&& nums[left]==nums[left+1]) left++;
         while(right>left&& nums[right] == nums[right-1])
        right--; 
        left++;
       right--;

       }        
    //return result
       
    }
    }
    return result;
    }
}
 

LeetCode18 四数之和

题目


剪枝

就是通过某种判断,避免一些不必要的遍历过程

AC代码


相较于三数之和 原理差不多   只不过多加了一个数字的循环
class Solution {
   public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);
       
        for (int i = 0; i < nums.length; i++) {
		
            // nums[i] > target 直接返回, 剪枝操作
            if (nums[i] > 0 && nums[i] > target) {
                return result;
            }
		
            if (i > 0 && nums[i - 1] == nums[i]) {    // 对nums[i]去重
                continue;
            }
            
            for (int j = i + 1; j < nums.length; j++) {

                if (j > i + 1 && nums[j - 1] == nums[j]) {  // 对nums[j]去重
                    continue;
                }

                int left = j + 1;
                int right = nums.length - 1;
                while (right > left) {
		    // nums[k] + nums[i] + nums[left] + nums[right] > target int会溢出
                    long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum > target) {
                        right--;
                    } else if (sum < target) {
                        left++;
                    } else {
                        result.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        // 对nums[left]和nums[right]去重
                        while (right > left && nums[right] == nums[right - 1]) right--;
                        while (right > left && nums[left] == nums[left + 1]) left++;

                        left++;
                        right--;
                    }
                }
            }
        }
        return result;
    }
}

哈希表总结

对于哈希表,要知道哈希函数哈希碰撞在哈希表中的作用

  • 哈希函数 是把传入的key映射到符号表的索引上。
  • 哈希碰撞 处理有多个key映射到相同索引上时的情景,处理碰撞的普遍方式是拉链法线性探测法
  • 接下来常见的三种哈希结构

数组

242.有效的字母异位词 (opens new window)中,就用到了数组,提到数组就是简单的哈希表,
这道题包括小写字母用数组最合适
相对于map 结构来说 ,map消耗空间比数组大的 而题目中要求有小写字母 也相当于是对我们的暗示要用到数组

set(集合)

349. 两个数组的交集 (opens new window)中我们给出了什么时候用数组就不行了,需要用set。

这道题目没有限制数值的大小,就无法使用数组来做哈希表了。

map(映射)

在1.两数之和 (opens new window)中map正式登场。

来说一说:使用数组和set来做哈希法的局限。

数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和
y的下标。所以set 也不能用。 map是一种<key,
value>的结构,本题可以用key保存数值,用value在保存数值所在的下标。所以使用map最为合适。

收获

黑暗就是你的蜡烛,你的边界就是你追寻的起点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值