算法学习 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数和问题啦~

相关推荐
胖咕噜的稞达鸭2 分钟前
算法日记分治:用归并排序解决逆序对问题
算法
代码or搬砖14 分钟前
JVM垃圾回收算法
jvm·算法
Aaron158814 分钟前
基于RFSOC+VU13P在5G波束成形中的技术应用分析报告
人工智能·算法·5g·fpga开发·硬件架构·信息与通信·基带工程
小丁努力不焦虑16 分钟前
常考算法题
算法
C雨后彩虹17 分钟前
亲子游戏问题
java·数据结构·算法·华为·面试
leoufung27 分钟前
Bitwise AND of Numbers Range - 题解与思路
算法
乌萨奇也要立志学C++32 分钟前
【洛谷】离散化专题 模板精讲 + 火烧赤壁 & 贴海报实战
数据结构·c++·算法
小龙报33 分钟前
【算法通关指南:数据结构与算法篇 】二叉树相关算法题:1.新二叉树 2.二叉树的遍历
c语言·数据结构·c++·人工智能·物联网·算法·深度优先
AI视觉网奇42 分钟前
ue 条件判断
笔记·算法·ue5