算法学习 Day06 哈希表2

454. 四数相加 II

文章讲解

视频讲解

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

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

解题思路

思路:由于是四个独立的数组,不用考虑重复元素的情况,可以暴力遍历两次。先遍历AB,将数字和到出现次数的映射记录在hash表,然后遍历CD,求和后找到补数是否在hash表内。

  • 时间复杂度:O(n^2)
  • 空间复杂度:O(n^2) 最坏情况下A和B的值各不相同,相加产生的数字个数为 n^2
python 复制代码
class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        hashmap = {}
        for n1 in nums1:
            for n2 in nums2:
                sum1 = n1 + n2
                hashmap[sum1] = hashmap.get(sum1, 0) + 1
        # 答案出现次数
        count = 0

        for n3 in nums3:
            for n4 in nums4:
                need = 0 - n3 - n4
                if need in hashmap:
                    count += hashmap[need]
        return count

总结

这种解法的关键在于利用哈希表来记录前两个数组元素之和的出现次数。这样在遍历后两个数组时,只需要查找哈希表中是否存在与当前元素之和相等的值即可。这种方法避免了直接暴力枚举四个数组的所有组合,大大提高了效率。

383. 赎金信

文章讲解

题目:给你两个字符串:ransomNotemagazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。如果可以,返回 true ;否则返回 falsemagazine 中的每个字符只能在 ransomNote 中使用一次。

解题思路

使用hash表记录magazine中字符和出现次数的映射char2cnt,然后迭代ransomNote的每个字符,看看该字符是否出现在char2cnt并且数量>0。

  • 时间复杂度: O(n^2)
  • 空间复杂度: O(1)
python 复制代码
class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        char2cnt = {} # 记录magazine中字符数量
        # 词频统计
        for c in magazine:
            char2cnt[c] = char2cnt.get(c, 0) + 1

        # 迭代判断ransomNote的字符是否在magazine里面
        for c in ransomNote:
            if c in char2cnt and char2cnt[c] > 0:
                char2cnt[c] -= 1
            else:
                return False

        return True

总结

通过使用哈希表记录前两个数组的所有可能和的出现次数,然后遍历后两个数组,查找其和的补数在哈希表中出现的次数,从而高效计算满足条件的元组数量。

15. 三数之和

文章讲解

视频讲解

labuladong讲解

题目:给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

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

解题思路

本题需要考虑到重复元素,可以使用双指针并且配合递归的方式实现一个通用的解决nSum的方法。具体如下:

  • 1 首先对数组进行排序,这样可以方便后续的双指针操作。
  • 2 然后使用递归的方式来解决 n 数之和的问题。当 n 等于 2 时,使用双指针的方式来查找满足条件的两个数。当 n 大于 2 时,递归计算 (n-1) 数之和,并将当前元素加入到结果中。
  • 3 在双指针操作时,需要跳过重复的元素,以避免重复的结果。
  • 时间复杂度: O(n^2)
  • 空间复杂度: O(1)
python 复制代码
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        # 1 数组排序
        nums.sort()

        # 2 双指针加递归计算
        return self.nSumTarget(nums,3, 0, 0)

    def nSumTarget(self, nums: List, n: int, start:int ,target:int)-> List[List[int]]:
        ''' 递归计算n数和,直到递归到2时使用双指针 
            Inputs:
                nums: 整数数组
                n: 计算n数之和
                start:从start开始求n数和
                target:目标和
        '''
        # 1 不足n元素或者n<2
        res = []
        sz = len(nums)
        if n< 2 or sz < n:
            return res

        # 2 双指针计算2数和
        if n == 2:
            low, high = start, sz-1 # 注意1:low从start开始
            while low<high:
                left_val, right_val = nums[low], nums[high]
                sum_val = left_val + right_val
                if sum_val < target:
                    # low++, 并且需要跳过当前重复元素 =
                    while low<high and nums[low] == left_val: # 注意2:需要跳过重复元素
                        low += 1
                elif sum_val > target:
                    while low<high and nums[high] == right_val:
                        high -= 1
                else:
                    res.append([left_val, right_val])
                    # 单独移动low和high
                    while low<high and nums[low]==left_val: # 注意3:low和high分别移动,跳过重复元素
                        low += 1
                    while low<high and nums[high]==right_val:
                        high -= 1

        # 3 递归计算n数和
        else:
            for i in range(start, sz):
                # 第二次开始排除重复元素
                if i > start and nums[i] == nums[i-1]:
                    continue

                # 递归计算(n-1)Sum
                sub_res = self.nSumTarget(nums, n-1, i+1, target-nums[i])
                for arr in sub_res:
                    arr.append(nums[i])
                    res.append(arr)
        return res

