LeetCode HOT100刷题笔记(一):哈希表, 双指针

【如果笔记对你有帮助,欢迎关注&点赞&收藏,收到正反馈会加快更新!谢谢支持!】

ps:笔记和代码按本人理解整理,重思路

目录

一、哈希表

题目1:两数之和

题目2:字母异位词分组

题目3:最长连续序列

二、双指针

题目4:移动零

题目5:盛最多水的容器

题目6:三数之和

题目7:接雨水


一、哈希表

题目1:两数之和

1. 两数之和 - 力扣(LeetCode)

  • 题意:在nums中找到和为 target 的两个数的index
  • 拆解:
    for idx, num in enumerate(nums):
    	- mapping[哈希表] 记录 {target—当前num[key]: 当前idx[value]}
    	if num在mapping.keys()中:
    		# 说明已有“当前num+之前num == target”,满足条件
    		- 返回结果[当前idx,mapping]
     
  • 代码:
    class Solution:
        def twoSum(self, nums: List[int], target: int) -> List[int]:
            n = len(nums)
            mapping = {}
            for i in range(n):
                if target - nums[i] in mapping:
                    return [mapping[target - nums[i]], i]
                else:
                    mapping[nums[i]] = i

题目2:字母异位词分组

49. 字母异位词分组 - 力扣(LeetCode)

  • 题意:将组成字母一致的单词归位一组
  • 关键:"ate","eat","tea" 这三个字符串在sort后都是 "aet"
    【哈希表为 {["aet": ["ate","eat","tea"], ……}】
  • 代码:
    class Solution:
        def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
            d = defaultdict(list)
            for str_ in strs:
                sorted_str = ''.join(sorted(str_))
                d[sorted_str].append(str_)
            return list(d.values())

题目3:最长连续序列

128. 最长连续序列 - 力扣(LeetCode)

  • 题意:找到数组(可能有重复)中连续的最长序列,要求时间复杂度为O(n) 【所以不能排序】
  • 拆解:
    「哈希表确定」st = set(nums) 
    「目标」找到连续序列的第一个数,即(num-1)不存在
    「逻辑」
    	for st中的每个数num:
    		if 是序列的第一个:
    			- 计算当前序列长度
    			- 更新答案
    			
    「注意」遍历元素的时候,要遍历哈希集合,不能是nums,不然循环次数会变成O(n^2)
  • 代码:
    class Solution:
        def longestConsecutive(self, nums: List[int]) -> int:
            max_len = 0
            st = set(nums)
            for num in st:
                if num - 1 in st:  # 不是连续序列的第一个,跳过
                    continue
                y = num + 1
                while y in st:
                    y += 1
                max_len = max(max_len, y-num)
            return max_len
           
    
    

二、双指针

题目4:移动零

283. 移动零 - 力扣(LeetCode)

  • 题意:把数组中的0移动到末尾,同时保持非零元素的相对顺序
  • 拆解:
    「双指针类型」快慢指针
    	「快指针作用」遍历数组的元素
    	「慢指针作用」重写数组 
    「逻辑」
    	初始化:快慢指针在第一个数位置
    	while/for 快指针遍历数组:
    		if 快指针指向0: 快指针前进
    		else 快指针指向非0:
    			- nums[慢指针]的值改写成nums[快指针]的值(慢指针负责改写数组)
    			- 快、慢指针都前进
    	for 慢指针到结尾的数:
    		- 改为0

  • 代码:
    class Solution:
        def moveZeroes(self, nums: List[int]) -> None:
            """
            Do not return anything, modify nums in-place instead.
            """
            slow = 0
            fast = 0
            while fast < len(nums):
                if nums[fast] != 0:
                    nums[slow] = nums[fast]
                    slow += 1                
                fast += 1
            
            for i in range(slow, len(nums)):
                nums[i] = 0
    
            return nums
        

题目5:盛最多水的容器

11. 盛最多水的容器 - 力扣(LeetCode)

  • 题意:求面积 H(y轴) * W(x轴),其中 H = min(左高度,右高度),W = 双指针距离
  • 关键:移动指针的时候 W一定减小,看 H 有没有可能增加(所以保留高的,移动低的)
  • 拆解:
    「双指针类型」左右指针
    
    「代码逻辑」
    	初始化:左、右指针分别在最左、最右端
    	while 左指针在左、右指针在右:
    		- 计算面积 = min(左高度,右高度) * 左右指针距离
    		- 更新最大面积
    		- 移动高度小的指针(左指针向 -> 或者 右指针向 <- )
  • 代码:
    class Solution:
        def maxArea(self, height: List[int]) -> int:
            l = 0
            r = len(height)-1
            result = 0
            while l < r:
                area = (r-l)*min(height[l], height[r])
                result = max(result, area)
                if height[r] < height[l]:
                    r -= 1
                else:
                    l += 1
            return result

题目6:三数之和

15. 三数之和 - 力扣(LeetCode)

  • 题意:所有和为 0 且不重复的三元组 → A + B + C = 0
  • 拆解:
    「双指针类型」左右指针
    
    「代码逻辑」
    	- nums排序 -> 有序数组
    	for 遍历第一个数A(固定A,转化成B+C=-A的两数之和问题): 
    		- 去重1:重复的A
    		- 剪枝:A > 0,因为排序后 C > B > A > 0,不可能有三数之和为0
    		# 左右双指针找A+B+C=0
    		while 左指针在左、右指针在右:
    			if 总和 > 0: 右指针⬅️移
    			elif 总和 < 0: 左指针右移
    			elif 总和为0:
    				- [A, B, C]加到结果
    				# 找下一个解
    				- 去重2:重复的B和C跳过
    				- 左、右指针同时右移、左移
    					

  •  代码:
    class Solution:
        def threeSum(self, nums: List[int]) -> List[List[int]]:
            result = []
            nums = sorted(nums)
            for i in range(len(nums)-2): 
                # 注释中 A=nums[i]
                if i > 0 and nums[i] == nums[i-1]:   # 重复情况
                    continue
                if nums[i] > 0:   # 因为 C>B>A>0,三数之和不可能为0,直接结束
                    return result
                
                # 开始两数之和
                left = i+1
                right = len(nums)-1
                while left < right:
                    sum_ = nums[i]+nums[left]+nums[right]
                    if sum_ > 0:
                        right -= 1
                    elif sum_ < 0:
                        left += 1
                    else:
                        result.append([nums[i], nums[left], nums[right]])
                        # 因为这题可能有多个答案,要找出所有答案
                        # 找到一个解之后怎么找下一个解:跳过重复数字 → 左右指针同时右移和左移
                        while left < right and nums[left] == nums[left+1]: # 跳过重复数字
                            left += 1
                        while left < right and nums[left] == nums[right-1]:  # 跳过重复数字
                            right -= 1
                        left += 1    
                        right -= 1
                        
            return result
    

题目7:接雨水

42. 接雨水 - 力扣(LeetCode)

  • 题意:找最多接水量
  • 关键:单位柱子能接的雨水量 = min(左侧最高柱,右侧最高柱) - 当前高度
  • 拆解:
    「双指针类型」左右指针
    	「左指针作用」记录左侧最高
    	「右指针作用」记录右侧最高
    	
    「代码逻辑」
    	- 初始化左右侧最高为-inf
    	while 左指针在左、右指针在右:
    		if 左侧最高 < 右侧最高:
    			# 移动左指针
    			if 左指针位置能存水(即,左指针水位 < 左侧最高):
    				- 记录左指针位置存水量
    			else: # 左指针位置不能存水(即,左指针水位 >= 左侧最高)
    				- 更新左侧最高水位
    			- 左指针右移
    		if 左侧最高 >= 右侧最高:
    			同理

  • 代码:
    class Solution:
        def trap(self, height: List[int]) -> int:
            result = 0
     
            left = 0
            right = len(height)-1
     
            height_l = height_r = -inf  # 初始化
     
            while left <= right:  
                if height_l <= height_r:  # 左端低,处理左边,移动左指针
                    if height[left] < height_l:   # 当前柱子高度<左侧最高,可以存水
                        result += (height_l - height[left])  # 记录存水量
                    else:  # 当前柱子高度>=左侧最高>=右侧最高,不能存水
                        height_l = height[left] # 更新左侧最高
                    left += 1   
                else:
                    if height[right] < height_r:  # 右端低,处理右边,移动右指针
                        result += (height_r - height[right])
                    else:
                        height_r = height[right]
                    right -= 1
     
            return result

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值