数组
大家好,我是老马。
今天我们一起来学习一下数组这种数据结构。
主要知识
数组需要拆分下面几个部分:
-
理论介绍
-
源码分析
-
数据结构实现?
-
题目练习(按照算法思想分类)
-
梳理对应的 sdk 包
-
应用实战
因为这个是 leetcode 系列,所以重点是 4、5(对4再一次总结)。
为了照顾没有基础的小伙伴,会简单介绍一下1的基础理论。
简单介绍1,重点为4。其他不是本系列的重点。
基础篇
数组-矩阵
字符串-字符串匹配
排序:计数+桶+基数
模拟
枚举
chat
详细介绍一下力扣基础之枚举 enumration
我们这次来系统讲解力扣(LeetCode)中的基础技巧之一:枚举(Enumeration),包括:
一、什么是枚举?
**枚举(Enumeration)**就是:
在所有可能的情况中,一个不漏地遍历一遍,判断每种情况是否满足题目条件。
通俗讲就是:“把所有可能性都试一遍”。
二、什么时候用枚举?
情形 | 举例 |
---|---|
选项不多,可以暴力尝试所有组合 | 穷举子集、枚举三元组 |
无法直接计算,必须尝试所有方案 | 两数之和、最长公共前缀 |
子问题不多,暴力可过 | 最长回文子串、回文对 |
💡 重点:枚举适用于“规模小但组合多”的问题,适合用作初步解法或暴力对拍。
三、常见枚举方式分类
1. 枚举一个变量
for (int i = 0; i < n; i++) {
// 判断 i 是否满足条件
}
📌 例题:
2. 枚举两个变量(双层嵌套)
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// 枚举所有 i < j 的组合
}
}
📌 例题:
3. 枚举子串 / 子数组
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
// [i, j] 子串或子数组
}
}
📌 例题:
4. 枚举组合(回溯/位运算)
- 用回溯或二进制掩码枚举所有子集、排列、组合
📌 例题:
5. 特殊结构的枚举
如:
- 枚举矩阵中所有子矩阵
- 枚举图中所有路径
- 枚举两个数的乘积组合
📌 例题:
四、优化枚举的方法
虽然枚举很暴力,但我们可以优化它的方式,让它变得更高效。
✅ 技巧一:剪枝(提前退出)
for (...) {
if (不满足条件) break;
}
📌 例子:
- 三数之和排序后剪枝
- 两数之和先排序,用双指针
✅ 技巧二:用数据结构辅助
比如:
- 用
Set
/Map
减少查找时间 - 用
前缀和
优化子数组求和
📌 例题:
✅ 技巧三:位运算枚举子集
int n = nums.length;
for (int mask = 0; mask < (1 << n); mask++) {
// mask 表示一个子集
for (int i = 0; i < n; i++) {
if ((mask >> i & 1) == 1) {
// 选了 nums[i]
}
}
}
📌 例题:
五、枚举模板代码总结
🔁 枚举两个数:
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// 判断 nums[i] + nums[j]
}
}
🔁 枚举所有子数组:
for (int i = 0; i < n; i++) {
int sum = 0;
for (int j = i; j < n; j++) {
sum += nums[j];
// 判断子数组 [i, j]
}
}
🔁 枚举所有子集(二进制法):
int n = nums.length;
for (int mask = 0; mask < (1 << n); mask++) {
List<Integer> subset = new ArrayList<>();
for (int i = 0; i < n; i++) {
if ((mask & (1 << i)) != 0) {
subset.add(nums[i]);
}
}
// subset 是一个子集
}
六、推荐刷题顺序(入门 → 提升)
✅ 入门枚举题
✅ 中等枚举题
✅ 高阶进阶
七、小结
优点 | 缺点 |
---|---|
简单直接,逻辑清晰 | 时间复杂度可能高,适合数据范围小 |
不需要太多技巧 | 有些题暴力法过不了,需要优化 |
如果你需要,我可以帮你: