代码随想录day7|哈希表2

1.两数之和-哈希表

思路:需要判断一个元素是否遍历过,是否在集合中出现过,用到哈希表的结构

  1. 为什么会想到用哈希表:需要判断需要的值是否在之前遍历过的元素中出现过
  2. 哈希表为什么用map:因为要判断值是否出现过,同时返回对应元素的下标
  3. 本题map是用来存什么的:存放已经遍历过数据的值和下标
    在这里插入图片描述
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        dic = {}
        # 通过建立数组得到对应遍历过的元素的值
        for i in range(len(nums)):
            y = target - nums[i]
            if y in dic.keys():
                return [i,dic[y]]
            else:
                dic[nums[i]] = i

454.四数相加-哈希表

题目简介: 给定四个长度相同的数组,在四个数组中分别找一个元素,使得四个元素相加等于0,找到这样取值的数量有多少。
整体思路: 暴力解法是遍历四个数组,然后count++,**另一种思路是仅遍历A+B两个数组,然后看C+D中有没有出现对应的值。**两数相加的变形,将两个数组当成整体进行两数相加。
在这里插入图片描述

class Solution:
    def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
        map = {}
        for a in nums1:
            for b in nums2:
                if a+b not in map.keys():
                    map[a+b] = 1
                else:
                    map[a+b] += 1
        
        # if the -(a+b) exists in nums3 and nums4, we shall add the count
        count = 0
        for c in nums3:
            for d in nums4:
                if -(c+d) in map.keys():
                    count += map[-(c+d)]
        return count

383.赎金信-哈希表+字典

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        map = {}
        for i in magazine:
            if i not in map.keys():
                map[i] = 1
            else :
                map[i] += 1
        for j in ransomNote:
            if j not in map.keys():
                return False
            elif j in map.keys() and map[j] == 0:
                return False
            else:
                map[j] -= 1
        return True
# 利用数组哈希表结构
class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:

        arr = [0] * 26

        for x in magazine:    # 记录 magazine里各个字符出现次数
            arr[ord(x) - ord('a')] += 1

        for x in ransomNote:  # 在arr里对应的字符个数做--操作
            if arr[ord(x) - ord('a')] == 0:  # 如果没有出现过直接返回
                return False
            else:
                arr[ord(x) - ord('a')] -= 1
        
        return True
        

15.三数之和-排序+双指针

思路:

  1. 排序:因为不需要获取下标的值,所以可以先对这个数组进行排序
  2. 双指针:根据当前值的大小变更指针的指向,本题目不需要返回数组的下标,所以可以使用双指针的方法进行求解。
  3. 去重:a+b+c = 0 ,如何对a,b,c进行去重。
    nums[i] = nums[i-1]按照这个条件进行剪枝操作,同时还需要对left和right的位置进行剪枝操作。
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        nums.sort()
        result = []
        for i in range(n):
            # 对第一个数进行剪枝
            if i>0 and nums[i] == nums[i-1]:
                continue
            # 如果第一个元素已经大于0,那么没有必要继续寻找
            if nums[i] > 0:
                break 
            left = i+1
            right = n-1
            while right > left:
                total = nums[i] + nums[left] + nums[right]
                if total == 0:
                    result.append([nums[i],nums[left],nums[right]])
                    # 在找到一个三元组之后进行对后续的数值进行去重
                    while left != right and nums[left] == nums[left+1]: 
                        left += 1
                    while left != right and nums[right] == nums[right-1]: 
                        right -= 1
                    left += 1
                    right -= 1
                elif total > 0:
                    right -= 1
                else:
                    left += 1
        return result

反思:
4. 临界条件思考不清晰: 没有想到当第一个元素移动到大于0的位置,即nums[i]>0时,可以直接停止搜索。
5. 后续left和right指针剪枝的位置,没有写对, 应该是在找到一个元素之后进行剪枝,这样可以做到用尽可能少的时间达到剪枝的作用。
6. 第一层剪枝操作: 第一层剪枝nums[i]==nums[i+1]用来判断结果集中有没有重复元素,而nums[i]==nums[i-1]是用来判断result中的列表去重。

18.四数之和-双指针+剪枝

  1. 双层for循环,双指针的方式,即在三数之和的基础上在外面套一个循环
  2. 细节:重点在k,i的剪枝以及后续left和right的去重
  3. 注意:不能延续三数之和的剪枝操作,因为输入的target既可为正数,也可为负数。
    在这里插入图片描述

四数之和的双指针解法是两层for循环nums[k] + nums[i]为确定值,依然是循环内有left和right下标作为双指针,找出nums[k] + nums[i] + nums[left] + nums[right] == target的情况,通过双指针的方式可以使时间复杂度与原来相比降低一个量级。

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        n = len(nums)
        nums.sort()
        result = []
        for k in range(n):
            # 第一层剪枝操作
            if k > 0 and nums[k] == nums[k-1]:
                continue
            for i in range(k+1,n-2):
                if i > k+1 and nums[i] == nums[i-1]:
                    continue
                left = i+1
                right = n-1
                while left < right:
                    value = nums[k]+nums[i]+nums[left]+nums[right]
                    if value > target:
                        right -= 1
                    elif value < target:
                        left += 1 
                    else:
                        result.append([nums[k],nums[i],nums[left],nums[right]])    
                        # 三层剪枝
                        while left < right and nums[right] == nums[right-1]:right-= 1
                        while left < right and nums[left] == nums[left+1]:left+= 1
                        right -= 1
                        left += 1
        return result
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值