LeetCode Hot 100

成元 / 2026-07-24 / 约 1442 字 / 预计阅读 3 分钟 / — 次浏览 < 教程, 笔记 > • [ Algorithm ]

前言

最近开始抽事件刷 Hot 100 了。

后续我会逐步完善题型导航。

题型导航

题目 解法 个人理解
5. 最长回文子串 动态规划
11. 盛最多水的容器 双指针 + 贪心
22. 括号生成 回溯
39. 组合总和 回溯
46. 全排列 回溯
48. 旋转图像 数学 知道矩阵相关数学知识就能做出来
55. 跳跃游戏 贪心 / 动态规划 一开始使用动态规划,通过后发现贪心更快
56. 合并区间 快速排序(等较快的排序) 先根据各个边界的左端点排序,然后再合并
62. 不同路径 动态规划 貌似有数学上的解,更快,但是懒得看
64. 最小路径和 动态规划 到 (i,j) 的最小路径和取决于 (i-1,j) 和 (i,j-1)
75. 颜色分类 快速排序(三路) 这题因为有大量重复项,使用三路快排比较好
78. 子集 回溯
102. 二叉树的层序遍历 BFS 几乎就是纯 BFS,要额外记录每层元素个数而已
279. 完全平方数 动态规划(完全背包) 参考零钱兑换,假设硬币都是完全平方数
322. 零钱兑换 动态规划(完全背包)
337. 打家劫舍 III DFS + 动态规划(树形DP) 由底朝上不用哈希表,相反则需要
347. 前 K 个高频元素 桶排序 / 快速选择 配合哈希表,两种方法都能完成进阶要求
394. 字符串解码 用纯递归写出来的,感觉没有用到什么算法技巧
399. 除法求值 图(邻接表) + BFS/DFS 邻接表记录权值,然后从一个端点搜索到另一个
416. 分割等和子集 动态规划( 0-1 背包) 类似传统 0-1 背包问题
494. 目标和 回溯 / 动态规划( 0-1 背包) 数学功底不好,一开始没想到可以转为 0-1 背包
581. 最短无序连续子数组 双指针 + 贪心 双指针确定左右边界可做到 O(n)

知识点

桶排序

桶排序(Bucket Sort)的思路是:先按照某种映射规则,把元素分到若干个桶里;再分别对每个桶排序;最后按照桶的顺序把结果合并起来。

它适合以下情况:

假设有 nn 个元素、bb 个桶,第 ii 个桶中有 mim_i 个元素,那么桶排序的时间复杂度取决于桶内使用的排序算法。下面的模板使用插入排序,时间复杂度为:

O(n+b+∑i=1bmi2) O\left(n + b + \sum_{i=1}^{b}m_i^2\right)

下面是一个支持负数的整数桶排序模板。bucketWidth 表示每个桶覆盖的数值范围,需要根据数据分布选择;它必须大于 0:

#include <algorithm>
#include <cstddef>
#include <stdexcept>
#include <vector>

void bucketSort(std::vector<int>& nums, int bucketWidth) {
    if (nums.size() < 2) {
        return;
    }
    if (bucketWidth <= 0) {
        throw std::invalid_argument("bucketWidth must be positive");
    }

    const auto [minIt, maxIt] = std::minmax_element(nums.begin(), nums.end());
    const long long minValue = *minIt;
    const long long maxValue = *maxIt;
    const std::size_t bucketCount =
        static_cast<std::size_t>((maxValue - minValue) / bucketWidth + 1);

    std::vector<std::vector<int>> buckets(bucketCount);
    for (int value : nums) {
        const std::size_t index =
            static_cast<std::size_t>((static_cast<long long>(value) - minValue) /
                                     bucketWidth);
        buckets[index].push_back(value);
    }

    std::size_t writeIndex = 0;
    for (auto& bucket : buckets) {
        // 对桶内元素使用插入排序
        for (std::size_t i = 1; i < bucket.size(); ++i) {
            const int value = bucket[i];
            std::size_t j = i;
            while (j > 0 && bucket[j - 1] > value) {
                bucket[j] = bucket[j - 1];
                --j;
            }
            bucket[j] = value;
        }

        for (int value : bucket) {
            nums[writeIndex++] = value;
        }
    }
}

在前 K 个高频元素中,不是按照元素值分桶,而是按照元素出现的次数分桶。一个元素最多出现 nn 次,因此可以创建 n+1n + 1 个桶,把出现次数为 frequency 的元素放入 buckets[frequency],再从后向前遍历桶。这样不需要对频次排序,时间复杂度和空间复杂度都是 O(n)O(n)。

快速选择

Other

枚举
模拟
排序
哈希
前缀和
前后缀
原地置换
矩阵
双指针
滑动窗口
二分查找
中心扩展
快慢指针
递归
分治
回溯
深度优先搜索
广度优先搜索
栈
单调栈
队列
单调队列
堆
链表
二叉树
二叉搜索树
图
拓扑排序
并查集
字典树
贪心
动态规划
记忆化搜索
快速选择
摩尔投票
位运算
数学

总结

总结就等到我把 Hot 100 全部刷完再写吧。