Day7代码随想录(1刷) 哈希表

文章讨论了解决四数之和和数组中特定条件下的求和问题,包括使用哈希映射优化存储和查找,以及利用双指针法进行三数之和的扩展。提供了Java代码实现和示例分析。
摘要由CSDN通过智能技术生成

目录

454. 四数相加 II

 383. 赎金信

15. 三数之和

 18. 四数之和


 

454. 四数相加 II

给你四个整数数组 nums1nums2nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

  • 0 <= i, j, k, l < n
  • nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

示例 1:

输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出:2
解释:
两个元组如下:
1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0

示例 2:

输入:nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]
输出:1

  提示:

  • n == nums1.length
  • n == nums2.length
  • n == nums3.length
  • n == nums4.length
  • 1 <= n <= 200
  • -228 <= nums1[i], nums2[i], nums3[i], nums4[i] <= 228

状态:看了答案思路完成,一开始定nums1的值,然后遍历剩下三个数组的方式超时

思路: 把nums1和nums2的和有多少种情况用map存起来,然后在nums3和nums4中遍历并查看map里有无与其相加为0的数字若有则把val加到sum中。map.getOrDefault(key,val)这个方法可以指定默认值然后存取。

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        int sum=0;
        HashMap<Integer,Integer> map = new HashMap<>();
            for(int j=0;j<nums1.length;j++){
                for(int k=0;k<nums2.length;k++){
                    if(map.containsKey(nums1[j]+nums2[k])){
                        map.put(Integer.valueOf(nums1[j]+nums2[k]),Integer.valueOf(map.get(nums1[j]+nums2[k])+1));
                    }else{
                        map.put(Integer.valueOf(nums1[j]+nums2[k]),Integer.valueOf(1));
                    }
                }
            }
        for(int i=0;i<nums3.length;i++){
            for(int j=0;j<nums4.length;j++){
                if(map.containsKey(0-nums3[i]-nums4[j])){
                    sum+=map.get(0-nums3[i]-nums4[j]);
                }
            }
        }
        return sum;
    }
}

 383. 赎金信

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。

magazine 中的每个字符只能在 ransomNote 中使用一次。

示例 1:

输入:ransomNote = "a", magazine = "b"
输出:false

示例 2:

输入:ransomNote = "aa", magazine = "ab"
输出:false

示例 3:

输入:ransomNote = "aa", magazine = "aab"
输出:true

提示:

  • 1 <= ransomNote.length, magazine.length <= 105
  • ransomNote 和 magazine 由小写英文字母组成

状态:完成

思路:因为只有小写字母,所以直接构建长度为26的int数组arr用于存放magzine中的字符出现次数,字符-'a'则可以得到数组的下标。存放完magzine中出现次数后,遍历ransomNote,如果arr里该值大于0则arr中该下标-1,如果等于0则返回false。

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        if(ransomNote.length()>magazine.length()) return false;
        int[] arr = new int[26];
        char[] ransomNotes=ransomNote.toCharArray();
        char[] magazines=magazine.toCharArray();
        for(int i=0;i<magazines.length;i++){
            arr[magazines[i]-'a']++;
        }
        for(int i=0;i<ransomNotes.length;i++){
            if(arr[ransomNotes[i]-'a']>0){
                arr[ransomNotes[i]-'a']--;
            }else{ 
                return false;
            }
        }
        return true;
        
    }
}

15. 三数之和

 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

提示:

  • 3 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

状态:完成

思路:使用双指针的方式去解题更好,不用建立哈希表节约空间与时间。我先对数组采用升序排序,因为是要找到三个数和为0的,我们先指定一个数i,将他的值固定,以不变找变,left的初始值是i+1,right初始值是最后一个,如图一所示。

                                                        图1

-4是小于0,若i所对应的值大于0则不可能相加为0了,因为采用升序排。如果三个数相加如图一小于0,则left++,将结果变大。若大于0,则right--将结果变小,若等于0则将i,left,right写入数组,java可以用Arrays.asList(int,int,int,...)来快速创建数组,然后left++,right--,因为这两个值肯定不能选择了。这时注意结果数组不能有重复,如果left++/right--之后对应的值等于原先的值则一直+/-到不同样为止。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> arr = new ArrayList<>();
        if(nums[0]>0) return arr;
        for(int i=0;i<nums.length;i++){
            while(i>0&&i<nums.length-1&&nums[i]==nums[i-1]) i++; 
            if(nums[i]>0) break;
            int left=i+1;
            int right=nums.length-1;
            if(right==i) break;
            while(left<right){
                int sum=nums[left]+nums[right]+nums[i];
                if(sum==0){
                    arr.add(Arrays.asList(nums[left],nums[right],nums[i]));
                    left++;
                    right--;
                    while(left<nums.length-1&&nums[left]==nums[left-1]) left++; 
                    while(right>i&&nums[right]==nums[right+1]) right--; 
                }else if(sum>0){
                    right--;
                }else if(sum<0){
                    left++;
                }
            }
        }
        return arr;
    }
}

 18. 四数之和

状态:缝缝补补写出来的,有两个点没注意。一是剪枝的时候把nums[a]>0的值给删了,但是这个target可以是正可以是负,导致错误。二是sum的结果溢出,要用long类型。

思路:一看到就知道是三数之和多嵌套了一层,但是实际写起来没有这么简单,问题主要就在剪枝和去重以及结果溢出。我的代码太乱了,还是要想清楚再做题,下面给出正确的思路及代码。

思路:链接icon-default.png?t=N7T8https://programmercarl.com/0018.%E5%9B%9B%E6%95%B0%E4%B9%8B%E5%92%8C.html#%E6%80%9D%E8%B7%AF

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> list = new ArrayList<>();
        if (nums.length < 4)
            return list;
        Arrays.sort(nums);
        for (int a = 0; a < nums.length - 3; a++) {
            while (a > 0 && nums[a] == nums[a - 1]){
                a++;
                if (a >= nums.length - 3) return list;
            }
            long sum_t = (long)target - nums[a];// b+c+d所要求的总和
            int b = a + 1;
            int c = b + 1;
            int d = nums.length - 1;
            long sum = (long)nums[b] + nums[c] + nums[d];
            for (; b < d - 1; b++) {
                System.out.println(a + " " + b + " " + c + " " + d + " ");
                while(b!=a+1&&b<d&&nums[b]==nums[b-1]) b++;
                c = b + 1;
                while (b < c && c < d) {
                    sum = (long)nums[b] + nums[c] + nums[d];
                    if (sum == sum_t) {
                        list.add(Arrays.asList(nums[a], nums[b], nums[c], nums[d]));
                        c++;
                        d--;
                        while (c < d && nums[c] == nums[c - 1])
                            c++;
                        while (d > c && nums[d] == nums[d + 1])
                            d--;
                    } else if (sum > sum_t) {
                        d--;
                    } else if (sum < sum_t) {
                        c++;
                    }
                }
                d = nums.length - 1;
            }
        }
        return list;
    }
}

感想:今天的题目难度主要都集中于最后一题。没想到最后一题竟然这么多坑,其实就比第三题多一个循环,但是就是要想的点有很多。继续坚持下去。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值