总结

利用了排序和双指针的技巧,并通过递归的方式来解决 n 数之和的问题。虽然时间复杂度为 O(n^2),但是空间复杂度较低,并且代码实现也比较简洁。需要时刻注意排除重复元素。

18. 四数之和

文章讲解

视频讲解

题目:给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复 的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abcd 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

解题思路

同"三数之和"。

  • 时间复杂度: O(n^2)
  • 空间复杂度: O(1)
python 复制代码
class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        # 1 数组排序
        nums.sort()

        # 2 双指针加递归计算
        return self.nSumTarget(nums,4, 0, target)

    def nSumTarget(self, nums: List, n: int, start:int ,target:int)-> List[List[int]]:
        ''' 递归计算n数和,直到递归到2时使用双指针 
            Inputs:
                nums: 整数数组
                n: 计算n数之和
                start:从start开始求n数和
                target:目标和
        '''
        # 1 不足n元素或者n<2
        res = []
        sz = len(nums)
        if n< 2 or sz < n:
            return res

        # 2 双指针计算2数和
        if n == 2:
            low, high = start, sz-1 # 注意1:low从start开始
            while low<high:
                left_val, right_val = nums[low], nums[high]
                sum_val = left_val + right_val
                if sum_val < target:
                    # low++, 并且需要跳过当前重复元素 =
                    while low<high and nums[low] == left_val: # 注意2:需要跳过重复元素
                        low += 1
                elif sum_val > target:
                    while low<high and nums[high] == right_val:
                        high -= 1
                else:
                    res.append([left_val, right_val])
                    # 单独移动low和high
                    while low<high and nums[low]==left_val: # 注意3:low和high分别移动,跳过重复元素
                        low += 1
                    while low<high and nums[high]==right_val:
                        high -= 1

        # 3 递归计算n数和
        else:
            for i in range(start, sz):
                # 第二次开始排除重复元素
                if i > start and nums[i] == nums[i-1]:
                    continue

                # 递归计算(n-1)Sum
                sub_res = self.nSumTarget(nums, n-1, i+1, target-nums[i])
                for arr in sub_res:
                    arr.append(nums[i])
                    res.append(arr)
        return res

总结

同三数之和,背下nSumTarget就能一劳永逸的解决N数和问题啦~

相关推荐
焦耳加热23 分钟前
阿德莱德大学Nat. Commun.:盐模板策略实现废弃塑料到单原子催化剂的高值转化,推动环境与能源催化应用
人工智能·算法·机器学习·能源·材料工程
wan5555cn31 分钟前
多张图片生成视频模型技术深度解析
人工智能·笔记·深度学习·算法·音视频
u6061 小时前
常用排序算法核心知识点梳理
算法·排序
蒋星熠3 小时前
Flutter跨平台工程实践与原理透视:从渲染引擎到高质产物
开发语言·python·算法·flutter·设计模式·性能优化·硬件工程
小欣加油4 小时前
leetcode 面试题01.02判定是否互为字符重排
数据结构·c++·算法·leetcode·职场和发展
3Cloudream4 小时前
LeetCode 003. 无重复字符的最长子串 - 滑动窗口与哈希表详解
算法·leetcode·字符串·双指针·滑动窗口·哈希表·中等
王璐WL4 小时前
【c++】c++第一课:命名空间
数据结构·c++·算法
空白到白4 小时前
机器学习-聚类
人工智能·算法·机器学习·聚类
索迪迈科技5 小时前
java后端工程师进修ing(研一版 || day40)
java·开发语言·学习·算法
zzzsde5 小时前
【数据结构】队列
数据结构·算法