代码随想录第七天

内容:

  1. 四数相加II(454)
  2. 赎金信(383)
  3. 三数之和(15)
  4. 四数之和(18)
  5. 哈希表总结

1.四数相加II

难度:🔥🔥🔥

1.1 思路分析

与前面的两数之和很像,这里我们使用map解决这个问题。将前两个数组看成一个整体,他们的和作为key,而他们出现的次数为value。

再去遍历后面两个数组时,我们得到他们的和temp,之后去map中寻找 0 - temp 是否存在,如果存在则让我们的元组数目加上对应的value。

1.2 代码实现
class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        //用map来解决该问题
        Map<Integer,Integer> map = new HashMap<>();
        int sum = 0;
        int temp = 0;
        int count = 0;//记录元组的个数
        for(int i :nums1){
            for(int j : nums2){
                sum = i + j;//前两个数组元素的和记录到我们的map集合中
                if (map.containsKey(sum)){
                    map.put(sum,map.get(sum) + 1);
                }else{
                    map.put(sum,1);
                }
            }
        }
        for(int i : nums3){
            for(int j : nums4){
                temp = i + j;
                if (map.containsKey(-temp)){
                    count += map.get(-temp);
                }
            }
        }
        return count;
    }
}
1.3 注意事项
  • 这道题目是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况

2.赎金信

🔥

1.1 思路分析

做完有效的字母异位词再去做这道题目其实就很简单了。这题使用数组会更简单直接有效,而不使用map来解决。

1.2 代码实现
class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        //存放我们的26个字母
        int[] record = new int[26];

        for(char c : magazine.toCharArray()){
            record[c - 'a']++;
        }
        for(char c : ransomNote.toCharArray()){
            record[c - 'a']--;
        }
        for(int count : record){
            if (count < 0){
                return false;
            }
        }
        return true;
    }
}
1.3 收获总结
  • 在哈希法中有一些场景就是为数组量身定做的
  • 在本题的情况下,使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了

3.三数之和

难度:🔥🔥🔥🔥

3.1 思路分析

这道题目使用哈希法并不十分合适,因为在去重的操作中有很多细节需要注意。

采用双指针法会比哈希法更容易理解,高效一些。大体思路是首先我们要求这个数组是一个有序的数组,之后通过一个for循环来从头遍历整个数组,这是我们的双指针就要用到了。left指针指向for循环中i的下一位,而right指针指向数组的最后位置的索引。记录三个指针指向位置数的总和为sum,如果sum大于0,说明总和大了,则right指针需要前移,反之left指针后移。如果正好相等,则记录数据,同时left++,right--

很显然我们在整体思路外还需要做去重操作来避免集合元素的重复。

如图所示:
在这里插入图片描述

3.2 代码实现
class Solution {
        //要求:元素集合不可以重复,每个数只能使用一次
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> list = new ArrayList<>();
        //对nums数组进行排序
        Arrays.sort(nums);
        for(int i = 0;i < nums.length;i++) {
            //剪枝操作,如果nums[i] > 0,因为我们的数组是按照顺序排列的。
            if (nums[i] > 0) {
//                break;
                return list;
            }
            //去重操作
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;//直接进入下一次循环
            }
            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 {
                    list.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    //去重操作
                    while (left < right && nums[right] == nums[right - 1]) {
                        right--;
                    }
                    while (left < right && nums[left] == nums[left + 1]) {
                        left++;
                    }
                    left++;
                    right--;
                }
            }
        }
        return list;
    }
}
3.3收获总结
  • 这种解法的时间复杂度为O(n ^ 2)
  • 在去重时我们需要明白nums[i] == nums[i - 1]nums[i] == nums[i + 1]的区别,如果是后者,那么我们可能会因为前一个数据没有记录到而直接跳过
  • 后面两个数也需要去重操作
  • 剪枝操作也很重要,很考验一个人的思维能力

4.四数之和

难度:🔥🔥🔥🔥

4.1 思路分析

这里的思路与三数之和很像,但是有一些细节需要注意,例如:不要判断nums[k] > target 就返回了,三数之和 可以通过 nums[i] > 0 就返回了,因为 0 已经是确定的数了,四数之和这道题目 target是任意值。比如:数组是[-4, -3, -2, -1]target-10,不能因为-4 > -10而跳过。但是我们依旧可以去做剪枝,逻辑变成nums[i] > target && (nums[i] >=0 || target >= 0)就可以了

4.2 代码实现
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> list = new ArrayList<>();
        Arrays.sort(nums);

        for(int i = 0;i < nums.length;i++){
            if (nums[i] > 0 && nums[i] > target){//nums[i] > target
                return list;
            }
            if (i > 0 && nums[i] == nums[i - 1]){
                continue;
            }
            for(int j = i + 1;j < nums.length;j++){
                //下面这句话是不需要的
//                if (nums[j] > 0 && nums[j] < target){
//                    return list;
//                }
				//这里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 sum = nums[i] + nums[j] + nums[left] + nums[right];
                    
                    if (sum > target){
                        right--;
                    }else if (sum < target){
                        left++;
                    }else{
                        //alList方法返回List类型
                        list.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
                        //下面这部分需要写在else循环中
                        while(left < right && nums[left] == nums[left + 1]){
                            left++;
                        }
                        while(left < right && nums[right] == nums[right - 1]){
                            right--;
                        }
                        left++;
                        right--;
                    }
                }
            }
        }
        	return list;
    }
}
4.3 收获总结
  • 该题的时间复杂度为O(n ^ 3)
  • 掌握双指针法我们可以将O(n ^ 2) 的时间复杂度优化为 O(n)
  • 同理我们可以解决类似N数之和的题目

5.哈希表总结

  • 一般来说哈希表都是用来快速判断一个元素是否出现集合里,如果题目中需要用到查找元素,那么就可以考虑使用哈希表
  • 常见的三种哈希结构:数组,set(集合),map(映射)
  • 分析每种哈希结构的优劣,选择合适的哈希结构来解决实际问题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值