| title | 数据结构与算法:Java开发者的必备修炼 |
|---|---|
| date | 2025-05-09 |
| categories | Algorithm |
💡 关于怎么刷题的帖子:
- 📖 《论如何4个月高效刷满 500 题并形成长期记忆》 https://leetcode-cn.com/circle/discuss/jq9Zke/
本专栏致力于为Java开发者提供全面的数据结构与算法学习资源,涵盖从基础概念到高级应用的完整知识体系。通过系统性的学习和实践,帮助开发者提升编程能力,掌握解决复杂问题的核心技能。
- 🎯 系统性学习:从基础到进阶,循序渐进
- 💻 Java实现:所有代码示例均使用Java语言
- 🔥 实战导向:结合LeetCode经典题目
- 📊 可视化理解:丰富的图表和动画演示
- 🎨 美观排版:精心设计的文档格式
数据结构是计算机存储、组织数据的方式,是算法的基础。掌握各种数据结构的特点和应用场景,是成为优秀程序员的必经之路。
线性数据结构是指数据元素之间存在一对一关系的数据结构,元素按线性顺序排列。
数组结构示意图:
Index: [0] [1] [2] [3] [4]
Value: [12][45][78][23][56]
↑ ↑ ↑ ↑ ↑
连续的内存地址空间
- 特点:连续存储,支持随机访问
- 时间复杂度:访问O(1),插入/删除O(n)
- Java实现:
int[]、ArrayList
单链表结构示意图:
[Data|Next] -> [Data|Next] -> [Data|Next] -> null
| | |
节点1 节点2 节点3
双链表结构示意图:
null <- [Prev|Data|Next] <-> [Prev|Data|Next] <-> [Prev|Data|Next] -> null
- 特点:动态存储,插入删除高效
- 时间复杂度:访问O(n),插入/删除O(1)
- Java实现:
LinkedList
栈结构示意图:
| | <- top (栈顶)
| C |
| B |
| A |
|_____| <- bottom (栈底)
操作:LIFO (后进先出)
- 特点:后进先出(LIFO)
- 时间复杂度:push/pop/peek都是O(1)
- Java实现:
Stack、Deque
队列结构示意图:
出队 <- [A][B][C][D] <- 入队
front rear
操作:FIFO (先进先出)
- 特点:先进先出(FIFO)
- 时间复杂度:enqueue/dequeue都是O(1)
- Java实现:
Queue、LinkedList
非线性数据结构是指数据元素之间存在一对多或多对多关系的数据结构,形成复杂的层次或网状结构。
二叉树结构示意图:
A (根节点)
/ \
B C
/ \ / \
D E F G (叶子节点)
层次:
第0层: A
第1层: B C
第2层: D E F G
- 特点:每个节点最多有两个子节点
- 时间复杂度:搜索/插入/删除O(logn)~O(n)
- Java实现:
TreeMap、TreeSet
最大堆示意图:
90
/ \
80 70
/ \ / \
60 50 40 30
特点:父节点 >= 子节点 (最大堆)
数组表示:[90,80,70,60,50,40,30]
- 特点:完全二叉树,堆序性质
- 时间复杂度:插入/删除O(logn),查找最值O(1)
- Java实现:
PriorityQueue
无向图示意图:
A --- B
/| |\
/ | | \
D | | C
| | /
E --- F
邻接矩阵表示:
A B C D E F
A [ 0 1 0 1 1 0 ]
B [ 1 0 1 0 0 1 ]
C [ 0 1 0 0 0 1 ]
D [ 1 0 0 0 1 0 ]
E [ 1 0 0 1 0 1 ]
F [ 0 1 1 0 1 0 ]
- 特点:顶点和边的集合,表示复杂关系
- 时间复杂度:遍历O(V+E),最短路径O(V²)
- Java实现:
Map<Node, List<Node>>
哈希表结构示意图:
Hash函数:key → hash(key) % size → index
Key: "apple" → hash("apple") = 5 → index: 5 % 8 = 5
Key: "banana" → hash("banana")= 3 → index: 3 % 8 = 3
Table:
[0] → null
[1] → null
[2] → null
[3] → "banana" → value
[4] → null
[5] → "apple" → value
[6] → null
[7] → null
冲突处理(链地址法):
[3] → ["banana",value1] → ["grape",value2] → null
- 特点:基于键值对,快速查找
- 时间复杂度:平均O(1),最坏O(n)
- Java实现:
HashMap、HashSet
算法是解决问题的步骤和方法,是程序设计的核心。掌握各种算法的思想和实现,能够帮助我们高效地解决各种复杂问题。
排序算法是计算机科学中最基础也是最重要的算法之一,掌握各种排序算法的特点和应用场景至关重要。
| 算法 | 时间复杂度(平均) | 时间复杂度(最坏) | 空间复杂度 | 稳定性 |
|---|---|---|---|---|
| 冒泡排序 | O(n²) | O(n²) | O(1) | 稳定 |
| 选择排序 | O(n²) | O(n²) | O(1) | 不稳定 |
| 插入排序 | O(n²) | O(n²) | O(1) | 稳定 |
| 快速排序 | O(nlogn) | O(n²) | O(logn) | 不稳定 |
| 归并排序 | O(nlogn) | O(nlogn) | O(n) | 稳定 |
| 堆排序 | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
| 计数排序 | O(n+k) | O(n+k) | O(k) | 稳定 |
| 基数排序 | O(nk) | O(nk) | O(n+k) | 稳定 |
搜索算法用于在数据集合中查找特定元素,不同的搜索算法适用于不同的场景。
- 线性搜索:O(n) - 适用于无序数组
- 二分搜索:O(logn) - 适用于有序数组
- 哈希查找:O(1) - 适用于HashMap/HashSet
- 树搜索:O(logn) - 适用于二叉搜索树
- 图搜索:DFS/BFS - O(V+E)
图算法是处理图结构数据的重要工具,广泛应用于网络分析、路径规划等领域。
- 深度优先搜索(DFS):O(V+E)
- 广度优先搜索(BFS):O(V+E)
- Dijkstra算法:O((V+E)logV) - 单源最短路径
- Floyd-Warshall算法:O(V³) - 全源最短路径
- Bellman-Ford算法:O(VE) - 含负权边
- Prim算法:O(ElogV)
- Kruskal算法:O(ElogE)
- Kahn算法:O(V+E)
- DFS算法:O(V+E)
动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。
- 斐波那契数列:O(n)
- 爬楼梯:O(n)
- 最大子序和:O(n)
- 最长递增子序列(LIS):O(nlogn)
- 最长公共子序列(LCS):O(mn)
- 编辑距离:O(mn)
- 0-1背包:O(nW)
- 完全背包:O(nW)
- 多重背包:O(nWlogM)
- 最长回文子串:O(n²)
- 矩阵链乘法:O(n³)
贪心算法是一种在每一步选择中都采取在当前状态下最好或最优的选择,从而希望导致结果是最好或最优的算法。
- 活动选择问题:O(nlogn)
- 分数背包:O(nlogn)
- 最小生成树(Prim/Kruskal):O(ElogV)
- 霍夫曼编码:O(nlogn)
- 区间调度:O(nlogn)
分治算法是一种很重要的算法,字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题。
- 归并排序:O(nlogn)
- 快速排序:O(nlogn)
- 二分搜索:O(logn)
- 最大子数组和:O(nlogn)
- 最近点对:O(nlogn)
回溯算法是一种通过穷举所有可能情况来找到所有解的算法。当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择。
- N皇后问题:O(N!)
- 数独求解:O(9^(n*n))
- 全排列:O(n!)
- 子集生成:O(2^n)
- 组合问题:O(C(n,k))
字符串算法是处理文本数据的重要工具,广泛应用于文本搜索、模式匹配等领域。
- KMP算法:O(n+m) - 字符串匹配
- Rabin-Karp算法:O(n+m) - 字符串匹配
- 最长公共前缀:O(S) - S为所有字符串长度和
- 字典树(Trie):插入/查找 O(m)
- 后缀数组:O(nlogn)
数学算法是解决数学问题的计算方法,在编程中经常需要用到各种数学算法。
- 最大公约数(GCD):O(logn)
- 快速幂:O(logn)
- 素数筛选:O(nloglogn)
- 模运算:O(1)
- 组合数学:O(nlogn)
位运算是计算机中最底层的运算,掌握位运算技巧可以写出更高效的代码。
- 位运算基础:O(1)
- 状态压缩DP:O(n*2^m)
- 子集枚举:O(2^n)
- 位操作技巧:O(1)
高级数据结构算法是建立在基础数据结构之上的复杂算法,能够解决更复杂的问题。
- 并查集:O(α(n)) - 接近常数时间
- 线段树:O(logn) - 区间查询/更新
- 树状数组:O(logn) - 前缀和查询
- 平衡树(AVL/红黑树):O(logn)
- 跳表:O(logn)
LeetCode是程序员刷题的重要平台,通过系统性的刷题练习,可以快速提升算法能力。以下是按类型分类的经典题目。
数组是最基础的数据结构,掌握数组的各种操作技巧是算法学习的基础。
- 1. 两数之和 - 哈希表优化
- 26. 删除排序数组中的重复项 - 双指针
- 27. 移除元素 - 双指针
- 88. 合并两个有序数组 - 双指针
- 33. 搜索旋转排序数组 - 二分搜索
- 34. 在排序数组中查找元素的第一个和最后一个位置 - 二分搜索
- 35. 搜索插入位置 - 二分搜索
- 153. 寻找旋转排序数组中的最小值 - 二分搜索
- 15. 三数之和 - 排序+双指针
- 16. 最接近的三数之和 - 排序+双指针
- 18. 四数之和 - 排序+双指针
- 42. 接雨水 - 双指针
- 11. 盛最多水的容器 - 双指针
- 3. 无重复字符的最长子串 - 滑动窗口
- 76. 最小覆盖子串 - 滑动窗口
- 209. 长度最小的子数组 - 滑动窗口
- 438. 找到字符串中所有字母异位词 - 滑动窗口
链表是动态数据结构,掌握链表的操作技巧对于理解指针和递归非常重要。
- 206. 反转链表 - 迭代/递归
- 21. 合并两个有序链表 - 双指针
- 83. 删除排序链表中的重复元素 - 单指针
- 82. 删除排序链表中的重复元素 II - 双指针
- 141. 环形链表 - 快慢指针
- 142. 环形链表 II - 快慢指针
- 160. 相交链表 - 双指针
- 19. 删除链表的倒数第 N 个结点 - 快慢指针
- 234. 回文链表 - 快慢指针+反转
- 143. 重排链表 - 找中点+反转+合并
- 148. 排序链表 - 归并排序
- 23. 合并K个排序链表 - 分治/优先队列
栈和队列是重要的线性数据结构,在算法中有着广泛的应用。
- 20. 有效的括号 - 栈匹配
- 155. 最小栈 - 辅助栈
- 225. 用队列实现栈 - 设计问题
- 232. 用栈实现队列 - 设计问题
- 496. 下一个更大元素 I - 单调栈
- 503. 下一个更大元素 II - 单调栈
- 739. 每日温度 - 单调栈
- 84. 柱状图中最大的矩形 - 单调栈
- 94. 二叉树的中序遍历 - 递归/迭代
- 144. 二叉树的前序遍历 - 递归/迭代
- 145. 二叉树的后序遍历 - 递归/迭代
- 102. 二叉树的层序遍历 - BFS
- 104. 二叉树的最大深度 - DFS
- 111. 二叉树的最小深度 - BFS/DFS
- 226. 翻转二叉树 - DFS
- 101. 对称二叉树 - DFS
- 98. 验证二叉搜索树 - 中序遍历
- 700. 二叉搜索树中的搜索 - 二分搜索
- 701. 二叉搜索树中的插入操作 - 递归
- 450. 删除二叉搜索树中的节点 - 递归
- 112. 路径总和 - DFS
- 113. 路径总和 II - DFS+回溯
- 124. 二叉树中的最大路径和 - DFS
- 257. 二叉树的所有路径 - DFS+回溯
- 200. 岛屿数量 - DFS/BFS
- 695. 岛屿的最大面积 - DFS/BFS
- 994. 腐烂的橘子 - BFS
- 130. 被围绕的区域 - DFS/BFS
- 207. 课程表 - 拓扑排序
- 210. 课程表 II - 拓扑排序
- 547. 省份数量 - 并查集/DFS
- 684. 冗余连接 - 并查集
- 721. 账户合并 - 并查集
- 70. 爬楼梯 - 基础DP
- 198. 打家劫舍 - 线性DP
- 213. 打家劫舍 II - 环形DP
- 53. 最大子序和 - Kadane算法
- 300. 最长递增子序列 - LIS
- 1143. 最长公共子序列 - LCS
- 72. 编辑距离 - 字符串DP
- 5. 最长回文子串 - 区间DP
- 416. 分割等和子集 - 0-1背包
- 494. 目标和 - 0-1背包
- 322. 零钱兑换 - 完全背包
- 518. 零钱兑换 II - 完全背包
- 121. 买卖股票的最佳时机 - 状态机DP
- 122. 买卖股票的最佳时机 II - 状态机DP
- 123. 买卖股票的最佳时机 III - 状态机DP
- 188. 买卖股票的最佳时机 IV - 状态机DP
- 46. 全排列 - 回溯
- 47. 全排列 II - 回溯+去重
- 77. 组合 - 回溯
- 78. 子集 - 回溯
- 131. 分割回文串 - 回溯+动态规划
- 93. 复原IP地址 - 回溯
- 51. N 皇后 - 回溯
- 37. 解数独 - 回溯
- 435. 无重叠区间 - 贪心
- 452. 用最少数量的箭引爆气球 - 贪心
- 55. 跳跃游戏 - 贪心
- 45. 跳跃游戏 II - 贪心
- 28. 实现 strStr() - KMP算法
- 459. 重复的子字符串 - KMP算法
- 125. 验证回文串 - 双指针
- 5. 最长回文子串 - 中心扩展
- 647. 回文子串 - 中心扩展
- 136. 只出现一次的数字 - 异或运算
- 191. 位1的个数 - 位运算
- 338. 比特位计数 - 位运算+DP
- 461. 汉明距离 - 位运算
- 由易到难:从Easy开始,逐步提升到Hard
- 分类练习:按数据结构和算法类型分类刷题
- 反复练习:重要题目要反复练习,形成肌肉记忆
- 总结模板:每种题型都要总结解题模板
- 时间管理:每天固定时间刷题,保持连续性
- 记录总结:建立错题本,定期回顾总结
- LeetCode中国 - 主要刷题平台
- 牛客网 - 面试真题
- AcWing - 算法竞赛
- 洛谷 - 算法学习
- IDE:IntelliJ IDEA、Eclipse
- 调试:LeetCode插件、本地调试
- 版本控制:Git管理代码
- 笔记:Markdown记录学习心得
💡 记住:数据结构和算法是程序员的内功,需要持续练习和积累
🚀 建议:每天至少刷一道LeetCode,坚持100天必有收获
📚 资源:LeetCode中国 | 算法可视化
🎉 加油:相信通过系统性的学习,你一定能够掌握数据结构和算法的精髓!