刷题方案¶
作为一个以 Java 后台开发 为职业目标的初学者,你的刷题策略不能仅仅是“解出题目”,更需要体现出你对 Java 语言特性的理解以及良好的工程素养。
以下是为你定制的最佳刷题方案和语言建议:
一、 核心问题:选什么语言?¶
结论:毫无疑问,必须用 Java。
虽然 Python 代码更短,C++ 运行更快,但对于面试 Java 后台 岗位,使用 Java 刷题有巨大的战略优势:
- 证明熟练度: 面试官会考察你对 Java API 的熟悉程度(例如
ArrayListvsLinkedList,HashMap的使用,PriorityQueue的自定义排序等)。 - 避免认知割裂: 你的项目是 Java 写的,八股文背的是 JVM 和 JUC,如果算法用 Python 写,面试时需要在两种思维模式间切换,容易出错。
- 源码追问: 面试官经常会在你写完算法后,指着你用到的某个类问底层实现(比如:“你这里用了
HashMap,能讲讲它的扩容机制吗?”)。如果你用 Java 写,这种过渡非常自然。
二、 最佳刷题路线图 (分阶段执行)¶
不要一上来就从 LeetCode 第 1 题开始做,那是效率最低的方法。建议按照 “知识点分类 + 高频题优先” 的策略。
第一阶段:夯实地基 (2-3 周)¶
目标: 熟悉 Java 常用集合类的 API,掌握基本数据结构。
重点: 数组 (Array)、链表 (Linked List)、哈希表 (HashMap)。
- 必做动作: 不要在 IDE (IntelliJ IDEA) 里写代码,尝试在网页编辑器里写,习惯没有代码补全的环境。
- Java 关键点:
- 熟练掌握
String和StringBuilder的转换。 - 熟练掌握
List转Array,Array转List。 - 理解
==和.equals()在处理对象时的区别。
- 熟练掌握
第二阶段:专题突破 (1-2 个月)¶
目标: 掌握面试中最常见的算法模式(Pattern)。
策略: 按标签刷题。不要今天做一道数组,明天做一道动态规划。
推荐顺序及经典题(括号内为 LeetCode 题号):
-
双指针 (Two Pointers): 解决数组、链表问题。
- 例题: 两数之和 (1), 移动零 (283), 环形链表 (141)。
-
二分查找 (Binary Search): 简单但细节多。
- 例题: 二分查找 (704), 搜索插入位置 (35)。
-
树与递归 (Tree & DFS/BFS): 重中之重,后台开发处理层级数据最常用。
- 例题:二叉树的最大深度 (104), 翻转二叉树 (226), 层序遍历 (102)。
-
哈希表 (Hash Table): 空间换时间的核心。
- 例题: 有效的字母异位词 (242), 多数元素 (169)。
第三阶段:高频冲刺 (面试前 1 个月)¶
目标: 针对国内大厂面试风格进行突击。
工具: CodeTop (企业题库)。
- 国内面试不像国外那么随机,热题重复率极高。
- 去 CodeTop 查看“字节跳动”、“阿里”、“美团”等公司最近半年的高频题。
- 重点攻克: 前 100 高频题,必须烂熟于心(能手写 bug-free)。
三、 避坑指南 & 刷题心法¶
1. "五分钟法则"¶
如果一道题你 5 分钟 没有任何思路,直接看题解。
- 初学者最忌讳在一道题上死磕 2 小时,这会极大地打击自信心,且效率极低。你的目的是“学习模式”,而不是“发明算法”。
2. 理解 > 记忆 (不要死记代码)¶
- 错误做法: 背诵代码的每一行。
- 正确做法: 记住解题的“骨架”。例如,写 BFS (广度优先搜索) 时,脑子里应该立刻浮现出
Queue和while(!queue.isEmpty())的结构。
3. 利用 Java 特性“取巧”¶
面试时,合理利用 Java 标准库可以节省大量时间:
- 排序:
Arrays.sort()或Collections.sort()。 - 栈: 不要用
Stack类(它是遗留类,性能差),要用Deque<Integer> stack = new ArrayDeque<>();。 - 大顶堆/小顶堆:
PriorityQueue,例如new PriorityQueue<>((a, b) -> b - a)实现大顶堆。
4. 坚持“三遍刷题法”¶
- 第一遍:看题解,理解思路,照着敲出来。
- 第二遍:(次日)不看题解,凭记忆和理解独立写出来。
- 第三遍:(一周后)复习,如果还能写出来,说明真正掌握了。
四、 Java 后台面试必会的“数据结构映射”¶
在 Java 后台面试中,算法题往往对应着实际场景,请务必建立以下联系:
| 算法/数据结构 | Java 实现类 | 后台开发实际场景 |
|---|---|---|
| 动态数组 | ArrayList |
绝大多数列表数据的存储 |
| 链表 | LinkedList |
频繁增删的场景 (如 LRU 缓存设计) |
| 哈希映射 | HashMap / ConcurrentHashMap |
缓存、快速查找、Spring Bean 容器 |
| 树 (Tree) | TreeMap (红黑树) |
数据库索引 (B+树)、有序数据存储 |
| 堆 (Heap) | PriorityQueue |
任务调度系统、延时队列 |
总结¶
作为 Java 后台初学者,你的战略应该是:
- 锁定 Java 语言。
- 前期按标签刷(数组 -> 链表 -> 树 -> 搜索)。
- 后期按CodeTop 高频榜刷。
- 遇到难题不要死磕,看懂答案并重复练习。
Java 刷题常用 API 速查表¶
这份 “Java 刷题常用 API 速查表” 是专为 LeetCode 算法题定制的。
在实际的 Java 后台开发中,我们可能会用到复杂的 Stream 流或第三方工具库(如 Guava/Apache Commons),但在刷题和机试中,尽量只使用 JDK 原生提供的、最基础、最高效的方法。
以下是按数据结构分类的核心 API 讲解:
1. 数组与字符串 (Array & String)¶
这是最基础的部分,注意 Java 中 String 是不可变的,频繁修改必须用 StringBuilder。
数组 (Array)¶
Java
// 声明与初始化
int[] arr = new int[10]; // 默认初始化为0
int[] nums = {1, 2, 3}; // 直接赋值
int len = arr.length; // 注意:没有括号()
// 排序 (Dual-Pivot Quicksort)
Arrays.sort(arr); // O(NlogN)
// 填充
Arrays.fill(arr, -1); // 将数组全部初始化为 -1
// 转列表 (面试常考)
// 注意:如果是 int[] 这种基本类型数组,Arrays.asList() 会出问题,建议手动循环或用流
List<Integer> list = new ArrayList<>();
for (int num : arr) list.add(num);
字符串 (String)¶
面试坑点:不要在循环里用 + 拼接字符串,性能极差。
Java
String s = "Hello World";
// 获取信息
char c = s.charAt(2); // 获取第2个字符
int len = s.length(); // 注意:这里有括号()
int idx = s.indexOf("World"); // 查找子串位置,找不到返回 -1
// 转换
char[] chars = s.toCharArray(); // 转成字符数组(很常用,因为String不能直接改)
String sub = s.substring(1, 4); // 截取索引 1 到 3 的子串 (左闭右开 [1, 4))
String[] parts = s.split(" "); // 按空格分割
// StringBuilder (修改字符串必用)
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append(10);
sb.reverse(); // 反转字符串 (解决回文题神器)
String res = sb.toString(); // 变回 String
2. 动态列表 (ArrayList)¶
比数组更灵活,面试中 90% 的情况用它代替数组。
Java
// 推荐使用接口 List 接收
List<Integer> list = new ArrayList<>();
// 增删改查
list.add(10); // 加到末尾
list.add(0, 5); // 插到开头 (效率低,O(N))
int val = list.get(2); // 获取索引2的元素
list.set(2, 99); // 修改索引2的值为99
list.remove(list.size() - 1); // 删除最后一个元素
// 常用工具
int size = list.size();
boolean hasVal = list.contains(10); // O(N) 线性查找
Collections.sort(list); // 排序 (TimSort)
Collections.reverse(list); // 反转
3. 哈希表 (HashMap / HashSet)¶
刷题神器,用来降低时间复杂度(通常将 O(N^2) 降为 O(N))。
HashMap (键值对)¶
Java
Map<String, Integer> map = new HashMap<>();
// 基础操作
map.put("apple", 1);
int val = map.get("apple");
boolean hasKey = map.containsKey("apple"); // O(1)
// ★ 高频技巧:统计频率 (Word Count)
// 如果 key 存在则 +1,不存在则设为 0 再 +1
map.put(key, map.getOrDefault(key, 0) + 1);
// 遍历 (面试尽量用 entrySet,效率最高)
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String k = entry.getKey();
Integer v = entry.getValue();
}
HashSet (去重集合)¶
Java
Set<Integer> set = new HashSet<>();
set.add(1);
boolean exists = set.contains(1); // O(1)
4. 栈与队列 (Stack & Queue)¶
重要修正: 永远不要用 Stack 类(它是 Java 1.0 的遗留类,带锁,性能差)。请统一使用 Deque (双端队列) 接口。
栈 (Last-In-First-Out)¶
Java
// 使用 ArrayDeque 实现栈
Deque<Integer> stack = new ArrayDeque<>();
stack.push(1); // 压栈 (等同于 addFirst)
int top = stack.pop(); // 弹栈 (等同于 removeFirst),栈空会抛异常
int peek = stack.peek(); //以此查看栈顶元素但不删除
boolean isEmpty = stack.isEmpty();
队列 (First-In-First-Out)¶
Java
// 使用 ArrayDeque 或 LinkedList 实现队列
Queue<Integer> queue = new ArrayDeque<>();
// 或者 Queue<Integer> queue = new LinkedList<>(); (如果需要中间插入)
queue.offer(1); // 入队 (推荐用 offer 而不是 add,满了返回 false 不抛异常)
int head = queue.poll(); // 出队 (推荐用 poll 而不是 remove,空了返回 null)
int peek = queue.peek(); // 查看队头
5. 优先队列 (PriorityQueue / Heap)¶
用于解决 Top K 问题 或 第 K 大/小元素。底层是二叉堆。
Java
// 默认是:小顶堆 (Min Heap),队头是最小值
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
// ★ 面试必背:大顶堆 (Max Heap) 写法
// 使用 Lambda 表达式自定义比较器:(b - a) 表示降序
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);
// 操作
maxHeap.offer(10);
maxHeap.offer(5);
int max = maxHeap.poll(); // 弹出 10
6. 数学与数字处理¶
Java
// 比较大小
Math.max(a, b);
Math.min(a, b);
// 绝对值
Math.abs(-10);
// ★ 边界值 (防止溢出常用)
int maxInt = Integer.MAX_VALUE; // 2^31 - 1
int minInt = Integer.MIN_VALUE;
// 字符转数字
int digit = '5' - '0'; // 结果是整数 5
7. 刷题/面试中的注意事项¶
-
自动拆装箱 (Autoboxing) 的坑:
在 Integer 和 int 之间比较时,特别小心 null。
Java
Integer a = null; // if (a == 1) ... // 抛出 NullPointerException -
对象比较:
比较对象(包括 String, Integer 等包装类)的值是否相等,永远用 .equals(),不要用 ==。
例外:LeetCode 中 Integer 缓存池 (-128 到 127) 虽用 == 有效,但面试写 == 会被认为基础不牢。
-
大数处理:
如果题目涉及超过 long 范围的数字(如大数相加),需使用 BigInteger 或直接用字符串模拟。
总结 & 你的下一步¶
建议你把这篇内容收藏或复制到你的笔记软件里。
下一步实战建议:
为了让你快速上手,你想让我给你出一道最经典的 Java 入门算法题(比如“有效的括号”),并用上面提到的 Deque 栈结构写一个标准范例给你看吗?这样你能直接看到这些 API 是如何组合使用的。