速通Hot100-Day04——哈希

454. 四数相加 II

像是类似于**两数之和,**但是如何存储和查找呢?

果然像,就是如何降低时间复杂度,2-2的时候时间复杂度是最小的,1-3时间复杂度太高,4个for更高。该题的target = 0

【分析】时间O(n²),空间O(n²)

【思想】

A + B作为键存储在map中,value就是A + B对应 数值出现的次数。只要C + D = - (A + B)map中,那么就能够得到满足条件target = 0的组合数量,即value

1. 两数之和的区别在于:

  • 只是计数,不需要返回索引,没有就是计数0,不匹配,没必要存储
  • 两数之和必须存储,因为要返回对应的索引值
java 复制代码
class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer, Integer> map = new HashMap<>();

        for(int a : nums1) {
            for(int b : nums2) {
                map.put(a + b, map.getOrDefault(a+b, 0) + 1);
            }
        }

        int res = 0;
        for(int c : nums3) {
            for(int d : nums4) {
                int sum = 0 - (c + d);
                if(map.containsKey(sum)) {
                    res += map.get(sum);
                }
            }
        }

        return res;
    }
}

383. 赎金信

【分析】时间O(2 * n),空间O(1)

【思想】

与上题唯一的区别:第二个字符串中可以存在不同的字母 ,在于能否组成第一个字符串(字母只用一次);只要遍历完hash所有元素<=0那么就证明有足够的字母能组成第一个字符串。

java 复制代码
class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int[] hash = new int[26];

        for(char c : ransomNote.toCharArray()) {
            hash[c - 'a']--;
        }

        for(char c : magazine.toCharArray()) {
            hash[c - 'a']++;
        }

        for(int i = 0;i < 26;i++) {
            if(hash[i] < 0) return false;
        }

        return true;
    }
}

15. 三数之和

1. 两数之和 之和的进阶版本

使用双指针,是需要排序的,而且是可行的:找的是元素值,而非下标。

思路很简单,但是去重很关键。

【分析】时间O(n²),空间O(1)

【思想】

排序 + 双指针,保持i不动,去遍历leftright的值,满足条件就留下。

  • 如果+ > 0,将right左移保证和== 0
  • 如果+ < 0,将left右移保证== 0
  • 如果 == 0,存下结果,并且准备判重

允许同一个元组内,元素可以重复;不同元组内,元素不可重复。即可重复元素值,不可重复下标

{0,0,0}允许出现,但是不允许第二个{0,0,0}。

【去重思想】

  1. 数组已经排序,nums[i]>0,直接返回结果,后面的也都>0
  2. 去重i,是nums[i]==nums[i-1]不同元组间,不可重复;而不是判重nums[i]==nums[i+1],因为{nums[i], nums[i+1],...}可能在同一个元组答案内
  3. 假如为-1 -1 -1 -1 2 2 2 2,那么第一组{-1,-1,2}已经存储为答案;再继续遍历left/right都只会使重复

【注意】

最后判断leftright与正常的left/right是不可以交换的。

可以手推一遍,也可以想象一下:

  • 如果是重复元素值,正常移动指针后,这个答案会被再次记录
  • 先移动到不是重复元素值,再移动指针,去到了不重复元素值重新判断是否满足条件
java 复制代码
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<>();

        int left,right;
        for(int i = 0;i < nums.length;i++) {
            if(nums[i] > 0) break;
            if(i > 0 && nums[i] == nums[i-1]) continue;

            left = i + 1;
            right = nums.length - 1;
            while(left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if(sum < 0) left++;
                else if(sum > 0) right--;
                else {
                    res.add(List.of(nums[i], nums[left], nums[right]));
                    while(left < right && nums[left] == nums[left + 1]) left++;
                    while(left < right && nums[right] == nums[right - 1]) right--;
                    left++;
                    right--;
                }
            }
        }
        return res;
    }
}

18. 四数之和

该题最精美的地方在于剪枝操作,可以体会一下剪枝的魅力。

  • 和三数之和可以成为对称版本了,嵌套两层。
  • 而且之前是0,现在是 target,取的就是 平均值(递增就没必要判断了)
java 复制代码
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> res = new ArrayList<>();

        Arrays.sort(nums);

        for(int i = 0;i < nums.length;i++) {
            // 一级剪枝和去重
            if(nums[i] > target/4) break;
            if(i > 0 && nums[i] == nums[i - 1]) continue;

            for(int j = i + 1;j < nums.length;j++) {
                // 二级剪枝和去重
                if(nums[i] + nums[j] > target/2) break;
                if(j > i + 1 && nums[j] == nums[j - 1]) continue;

                int left = j + 1, right = nums.length - 1;
                while(left < right) {
                    int sum = nums[i] + nums[j] + nums[left] + nums[right];
                    if(sum < target) left++;
                    else if(sum > target) right--;
                    else {
                        res.add(List.of(nums[i], nums[j], nums[left], nums[right]));
                        while(left < right && nums[left] == nums[left + 1]) left++;
                        while(left < right && nums[right] == nums[right - 1]) right--;
                        left++;
                        right--;
                    }
                }
            }
        }
        return res;
    }
}
相关推荐
memcpy0几秒前
LeetCode 1208. 尽可能使字符串相等【不定长滑窗,字符串】1497
算法·leetcode·职场和发展
阿Y加油吧3 分钟前
LeetCode 二叉树双王炸!二叉树展开为链表 + 前序 + 中序还原二叉树|小白递归一把过
算法·leetcode·链表
AI科技星5 分钟前
全球AI信息场(信息网)基础理论与数学建模研究(乖乖数学)
开发语言·人工智能·线性代数·算法·机器学习·数学建模
仟濹14 分钟前
【算法打卡day37(2026-04-04 周六)】DFS专项训练4-枚举专项训练 1-全部是蓝桥杯真题
算法·蓝桥杯·深度优先
汀、人工智能18 分钟前
12 - 内置函数:Python的瑞士军刀
数据结构·算法·数据库架构·图论·python的瑞士军刀
Tisfy29 分钟前
LeetCode 3418.机器人可以获得的最大金币数:动态规划
leetcode·机器人·动态规划
动恰客流管家1 小时前
动恰3DV3丨客流统计系统:自然山水景区客流统计破局,景区数字化标配
数据结构·microsoft·3d
于樱花森上飞舞1 小时前
【Redis】Redis的数据结构
数据结构·数据库·redis
羊小猪~~1 小时前
LLM--微调(Adapters,Prompt,Prefix)
算法·ai·大模型·llm·prompt·adapters·prefix
未来之窗软件服务1 小时前
SenseVoicecpp ggml-hexagon.cpp大模型[AI人工智能(七十九)]—东方仙盟
人工智能·算法·仙盟创梦ide·东方仙盟