Leetcode-hot100(2026.08.17)

哈希

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

python 复制代码
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        d = {}
        for i in range(len(nums)):
            if nums[i] in d:
                return [i,d[nums[i]]]
            d[target-nums[i]] = i
        return None

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

排序or计数

python 复制代码
class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        d = collections.defaultdict(list)
        for s in strs:
            mp = "".join(sorted(s))
            d[mp].append(s)
        return list(d.values())

时间复杂度:o(nklog(k))

空间复杂度:o(nk)

python 复制代码
class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        d = collections.defaultdict(list)
        for s in strs:
            counts = [0]*26
            for c in s:
                counts[ord(c)-ord('a')] += 1
            # list不能作为key
            d[tuple(counts)].append(s)
        return list(d.values())

时间复杂度:o(nk)

空间复杂度:o(nk)

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

python 复制代码
class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        # 如果出现重复元素,那么就需要我们不断的去重复判断,但是对于结果没有任何影响,所以需要先去重
        # 如果去重以后元素能按照顺序排列,那么接下来就是判断起点和最大长度的过程
        nums_set = sorted(set(nums))
        n = len(nums_set)
        if n<2:
            return n
        res = cur = 1
        for i in range(1,n):
            # if nums_set[i]-1!=nums_set[i-1]:
            #     res = max(res,cur)  # 这样写的bug是如果全部连续,那么没有办法触发条件
            #     cur = 1
            # else:
            #     cur += 1
            if nums_set[i]-1==nums_set[i-1]:
                cur += 1
                res = max(res,cur)
            else:
                cur = 1
            
        return res

时间复杂度:o(nlogn)

空间复杂度:o(n)

python 复制代码
class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        # 如果出现重复元素,那么就需要我们不断的去重复判断,但是对于结果没有任何影响,所以需要先去重
        # 其实没必要排序,我们只要找到连续序列的起点开始计数即可
        nums_set = set(nums)
        n = len(nums_set)
        if n<2:
            return n
        res = 1
        for num in nums_set:
            if num-1 not in nums_set:
                cur = 1
                while num+1 in nums_set:
                    cur += 1
                    num += 1
                res = max(res,cur)
            
        return res

时间复杂度:o(n) # 尽管for嵌套了while,但是由于if起点的判断,每一个元素在整体仅仅被遍历一次

空间复杂度:o(n)

双指针

283. 移动零 - 力扣(LeetCode)

python 复制代码
class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        # 快慢指针
        # 慢指针指向非0元素的下一个元素
        slow = fast = 0
        for fast in range(len(nums)):
            if nums[fast] != 0:
                nums[slow],nums[fast] = nums[fast],nums[slow]
                slow += 1

时间复杂度:o(n)

空间复杂度:o(1)

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

python 复制代码
class Solution:
    def maxArea(self, height: List[int]) -> int:
        # 左右指针,对于每个柱子,它能接的最多的雨水,就是距离它最远的柱子宽度乘以矮柱子的高度
        # 所以矮柱子的移动是有可能带来整体的更多的雨水的!
        left,right = 0,len(height)-1
        res = 0
        while left<right:
            res = max(res,(right-left)*min(height[left],height[right]))
            if height[left]<height[right]:
                left += 1
            else:
                right -= 1
        return res

时间复杂度:o(n)

空间复杂度:o(1)

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

python 复制代码
class Solution:
    def threeSum(self, nums: list[int]) -> list[list[int]]:
        res = []
        # 注意题目要求不重复,所以必须排序,排序可以方便去重
        nums_sort = sorted(nums)
        n = len(nums_sort)
        for f in range(n-2):
            if f!=0 and nums_sort[f]==nums_sort[f-1]:
                continue
            # 三数之和等于0,那么first应该小于等于0
            if nums_sort[f]>0:
                break
            s,t = f+1,n-1
            while s<t:
                cur = nums_sort[f]+nums_sort[s]+nums_sort[t]
                if cur == 0:
                    res.append([nums_sort[f],nums_sort[s],nums_sort[t]])
                    # 去重
                    while s<t and nums_sort[s+1]==nums_sort[s]:
                        s += 1
                    while s<t and nums_sort[t-1]==nums_sort[t]:
                        t -= 1
                    # 去重后进位
                    s += 1
                    t -= 1
                elif cur > 0:
                    t -= 1
                else:
                    s += 1
        return res

