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

相关推荐
学编程的小程4 小时前
LeetCode216
算法·深度优先
leeyayai_xixihah4 小时前
2.21力扣-回溯组合
算法·leetcode·职场和发展
01_4 小时前
力扣hot100——相交,回文链表
算法·leetcode·链表·双指针
萌の鱼4 小时前
leetcode 2826. 将三个组排序
数据结构·c++·算法·leetcode
Buling_04 小时前
算法-哈希表篇08-四数之和
数据结构·算法·散列表
AllowM4 小时前
【LeetCode Hot100】除自身以外数组的乘积|左右乘积列表,Java实现!图解+代码,小白也能秒懂!
java·算法·leetcode
RAN_PAND4 小时前
STL介绍1:vector、pair、string、queue、map
开发语言·c++·算法
fai厅的秃头姐!6 小时前
C语言03
c语言·数据结构·算法
lisanndesu7 小时前
动态规划
算法·动态规划
myprogramc7 小时前
十大排序算法
数据结构·算法·排序算法