代码随想录-哈希表2

第454题.四数相加II

力扣题目链接

基本思路

  1. 要求的是有多少个组合满足,最坏循环遍历四个;最好分成两组,把一组a+b的和放到map的key,和出现的次数作为value,计算另一组,如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来

方法代码

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer, Integer> map1 = new HashMap<>();
        int cont = 0;
        for(int a : nums1){
            for(int b : nums2){
                map1.put(a+b, map1.getOrDefault(a+b, 0) + 1);
            }
        }

        for(int c : nums3){
            for(int d : nums4){
                cont += map1.getOrDefault(0 - c - d, 0);
            }
        }
        return cont;
    }
}
  • 时间复杂度:\(O(n^2)\)
  • 空间复杂度:\(O(n^2)\),最坏情况下A和B的值各不相同,相加产生的数字个数为\(n^2\)

383. 赎金信

力扣题目链接

基本思路

  1. 和之前的字母异位词一样,使用一个数组记录存在的字母,通过自增自减判断是否符合条件

方法代码

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        if (ransomNote.length() > magazine.length()) {
            return false;
        }
        int[] arr = new int[26];
        for (int c : magazine.toCharArray()) {
            arr[c - 'a']++;
        }
        for (int c : ransomNote.toCharArray()) {
            arr[c - 'a']--;
            if (arr[c - 'a'] < 0) {
                return false;
            }
        }
        return true;
    }
}
  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(1)\)

第15题. 三数之和

力扣题目链接

基本思路

  1. 先把数组排序,定义头尾的双指针,这样固定一个i之后就可以,根据sum的大小判断是需要更大的还是更小的值,从而根据排序数组的大小,更新指针指向

方法代码

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length;
        List<List<Integer>> res = new ArrayList<>();
        for(int i = 0 ; i < n - 2; i++){ //注意是n-2
            int x = nums[i];
            //跳过重复数字
            if(i > 0 && x == nums[i - 1]) continue;
            //如果最小的和大于0,直接结束
            if(x + nums[i + 1] + nums[i + 2] > 0) break;
            //如果最大j和k的和还小于0,则jk不变,跳到下一个循环,即更大的x
            if(x + nums[n - 1] + nums[n - 2] < 0) continue;
            //j,k是每次循环都要更新的
            int j = i + 1;
            int k = n - 1;
            while(j < k){
                int s = x + nums[j] + nums[k];
                if(s > 0){
                    k--;
                }else if(s < 0){
                    j++;
                }else{
                    //找到一个三元组
                    res.add(List.of(x, nums[j], nums[k]));
                    //找到之后先更新两个指针
                    //看看指针变化之后是否重复,若有重复,则继续更新
                    j++;
                    while(j < k && nums[j] == nums[j - 1])
                        j++;
                    k--;
                    while(k > j && nums[k] == nums[k + 1])
                        k--;
                }
            }
        }
        return res;
    }
}
  • 时间复杂度:\(O(n^2)\)
  • 空间复杂度:\(O(1)\)

注意点

  1. 注意如何去重,因为已经排序了,所以相等的值都会连在一起,所以通过判断当前数是否和前一个相等,来跳过重复值。
  2. 不能通过判断当前数是否和下一个数相等来跳过,因为j = i + 1,这样会跳过j的可能取值

第18题. 四数之和

力扣题目链接

基本思路

  1. 和上三数之和一样,双指针,复杂度会提升n倍

方法代码

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<>();
        int n = nums.length;
        for(int i = 0; i < n - 3; i++){
            if(i > 0 && nums[i] == nums[i - 1]) continue;
            //第一个值是(long),后面的加法自动转换成(long)
            //这里第一次最后一个nums[i + 3]就有可能超出int范围了,所以要先直接转型
            if((long)nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) break;
            if((long)nums[i] + nums[n - 1] + nums[n - 2] + nums[n - 3] < target) continue;
            for(int j = i + 1; j < n - 2; j++){ //这里设置j为i+1,即可保证j在i后面
                if(j > i + 1 && nums[j] == nums[j - 1]) continue;//这里设置j > i+1
                if((long)nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) break;
                if((long)nums[i] + nums[j] + nums[n - 1] + nums[n - 2] < target) continue;
                int k = j + 1;
                int z = n - 1;
                while(k < z){
                    long sum = (long)nums[i] + nums[j] + nums[k] + nums[z];
                    if(sum > target){
                        z--;
                    }else if(sum < target){
                        k++;
                    }else{
                        res.add(List.of(nums[i], nums[j], nums[k], nums[z]));
                        k++;
                        while(k < z && nums[k] == nums[k - 1])
                            k++;
                        z--;
                        while(z > k && nums[z] == nums[z + 1])
                            z--;
                    }
                }
            }
        }
        return res;
    }
}
  • 时间复杂度:\(O(n^3)\)
  • 空间复杂度:\(O(1)\)

注意点

  1. 注意j的取值和循环条件,这种单个数组的都是根据i的值来确定初始值
  2. 注意观察题目是否会溢出,设置long来解决加法溢出的问题
posted @ 2024-12-12 10:23  xloading  阅读(10)  评论(0)    收藏  举报