时间复杂度:o(n*n) # 最差就是内外都是遍历一遍

空间复杂度:o(logn) # 排序带来的,结果的存储不计入

42. 接雨水 - 力扣(LeetCode)

python 复制代码
class Solution:
    def trap(self, height: List[int]) -> int:
        # 接雨水就用单调栈求解是最好的
        # 柱子接多少雨水,完全取决于右侧柱子
        # 一旦右侧柱子比当前高,那么当前柱子就能接雨水(接多少取决于左臂和右侧柱子)
        n = len(height)
        if n<2:
            return 0
        stack = []
        res = 0
        for i in range(n):
            # 当前柱子高,stack[-1]就是坑底,stack[-2]才是左臂
            # 按照现在的弹出顺序,整个栈一定是栈顶小的!stack[-1]<=stack[-2]
            while stack and height[i]>height[stack[-1]]:
                bottom = stack.pop()
                if not stack:
                    break
                left = stack[-1]  # 左臂并不弹出
                res += (i-left-1)*(min(height[left],height[i])-height[bottom])
            stack.append(i)
        return res

时间复杂度:O(n) # for里面嵌套while,但是while仅仅是作用于stack,每个元素入栈出栈一次最多

空间复杂度:O(n)

滑动窗口

3. 无重复字符的最长子串 - 力扣(LeetCode)

python 复制代码
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # 快慢指针确定窗口,集合确定不重复,但是注意集合也是需要动态的,出现重复删除的是左侧
        # 23245,到了2重复了,但是删的是左侧的2,而不是放弃全部窗口
        # 223245,用while,而不是if
        res = 0
        d = set()
        left = 0
        for right in range(len(s)):
            while s[right] in d:
                d.remove(s[left])
                left += 1
            d.add(s[right])
            res = max(res,len(d))
        return res

时间复杂度:O(n) # for里面嵌套while,但是d也最多存一遍所有的字符

空间复杂度:O(n)

438. 找到字符串中所有字母异位词 - 力扣(LeetCode)

python 复制代码
class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        # 异位词的判断需要靠字典确定字符和数量
        # 借助collections.Counter()库可以解决
        # 但是我们不能对每一个字符串都这样去判断
        # 仅仅判断第一个对应串,其他是一个增删的逻辑
        m,n = len(s),len(p)
        res = []
        if m<n:
            return res
        ds = collections.Counter(s[:n])
        dp = collections.Counter(p)
        if ds == dp:
            res.append(0)
        # 构造窗口判断
        slow = 0
        for fast in range(n,m):
            ds[s[fast]] += 1
            ds[s[slow]] -= 1
            # 下面的判断没有任何作用,仅仅是减少存储,不加完全可以
            if ds[s[slow]] == 0: del ds[s[slow]]
            slow += 1
            if ds == dp:
                res.append(slow)
        return res

时间复杂度:O(n)

空间复杂度:O(n)

子串

560. 和为 K 的子数组 - 力扣(LeetCode)

python 复制代码
class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        # 求的是子数组,所以排序不可用
        # 数字有正有负,所以快慢指针也会失效
        # 求解思路是前缀和,如果i-j的子数组求和为k,说明j的前缀和减去i的前缀和为k
        res = 0
        pre = 0
        d = {0:1}  # 比如恰好每个元素都是k
        for n in nums:
            pre += n
            if pre-k in d:
                res += d[pre-k]  # 可能不止一个
            d[pre] = d.get(pre,0)+1
        return res

