代码随想录算法训练营第十二天 | LeetCode 454、15、18、哈希表小结

454.两数相加Ⅱ

题目链接:. - 力扣(LeetCode)

题目讲解:代码随想录

1)解题思路:

  1. 首先定义一个HashMap,key放a和b两数之和,value 放a和b两数之和出现的次数。
  2. 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。
  3. 定义int变量count,用来统计 a+b+c+d = 0 出现的次数。
  4. 再遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
  5. 最后返回统计值 count 就可以了.

2)代码实现:

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {


        //1. 定义一个hashmap,key放两数之和,value放两数之和出现的次数
        Map<Integer,Integer> hash = new HashMap<>();

        //2. 遍历大A和大B数组,记录两个数组元素之和
        for(int i = 0; i < nums1.length;i++){
            for(int j = 0; j < nums2.length;j++){
                hash.put(nums1[i]+nums2[j], hash.getOrDefault(nums1[i]+nums2[j],0)+1);
            }
        }

        //3.定义计数器
        int count = 0;

        //4. 遍历其他两个数组,统计个数
        for(int i = 0; i < nums3.length;i++){
            for(int j = 0; j < nums4.length ; j++){
                if(hash.getOrDefault(0-nums3[i]-nums4[j] , 0) != 0){
                    count += hash.getOrDefault(0-nums3[i]-nums4[j] , 0);
                }
            }
        }

        return count;
    }
}

15.三数之和

题目链接:. - 力扣(LeetCode)

题目讲解:代码随想录

1)解题思路:

(1)a+b+c = 0 转化为 nums[i] + nums[right] + nums[left] = 0

(2)!!现将数组排序

(3)i是放在数组左端(外层循环控制),right是放在数组右端,left在i和right之间移动,寻找三者和为0的搭配。

(4)内层循环逻辑:left在i和right之间移动,

i)nums[i] + nums[left] + nums[right] == 0 ,记录在答案中,向左寻找(left++)

ii)nums[i] + nums[left] + nums[right]  > 0,说明此时的最大数nums[right]太大了,右边界向右移动(right--),

iii)nums[i] + nums[left] + nums[right] < 0,说明此时的总数太小了,继续向左移动left(left++)

(5)当 right 和 left 相遇时,即可停止。

(6)本题有去重的操作,不能有重复的三元组排列,但是组内三个元素是可以重复的

在每一次发现搭配存入答案数组中之后,都需要去重,保证下一次搭配出现不与上一次搭配重复。但需要针对除第一个元素之外的其他元素进行去重,防止[-1,-1,2]这种被卡掉。

2)代码实现:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        //1.新建一个数组,存放结果
        List<List<Integer>> ans = new ArrayList<>();

        //2.双指针先排好序
        Arrays.sort(nums);

        //3.循环查找
        for(int i = 0; i < nums.length;i++){
            //判断合法,三元组里面最小的元素大于0,没有循环的必要
            if(nums[i] > 0){
                break;
            }

            //对i进行去重,非首项的三元组中最小元素如果和上一次循环的一样,结果也一样
            //去除这种可能,和上一项相同的i抛弃,进入下一次循环
            if(i > 0 && nums[i] == nums[i-1]){
                continue;
            }

            //双指针法进行查找
            //left是中间的迭代元素,right是三元组中最大的元素
            int left = i+1;
            int right = nums.length - 1;
            while(left < right){
                int sum = nums[i] + nums[left] + nums[right];
                if(sum > 0){
                    right--;
                }else if(sum < 0){
                    left++;
                }else{
                    ans.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    //对left去重,left向左移动找到与现在不同的元素
                    while(left < right && nums[left] == nums[left+1])left++;
                    //对right去重,right向右移动,找到与现在相同的最右边的元素
                    while(left < right && nums[right] == nums[right - 1])right--;

                    left++;right--;
                }
            }
        }
        return ans;
    }
}

18.四数之和

题目链接:. - 力扣(LeetCode)

题目讲解:代码随想录

1)解题思路:

四数之和的双指针解法是两层for循环nums[k] + nums[i]为确定值,依然是循环内有left和right下标作为双指针,找出nums[k] + nums[i] + nums[left] + nums[right] == target的情况。

三数之和的时间复杂度是O(n^2),四数之和的时间复杂度是O(n^3) 。

2)代码实现:

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        //1.新建一个返回类型的答案数组
        List<List<Integer>> ans = new ArrayList<>();

        //2.双指针先浅浅排序一下
        Arrays.sort(nums);

        //3.两层循环算nums[a] + nums[b]
        //left是nums[c],right是nums[d]
        for(int i = 0;i < nums.length;i++){
            //(剪枝处理)对四元组中最小元素,做合法判别
            if(nums[i] > target && nums[i] > 0){
                break;
            }

            //对四元组中的nums[a]去重,
            if(i > 0 && nums[i] == nums[i-1]){
                continue;
            }

            for(int j = i+1;j < nums.length;j++){
                //(剪枝处理)
                if(nums[i] + nums[j] > target && nums[i] + nums[j] >= 0){
                    break;
                }
                
                //对nums[b]去重
                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{
                        ans.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
                        //对left进行去重,循环找到left最后一个重复元素
                        while(left < right && nums[left] == nums[left + 1])left++;
                        //对right进行去重,循环找到right最后一个重复元素
                        while(left < right && nums[right] == nums[right - 1])right--;

                        left++;right--;
                    }
                }
            }
        }

        return ans;
    }
}

 哈希表小结

1)三种哈希表数据结构:

数组哈希表

int[] hash = new hash

(key-为坐标,value为数组元素值)

需要提前知道哈希表大小

242.有效的字母异位词

383.赎金信

set哈希表

Set<Integer> ans = new HashSet<>();

(单列存储,只储存键值)

单列存储,只能存储键值

349.两个数组的交集

202.快乐数

map哈希表

Map<Integer,Integer> ans = new HashMap<>();

(存储键值对,Key唯一)

存储键值对

1.两数之和

454.四数之和

2)HashSet常用方法:

//引入hashset类的封装包
import java.util.HashSet;
import java.util.Set;
 
//创建HashSet对象
Set<Integer> set1 = new HashSet<>();
 
//遍历数组1
for (int i : nums1) {
    //添加元素
    set1.add(i);
}
 
//查看哈希表中是否存在key值为i的元素
set1.contains(i)
 
//把HashSet集合转为数组
resSet.stream().mapToInt(x -> x).toArray();

3)HashMap常用方法:

getOrDefault(K key , V deflautValue) 根据指定的键获取对应的值,没有则返回后面那个默认数值。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值