时间复杂度:O(n)

空间复杂度:O(n)

239. 滑动窗口最大值 - 力扣(LeetCode)

python 复制代码
class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        # 在滑动窗口中只要出现了最大值,那么滑动窗口里面就是确定的
        # 但是如果原定的最大值离开了滑动窗口,则需要新的最大值
        # 而这个过程满足的是先进先出
        # 所以考虑一个维护顺序的队列
        # 队列的队首是最大的元素,从队首到队尾,元素依次变小
        # 队列里面存idx,需要判断长度是否达到滑动窗口
        dq = []
        res = []
        for i in range(k):
            # 不是所有的元素都存,而是说大元素之前的小元素没必要存
            # 但是大元素之后的小元素是需要存的
            # 所以从队尾开始往前走,只要大,就弹出前面的
            # 但是从队尾开始,如果小,那就得存起来
            while dq and nums[dq[-1]]<nums[i]:
                dq.pop()
            dq.append(i)
        res.append(nums[dq[0]])
        for i in range(k,len(nums)):
            while dq and nums[dq[-1]]<nums[i]:
                dq.pop()
            dq.append(i)
            if i-dq[0]>=k:
                dq.pop(0)
            res.append(nums[dq[0]])
        return res

时间复杂度:O(n) # for里面嵌套while,但是d也最多存一遍所有的字符

空间复杂度:O(k)

76. 最小覆盖子串 - 力扣(LeetCode)

python 复制代码
class Solution:
    def minWindow(self, s: str, t: str) -> str:
        # 其实还是异位词的思路,但是是子数组,所以对前后有点限制
        m,n = len(s),len(t)
        if m<n:
            return ""
        ds = collections.Counter()
        dt = collections.Counter(t)
        min_len = m+1
        min_left = left = 0
        cur = 0  # 记录一下有多少个字符满足了
        required = len(dt)  # 需要满足这些
        for right in range(m):
            ds[s[right]] += 1
            # 看看是否可以满足一个
            if s[right] in dt and ds[s[right]]==dt[s[right]]:
                cur += 1
            # 假如我们现在已经全部满足了,那就尝试缩小左边界,看看能不能更小
            # 注意满足条件是cur = required
            # 一次一步,边收缩边更新状态
            while cur == required:
                if right-left+1 < min_len:
                    min_left = left
                    min_len = right - left + 1
                # 然后把left移出窗口,其实就是+=1,但是在这之前要判断是否破坏了成立性
                if s[left] in dt:
                    ds[s[left]] -= 1
                    if ds[s[left]] < dt[s[left]]:
                        cur -= 1
                left += 1
        return "" if min_len == m+1 else s[min_left:min_left+min_len]

时间复杂度:O(n+m) # for里面嵌套while,但是实际一个移动right,一个移动left,各自其实均只有一遍,再加上构造counter的n。

空间复杂度:O(|Σ|),其中 Σ 是字符集。

相关推荐
W_326001 小时前
Python-OpenCV图像像素与通道:通道拆分合并、深浅拷贝
图像处理·人工智能·python·opencv·机器学习
泡沫冰@1 小时前
GO 语言基础
开发语言·算法·golang
让你三行代码QAQ1 小时前
AI大模型开发核心名词速览
python
2401_868534781 小时前
农商行分布式网络建设
python·pygame
luj_17682 小时前
元设计的诱惑与现实
c语言·开发语言·c++·经验分享·算法
小星星闪亮登场2 小时前
ST表--倍增思想
开发语言·数据结构·c++·算法·思维
AC赳赳老秦2 小时前
OpenClaw 多源采集公开行业数据:从原始信息到研究报告初稿的自动化实践
java·c语言·c++·python·php·deepseek·openclaw
程序员雷欧3 小时前
AQS深度解析
开发语言·python
玩三国杀玩的3 小时前
Pytorch-c++-CUDA
c++·pytorch·python·深度学习