Java 常用 API 分类总结(算法竞赛考前速记篇)- 适用于算法竞赛(如 CCF CSP、蓝桥杯、NOI)
以下是Java 常用 API 的系统性总结,特别适用于算法竞赛(如 CCF CSP、蓝桥杯、NOI)场景。按照功能分类,并给出代表性方法及简要用法说明,方便复习与带入考场:
✅ Java 常用 API 分类总结(算法竞赛篇)
常见数据类型的数据范围与默认值
当然可以!以下是 Java 中常见数据类型的数据范围与默认值总结,适合你背诵、练习和面试使用:
✅ 一、Java 基本数据类型总结(8种)
类型 | 占用空间 | 范围(含正负) | 默认值 |
---|---|---|---|
byte | 1 字节 | -128 ~ 127 | 0 |
short | 2 字节 | -32,768 ~ 32,767 | 0 |
int | 4 字节 | -2³¹ ~ 2³¹-1(-2,147,483,648 ~ 2,147,483,647) | 0 |
long | 8 字节 | -2⁶³ ~ 2⁶³-1(约 ±9 × 10¹⁸) | 0L |
float | 4 字节 | 约 ±3.4 × 10³⁸(7位有效数字) | 0.0f |
double | 8 字节 | 约 ±1.8 × 10³⁰⁸(15位有效数字) | 0.0d |
char | 2 字节 | 0 ~ 65535(Unicode 字符) | '\u0000' |
boolean | 1 位(JVM 按 1 字节处理) | true / false | false |
✅ 二、常用封装类与常量(用于边界判断)
类型 | 最大值 | 最小值 | 示例 |
---|---|---|---|
Integer | Integer.MAX_VALUE = 2147483647 | Integer.MIN_VALUE = -2147483648 | int a = Integer.MAX_VALUE; |
Long | Long.MAX_VALUE = 9223372036854775807L | Long.MIN_VALUE = -9223372036854775808L | |
Double | Double.MAX_VALUE ≈ 1.79769e+308 | Double.MIN_VALUE ≈ 4.9e-324(最小正数) | 注意 Double.MIN_VALUE 是正数 |
Float | Float.MAX_VALUE ≈ 3.40282e+38 | Float.MIN_VALUE ≈ 1.4e-45 | 同上 |
Character | Character.MAX_VALUE = 65535 ('\uffff' ) | Character.MIN_VALUE = 0 ('\u0000' ) |
✅ 三、如何选择数据类型?(实用建议)
场景 | 推荐类型 | 原因 |
---|---|---|
统计、计数 | int / long | 小数据用 int ,大数据(>10⁹)用 long |
精确小数运算 | BigDecimal | 如货币计算,避免精度丢失 |
浮点计算 | double | 精度高于 float |
布尔开关 | boolean | 性能优,语义清晰 |
单个字符 | char | 适合处理字符型数据 |
✅ 四、经典面试题:Integer.MIN_VALUE
的绝对值是多少?
System.out.println(Math.abs(Integer.MIN_VALUE)); // 输出仍为 -2147483648
这是因为 abs()
溢出!因为 -2147483648
没有正数对应(超出 int 正范围)。
✅ 五、背诵口诀助记法:
byte 短 short 刚好 32k,
int 四字节到 21亿。
long 八字节超千万亿,
float double 飘到天际。
char 是 Unicode,boolean 真或假。
1️⃣ 字符串处理(String
类)
方法 | 用途 | 示例 |
---|---|---|
length() | 获取字符串长度 | "abc".length() -> 3 |
charAt(i) | 获取索引 i 处字符 | "abc".charAt(1) -> 'b' |
substring(start, end) | 截取子串(左闭右开) | "abcdef".substring(1,4) -> "bcd" |
indexOf(str) | 第一次出现位置 | "ababc".indexOf("ab") -> 0 |
lastIndexOf(str) | 最后一次出现位置 | "ababc".lastIndexOf("ab") -> 2 |
contains(str) | 是否包含 | "abc".contains("b") -> true |
split(regex) | 按正则分割为数组 | "a,b,c".split(",") -> [a, b, c] |
equals(str) | 是否相等 | "abc".equals("abc") -> true |
compareTo(str) | 字典序比较 | "abc".compareTo("abd") -> -1 |
toCharArray() | 转为字符数组 | "abc" -> ['a','b','c'] |
replace(old, new) | 替换子串 | "aabb".replace("a", "c") -> "ccbb" |
trim() | 去除首尾空格 | " a b ".trim() -> "a b" |
toLowerCase() | 转小写 | "ABC".toLowerCase() -> "abc" |
toUpperCase() | 转大写 | "abc".toUpperCase() -> "ABC" |
startsWith(str) | 以某串开头 | "abc".startsWith("a") -> true |
endsWith(str) | 以某串结尾 | "abc".endsWith("c") -> true |
2️⃣ 高效字符串拼接(StringBuilder
/ StringBuffer
)
方法 | 用途 |
---|---|
append(str) | 添加字符串 |
insert(pos, str) | 插入字符串 |
delete(start, end) | 删除子串 |
reverse() | 翻转字符串 |
toString() | 转回字符串 |
⚠️
StringBuilder
非线程安全,StringBuffer
线程安全(但慢)。
3️⃣ 数学计算(Math
类)
方法 | 说明 |
---|---|
abs(x) | 绝对值 |
max(a, b) / min(a, b) | 最大 / 最小值 |
pow(a, b) | a 的 b 次幂 |
sqrt(x) | 平方根 |
cbrt(x) | 立方根 |
ceil(x) | 向上取整 |
floor(x) | 向下取整 |
round(x) | 四舍五入(返回 long ) |
random() | 返回 [0,1) 间随机数 |
log(x) / log10(x) | 自然对数 / 常用对数 |
sin(x) , cos(x) , tan(x) | 三角函数(弧度) |
4️⃣ 数组处理(Arrays
工具类)
方法 | 说明 |
---|---|
sort(array) | 升序排序 |
binarySearch(array, key) | 二分查找(有序数组) |
fill(array, val) | 全部填充为 val |
copyOf(arr, newLen) | 拷贝前 newLen 个元素 |
equals(a, b) | 比较两个数组是否完全相等 |
toString(arr) | 数组转字符串 |
asList(T... arr) | 数组转固定长度 List |
5️⃣ 集合框架
List(ArrayList
/ LinkedList
)
方法 | 说明 |
---|---|
add(e) | 添加元素 |
remove(i) | 删除索引 i 元素 |
get(i) | 获取元素 |
set(i, e) | 修改元素 |
size() | 获取大小 |
contains(e) | 是否包含元素 |
Set(HashSet
/ TreeSet
)
方法 | 说明 |
---|---|
add(e) | 添加元素 |
remove(e) | 移除元素 |
contains(e) | 是否存在 |
size() | 元素个数 |
first() / last() | TreeSet 中的最小 / 最大值 |
ceiling(e) | ≥e 的最小值 |
floor(e) | ≤e 的最大值 |
✅ 一、常见 Set 实现类对比
类名 | 是否有序 | 是否允许 null | 是否线程安全 | 底层结构 |
---|---|---|---|---|
HashSet | ❌ 无序 | ✅ 允许一个 | ❌ 不安全 | 哈希表 |
LinkedHashSet | ✅ 插入顺序 | ✅ 允许一个 | ❌ 不安全 | 哈希表 + 双向链表 |
TreeSet | ✅ 升序 | ❌ 不允许 | ❌ 不安全 | 红黑树(平衡二叉树) |
✅ 二、常用 Set API 汇总
功能 | 示例代码 | 说明 |
---|---|---|
初始化 | Set<Integer> set = new HashSet<>(); | 常用 HashSet |
添加元素 | set.add(x); | 添加元素(若重复则不变) |
删除元素 | set.remove(x); | 删除元素(若无也不报错) |
是否包含 | set.contains(x); | 判断元素是否存在 |
获取大小 | set.size(); | 元素个数 |
清空集合 | set.clear(); | 清空所有元素 |
是否为空 | set.isEmpty(); | 是否为空 |
遍历元素 | for (int x : set) | 常用 for-each 遍历 |
转为 List | new ArrayList<>(set); | 若需排序或索引操作 |
集合并集(新增) | set.addAll(otherSet); | 将另一个集合元素加入本集合 |
集合交集(保留) | set.retainAll(otherSet); | 只保留两集合都存在的元素 |
集合差集(去除) | set.removeAll(otherSet); | 去除在 otherSet 中也有的元素 |
✅ 三、典型代码模板
📌 1. 初始化 + 去重存储
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(2); // 无效重复
System.out.println(set); // 输出 [1, 2]
📌 2. 遍历 + 判断是否存在
for (int x : set) {if (x == 3) System.out.println("存在");
}
📌 3. 使用 TreeSet
实现自动排序
Set<String> treeSet = new TreeSet<>();
treeSet.add("banana");
treeSet.add("apple");
System.out.println(treeSet); // [apple, banana]
✅ 四、适配题型速查
题型类别 | 用法建议 | 举例题目 |
---|---|---|
去重统计 | 用 HashSet 存入后 size() | [CSP] 数字种类、集合大小 |
判断是否重复 | set.contains(x) + set.add(x) | 力扣 217、219 |
保持顺序去重 | 用 LinkedHashSet | 输出按插入顺序的唯一值序列 |
需要有序输出 | 用 TreeSet + 自动排序 | 力扣 349、350(交集类) |
✅ 五、背诵口诀:“增删查,去重快,TreeSet 排序不带盖!”
✅ 六、你可以练习的题目(推荐)
平台 | 题目 ID / 名称 | 涉及 API |
---|---|---|
力扣 | 217. 存在重复元素 | set.contains() |
力扣 | 349. 两个数组的交集 | set.retainAll() |
力扣 | 705. 设计哈希集合 | 手写 Set 底层结构 |
CSP | 出现过的数、不同的数种类统计 | set.add() + set.size() |
Map(HashMap
/ TreeMap
)
方法 | 说明 |
---|---|
put(key, val) | 添加键值对 |
get(key) | 获取值(无则返回 null) |
getOrDefault(key, def) | 若无该 key,返回默认值 |
containsKey(key) | 是否包含键 |
keySet() | 所有 key 集合 |
values() | 所有 value |
entrySet() | 所有 entry(用于遍历) |
频次统计(CSP常见)
map.put(x, map.getOrDefault(x, 0) + 1);
6️⃣ Collections 工具类(操作集合)
方法 | 说明 |
---|---|
sort(list) | 升序排序 |
reverse(list) | 反转列表 |
shuffle(list) | 随机打乱 |
frequency(list, obj) | 统计出现次数 |
swap(list, i, j) | 交换元素 |
rotate(list, k) | 向右旋转 k 位 |
max(list) / min(list) | 最大 / 最小值 |
7️⃣ 优先队列(PriorityQueue
)
PriorityQueue<Integer> pq = new PriorityQueue<>(); // 默认小根堆
pq.offer(3); pq.offer(1); pq.offer(2);
pq.peek(); // 1
pq.poll(); // 弹出最小的 1
自定义大根堆:
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);
8️⃣ 位运算(Integer
类)
方法 | 说明 |
---|---|
bitCount(i) | 二进制中 1 的个数 |
highestOneBit(i) | 最高位的 1 的值(如 1000) |
lowestOneBit(i) | 最低位的 1 的值(如 0001) |
toBinaryString(i) | 二进制表示 |
parseInt(s, radix) | 任意进制转十进制 |
toHexString(i) | 十六进制表示 |
9️⃣ 大数处理
BigInteger
方法 | 说明 |
---|---|
add() / subtract() / multiply() / divide() | 四则运算 |
mod() | 取模 |
pow(n) | 幂 |
compareTo(BigInteger) | 比较大小 |
gcd() | 最大公约数 |
isProbablePrime(certainty) | 判断素数(概率) |
BigInteger a = new BigInteger("123456789");
BigInteger b = new BigInteger("987654321");
a.add(b).toString(); // 字符串输出
BigDecimal
方法 | 说明 |
---|---|
add() , subtract() , multiply() , divide() | 高精度小数运算 |
setScale(n, RoundingMode) | 设置小数位数 |
compareTo() | 比较大小 |
🔟 时间函数
方法 | 说明 |
---|---|
System.currentTimeMillis() | 当前毫秒时间戳 |
System.nanoTime() | 纳秒时间戳(高精度测时) |
LocalDateTime.now() | 当前时间 |
ChronoUnit.SECONDS.between(start, end) | 时间间隔 |
🔟+1 正则表达式处理
类 | 方法 |
---|---|
Pattern.compile(regex) | 编译正则 |
matcher(str) | 创建匹配器 |
find() / group() | 匹配和提取子串 |
matches() | 整体匹配是否成功 |
🔟+2 输入输出(Scanner
, BufferedReader
, PrintWriter
)
类 | 方法 |
---|---|
Scanner | next() , nextLine() , nextInt() |
BufferedReader | 高效读取(支持 readLine() ) |
PrintWriter | 快速输出,println() 、flush() |
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(System.out);
String s = br.readLine();
out.println(s);
out.flush();
常考模块
自定义排序
你提的问题非常好!作为初学者,理解 Arrays.sort()
和 Collections.sort()
的区别与适用场景,对于写出更规范、稳定、灵活的排序代码至关重要。以下是详细解释和通用解法整理👇
✅ 一、Arrays.sort()
和 Collections.sort()
有什么区别?
比较点 | Arrays.sort() | Collections.sort() |
---|---|---|
适用对象 | 数组(如 int[] 、String[] 、Integer[] ) | List(如 ArrayList 、LinkedList ) |
所在包 | java.util.Arrays | java.util.Collections |
排序方式 | 默认升序;支持传入比较器 Comparator | 默认升序;也支持传入比较器 Comparator |
是否稳定排序 | 对对象数组使用 TimSort (稳定) | 使用 List.sort() ,底层同样是 TimSort (稳定) |
是否可以混用 | ❌ 不可以直接混用 | ✅ List 和 Collections.sort() 是配套的 |
🚫 不可以这样混用:
List<Integer> list = new ArrayList<>();
Arrays.sort(list); // ❌ 错误,Arrays.sort 不能用于 List
✅ 正确用法:
int[] arr = new int[]{5, 2, 3};
Arrays.sort(arr); // 用于基本类型数组List<Integer> list = new ArrayList<>(List.of(5, 2, 3));
Collections.sort(list); // 用于 List
✅ 二、二者的典型应用对比
🧩 排序数组 → 用 Arrays.sort()
int[] arr = {4, 2, 9};
Arrays.sort(arr); // 升序:[2, 4, 9]
🧩 排序对象数组 → 仍用 Arrays.sort()
Student[] stu = ...;
Arrays.sort(stu, (a, b) -> b.score - a.score); // 按成绩降序
🧩 排序 List → 用 Collections.sort()
或 Java 8 的 list.sort()
List<String> list = new ArrayList<>(List.of("cat", "apple", "banana"));
Collections.sort(list); // 默认字典序
等价于 Java 8 写法:
list.sort(String::compareTo); // 同样是字典序
✅ 三、是否可以用 Collections.sort()
替代 Arrays.sort()
?
🟡 不能直接替代! 因为它们的参数类型不同!
Arrays.sort()
适用于 数组(如int[]
,Integer[]
,String[]
等)Collections.sort()
适用于 List(如ArrayList
,LinkedList
)
但你可以将数组转成 List 来使用 Collections.sort()
(用于对象类型数组):
✅ 数组转 List 再排序(适用于对象数组)
Integer[] arr = {5, 2, 9};
List<Integer> list = Arrays.asList(arr);
Collections.sort(list); // 排序后 arr 也变化(共享内存)
⚠️ 注意: Arrays.asList()
返回的是一个固定长度的列表,不能增删元素,只能排序或修改已有元素。
✅ 四、初学者建议记忆总结
想排序什么? | 用什么? | 支持自定义比较器? | 是否稳定? |
---|---|---|---|
int[] / double[] | Arrays.sort() | ❌ | ✅ |
Integer[] / 对象数组 | Arrays.sort(arr, cmp) | ✅ | ✅ |
List(ArrayList) | Collections.sort() / list.sort() | ✅ | ✅ |
Map | 转为 entrySet() 的 List 后排序 | ✅ | ✅ |
✨ 五、通用排序封装函数(建议记忆)
// 通用对象排序(List)
public static <T> void sortList(List<T> list, Comparator<T> cmp) {Collections.sort(list, cmp);
}// 通用数组排序(对象数组)
public static <T> void sortArray(T[] arr, Comparator<T> cmp) {Arrays.sort(arr, cmp);
}
在 Java 中进行“自定义排序”,常用于对数组、对象集合(如 List
)等进行灵活的排序。CSP 考试中,常见场景包括:
- 对多个字段排序(如先按成绩,再按学号)
- 自定义结构(如 Pair)排序
- 降序 / 升序控制
✅ 一、对数组进行自定义排序(基本类型)
import java.util.*;public class CustomSortArray {public static void main(String[] args) {Integer[] arr = {5, 2, 8, 1, 9};// 降序排序Arrays.sort(arr, (a, b) -> b - a);System.out.println(Arrays.toString(arr)); // [9, 8, 5, 2, 1]}
}
注意:
int[]
不能直接使用 Lambda 表达式,必须使用Integer[]
对象数组。
✅ 二、自定义结构排序(如 Pair)
import java.util.*;class Pair {int id, score;public Pair(int id, int score) {this.id = id;this.score = score;}@Overridepublic String toString() {return "(" + id + "," + score + ")";}
}public class CustomSortPair {public static void main(String[] args) {List<Pair> list = new ArrayList<>();list.add(new Pair(1, 90));list.add(new Pair(3, 80));list.add(new Pair(2, 90));// 排序规则:先按 score 降序,再按 id 升序Collections.sort(list, (a, b) -> {if (a.score != b.score) return b.score - a.score; // 降序return a.id - b.id; // 升序});for (Pair p : list) {System.out.println(p);}}
}
✅ 三、二维数组排序(常见于模拟/DP)
import java.util.*;public class CustomSort2DArray {public static void main(String[] args) {int[][] data = {{1, 90},{2, 100},{3, 90}};// 按第二列降序,再按第一列升序Arrays.sort(data, (a, b) -> {if (a[1] != b[1]) return b[1] - a[1];return a[0] - b[0];});for (int[] row : data) {System.out.println(Arrays.toString(row));}}
}
✅ 四、优先队列中的自定义排序(堆)
import java.util.*;public class CustomPriorityQueue {public static void main(String[] args) {// 最小堆按第一维升序,第二维降序PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> {if (a[0] != b[0]) return a[0] - b[0];return b[1] - a[1];});pq.offer(new int[]{2, 100});pq.offer(new int[]{1, 80});pq.offer(new int[]{2, 90});while (!pq.isEmpty()) {System.out.println(Arrays.toString(pq.poll()));}}
}
📌 总结:常用模板
// Arrays.sort + Lambda
Arrays.sort(array, (a, b) -> {// 优先级:先按某字段,再按其他字段return a[0] - b[0]; // 升序 / b[0] - a[0] 降序
});// List + Collections.sort
Collections.sort(list, (a, b) -> {if (a.score != b.score) return b.score - a.score;return a.id - b.id;
});// PriorityQueue + 自定义比较器
PriorityQueue<Node> pq = new PriorityQueue<>((a, b) -> a.weight - b.weight);
以下是为 CCF CSP 考试 精心整理的「常见排序题速查表」,包含常考题型、解题策略、排序维度、API 示例等,帮助你快速定位解题方案。
✅ 一、速查表概览(按题型分类)
题型类别 | 排序关键 | 排序维度 | 示例题目 | 典型排序语句 |
---|---|---|---|---|
成绩/统计排序 | 值大小 | 降序或多字段 | 成绩排序、热度统计等 | Collections.sort(list, (a,b)->b.score-a.score) |
时间线排序 | 时间戳 | 升序 | 日志记录、任务调度等 | Arrays.sort(arr, Comparator.comparingInt(a -> a.time)) |
坐标排序 | x/y轴 | 多字段(先 x 后 y) | 坐标扫描、区间合并等 | Arrays.sort(points, (a,b)->a[0]==b[0]?a[1]-b[1]:a[0]-b[0]) |
编号优先 | 编号 | 按编号升序 | 按原始输入顺序输出 | Collections.sort(list, Comparator.comparingInt(a->a.id)) |
并查集/连通块 | 集合大小 | 降序或升序 | 连通块排序输出 | 自定义结构 + 统计 + 排序 |
哈希计数 | 次数 | 降序 + 值本身升序 | 频率统计、单词计数等 | 统计完后 List<Map.Entry> 排序 |
✅ 二、各类型题型详解与模板
1️⃣ 成绩类排序(权重/成绩/频次)
例题:
- 成绩排行
- 词频统计
class Student {int id, score;
}Collections.sort(list, (a, b) -> {if (a.score != b.score) return b.score - a.score;return a.id - b.id;
});
2️⃣ 时间类排序(时间戳、操作先后)
例题:
- 日志排序
- 任务调度优先队列
Arrays.sort(events, (a, b) -> a.time - b.time); // 按时间升序
或使用对象:
class Event {int time, id;
}
Collections.sort(list, Comparator.comparingInt(e -> e.time));
3️⃣ 坐标/区间排序
例题:
- 扫描线、区间覆盖、最大重叠区间
Arrays.sort(intervals, (a, b) -> {if (a[0] != b[0]) return a[0] - b[0]; // 起点升序return a[1] - b[1]; // 终点升序
});
4️⃣ Map排序(基于统计结果)
例题:
- 词频统计
- 热度排序
Map<Integer, Integer> count = new HashMap<>();
for (int x : arr) count.put(x, count.getOrDefault(x, 0) + 1);List<Map.Entry<Integer, Integer>> list = new ArrayList<>(count.entrySet());// 按频率降序、数值升序排序
Collections.sort(list, (a, b) -> {if (!a.getValue().equals(b.getValue()))return b.getValue() - a.getValue();return a.getKey() - b.getKey();
});
5️⃣ 并查集/连通块大小排序
例题:
- 社交网络连通块分析
- 亲戚关系等题
// 每个集合统计 size[]
// 然后将 size 按 root 排序
List<int[]> groups = new ArrayList<>();
for (int i = 1; i <= n; i++) {if (find(i) == i) groups.add(new int[]{i, size[i]});
}
groups.sort((a, b) -> b[1] - a[1]); // 按集合大小降序
6️⃣ 字典序排序(字符串或数组)
例题:
- 最小字典序拼接
- 拼接序列/排序
Arrays.sort(strings); // 默认字典序
Arrays.sort(strings, Comparator.reverseOrder()); // 字典序逆序
✅ 三、优先队列(堆)排序应用速查
需求类型 | 排序维度 | 声明语句 |
---|---|---|
最小值优先队列 | 值升序 | PriorityQueue<Integer> pq = new PriorityQueue<>(); |
最大值优先队列 | 值降序 | PriorityQueue<Integer> pq = new PriorityQueue<>((a,b)->b-a); |
多字段堆排序 | 数组 or 对象 | PriorityQueue<int[]> pq = new PriorityQueue<>((a,b)->{...}); |
✅ 四、常用 Java API 排序参考
用法 | 示例代码 |
---|---|
数组默认排序 | Arrays.sort(arr); |
对象数组排序 | Arrays.sort(objArr, (a, b) -> ...); |
List 排序 | Collections.sort(list, (a, b) -> ...); |
Map 排序(按值) | 见上面 Map 示例 |
PriorityQueue 自定义顺序 | new PriorityQueue<>((a,b) -> ...) |
📌 附:CCF CSP 排序常见题目清单(历年)
年份 | 题目名称 | 排序类型 |
---|---|---|
202206 | 通信网络 | 拓扑序 / 时间戳 |
202012 | 直播获奖名单 | 词频统计 + 排序 |
201809 | 元素选择器 | DOM序树结构排序 |
201712 | 游戏 | 结构排序 + 计分 |
201703 | 学生排队 | 优先队列 / 模拟 |
🔐 五、哈希/计数
HashMap
,HashSet
:用于快速查找TreeMap
,TreeSet
:自动排序Map.getOrDefault(k, v)
:避免空指针int[] cnt = new int[m + 1];
:模拟 HashMap 的计数数组,常用于编号有限的场景(如 CSP)
🧩 六、模拟题常用
Scanner
:快速读入StringTokenizer
(复杂输入场景)或BufferedReader
- 多维数组处理:
int[][] arr = new int[n][m];
- 模拟移动:方向数组
dx/dy
🔄 七、并查集(Union-Find)
int[] fa = new int[n];
for (int i = 0; i < n; i++) fa[i] = i;int find(int x) { return fa[x] == x ? x : (fa[x] = find(fa[x])); }void union(int x, int y) { fa[find(x)] = find(y); }
🌉 八、图论常用
✅ 图存储
- 邻接表:
List<List<Integer>> graph = new ArrayList<>();
- 邻接矩阵:
int[][] graph = new int[n][n];
✅ 遍历
- DFS / BFS 模板
Queue<Integer> q = new LinkedList<>();
📐 九、动态规划(DP)
- 通常使用
int[]
,int[][]
进行状态压缩或转移 - 可用
Arrays.fill()
进行初始化 - 多维数组状态转移举例:
dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]);
💡 十、贪心算法
- 常用
Arrays.sort()
或Collections.sort()
后进行策略判断 - 自定义排序:
Arrays.sort(arr, (a, b) -> a[0] - b[0]);
- 优先队列(堆):
PriorityQueue<Integer> pq = new PriorityQueue<>();
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
pq.offer(x); pq.poll(); pq.peek();
🧮 十一、常用工具类
功能 | API |
---|---|
比较两个对象 | Objects.equals(a, b) |
大整数运算 | BigInteger (如加减乘除、取模、幂) |
高精度小数 | BigDecimal |
Java API 使用示例代码
当然可以,下面我将针对 CSP 常考模块(字符串处理、模拟、哈希、排序、并查集、图、DP、贪心)分别提供一两个典型题目的Java API 使用示例代码,方便你快速上手实战题目。
✅ 一、字符串处理 - 示例题:“单词统计”
题目描述:给定一段英文文本,统计不同单词出现次数(不区分大小写,去除标点)。
import java.util.*;public class WordCount {public static void main(String[] args) {Scanner sc = new Scanner(System.in);String text = sc.nextLine().toLowerCase().replaceAll("[^a-z ]", " ");String[] words = text.split("\\s+");Map<String, Integer> count = new HashMap<>();for (String word : words) {if (!word.isEmpty()) {count.put(word, count.getOrDefault(word, 0) + 1);}}count.forEach((k, v) -> System.out.println(k + ": " + v));}
}
✅ 二、模拟 - 示例题:“排队打水”
题目描述:n 个人排队,每个人打水需要 t[i]
分钟,问最小总等待时间。
import java.util.*;public class WaterQueue {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int[] t = new int[n];for (int i = 0; i < n; i++) t[i] = sc.nextInt();Arrays.sort(t); // 排序是贪心核心long res = 0;for (int i = 0; i < n; i++) {res += (long) t[i] * (n - i - 1); // 模拟等待时间}System.out.println(res);}
}
✅ 三、哈希 - 示例题:“出现次数统计”
题目描述:输入 n 个整数,输出每个数的出现次数。
import java.util.*;public class FrequencyCount {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();Map<Integer, Integer> map = new HashMap<>();for (int i = 0; i < n; i++) {int x = sc.nextInt();map.put(x, map.getOrDefault(x, 0) + 1);}for (int key : map.keySet()) {System.out.println(key + ": " + map.get(key));}}
}
✅ 四、排序 - 示例题:“按得分排序”
题目描述:输入学生姓名与分数,按分数从高到低排序输出。
import java.util.*;public class ScoreSort {static class Student {String name; int score;Student(String n, int s) { name = n; score = s; }}public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();List<Student> list = new ArrayList<>();for (int i = 0; i < n; i++)list.add(new Student(sc.next(), sc.nextInt()));list.sort((a, b) -> b.score - a.score); // 自定义排序for (Student s : list)System.out.println(s.name + " " + s.score);}
}
✅ 五、并查集 - 示例题:“朋友圈数量”
题目描述:有 n 个人,m 对朋友关系,问总共有多少个朋友圈(连通块)。
import java.util.*;public class UnionFindFriends {static int[] fa;static int find(int x) {if (fa[x] != x) fa[x] = find(fa[x]);return fa[x];}static void union(int x, int y) {fa[find(x)] = find(y);}public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt(), m = sc.nextInt();fa = new int[n + 1];for (int i = 1; i <= n; i++) fa[i] = i;for (int i = 0; i < m; i++) union(sc.nextInt(), sc.nextInt());Set<Integer> roots = new HashSet<>();for (int i = 1; i <= n; i++) roots.add(find(i));System.out.println(roots.size()); // 连通块个数}
}
✅ 六、图 - 示例题:“最短路径 BFS”
题目描述:无权图从点 A 到点 B 的最短路径长度。
import java.util.*;public class BFSShortestPath {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt(), m = sc.nextInt();List<List<Integer>> g = new ArrayList<>();for (int i = 0; i <= n; i++) g.add(new ArrayList<>());for (int i = 0; i < m; i++) {int u = sc.nextInt(), v = sc.nextInt();g.get(u).add(v); g.get(v).add(u);}int[] dist = new int[n + 1];Arrays.fill(dist, -1);Queue<Integer> q = new LinkedList<>();q.offer(1); dist[1] = 0;while (!q.isEmpty()) {int cur = q.poll();for (int nei : g.get(cur)) {if (dist[nei] == -1) {dist[nei] = dist[cur] + 1;q.offer(nei);}}}System.out.println(dist[n]);}
}
✅ 七、动态规划(DP)- 示例题:“背包问题”
import java.util.*;public class ZeroOneKnapsack {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt(), W = sc.nextInt();int[] w = new int[n + 1], v = new int[n + 1];for (int i = 1; i <= n; i++) {w[i] = sc.nextInt(); v[i] = sc.nextInt();}int[] dp = new int[W + 1];for (int i = 1; i <= n; i++) {for (int j = W; j >= w[i]; j--) {dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);}}System.out.println(dp[W]);}
}
✅ 八、贪心 - 示例题:“活动安排问题”
题目描述:选择最多不重叠的活动。
import java.util.*;public class GreedyActivitySelect {static class Act {int start, end;Act(int s, int e) { start = s; end = e; }}public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();List<Act> list = new ArrayList<>();for (int i = 0; i < n; i++)list.add(new Act(sc.nextInt(), sc.nextInt()));list.sort(Comparator.comparingInt(a -> a.end)); // 按结束时间排序int cnt = 0, lastEnd = 0;for (Act a : list) {if (a.start >= lastEnd) {cnt++; lastEnd = a.end;}}System.out.println(cnt);}
}
蓝桥杯万字攻略:算法模板大放送!-Java 版
主要内容
由数据范围反推算法复杂度以及算法内容
一般ACM或者笔试题的时间限制是1秒或2秒。在这种情况下,Java代码中的操作次数控制在 (10^7 \sim 10^8) 为最佳。
下面给出在不同数据范围下,代码的时间复杂度和算法该如何选择:
数据范围 | 时间复杂度 | 算法 |
---|---|---|
(n \le 30) | 指数级别 | dfs+剪枝,状态压缩dp |
(n \le 100) | (O(n^3)) | Floyd,dp,高斯消元 |
(n \le 1000) | (O(n2)),(O(n2logn)) | dp,二分,朴素版Dijkstra、朴素版Prim、Bellman-Ford |
(n \le 10000) | (O(n * \sqrt n)) | 块状链表、分块、莫队 |
(n \le 100000) | (O(nlogn)) | 各种sort,线段树、树状数组、set/map、heap、拓扑排序、dijkstra+heap、prim+heap、Kruskal、spfa、求凸包、求半平面交、二分、CDQ分治、整体二分、后缀数组、树链剖分、动态树 |
(n \le 1000000) | (O(n)), 以及常数较小的 (O(nlogn)) 算法 | 单调队列、 hash、双指针扫描、并查集,kmp、AC自动机,常数比较小的 (O(nlogn)) 的做法:sort、树状数组、heap、dijkstra、spfa |
(n \le 10000000) | (O(n)) | 双指针扫描、kmp、AC自动机、线性筛素数 |
(n \le 10^9) | (O(\sqrt n)) | 判断质数 |
(n \le 10^{18}) | (O(logn)) | 最大公约数,快速幂,数位DP |
(n \le 10^{1000}) | (O((logn)^2)) | 高精度加减乘除 |
(n \le 10^{100000}) | (O(logk \times loglogk),k表示位数) | 高精度加减、FFT/NTT 由数据范围反推算法 |
基础算法
快速排序算法模板
import java.util.Arrays;public class QuickSort {public static void quickSort(int[] arr, int low, int high) {if (low < high) {int pi = partition(arr, low, high);quickSort(arr, low, pi - 1);quickSort(arr, pi + 1, high);}}private static int partition(int[] arr, int low, int high) {int pivot = arr[low + (high - low) / 2];int i = low - 1;int j = high + 1;while (true) {while (arr[++i] < pivot);while (arr[--j] > pivot);if (i >= j) {return j;}swap(arr, i, j);}}private static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
}
归并排序算法模板
import java.util.Arrays;public class MergeSort {private static int[] temp;public static void mergeSort(int[] arr) {temp = new int[arr.length];mergeSort(arr, 0, arr.length - 1);}private static void mergeSort(int[] arr, int l, int r) {if (l >= r) {return;}int mid = l + (r - l) / 2;mergeSort(arr, l, mid);mergeSort(arr, mid + 1, r);merge(arr, l, mid, r);}private static void merge(int[] arr, int l, int mid, int r) {System.arraycopy(arr, l, temp, l, r - l + 1);int i = l, j = mid + 1, k = l;while (i <= mid && j <= r) {if (temp[i] <= temp[j]) {arr[k++] = temp[i++];} else {arr[k++] = temp[j++];}}while (i <= mid) {arr[k++] = temp[i++];}while (j <= r) {arr[k++] = temp[j++];}}
}
整数二分算法模板
public class BinarySearch {public static int bsearch_1(int[] arr, int target) {int l = 0, r = arr.length - 1;while (l < r) {int mid = l + (r - l) / 2;if (arr[mid] >= target) {r = mid;} else {l = mid + 1;}}return l;}public static int bsearch_2(int[] arr, int target) {int l = 0, r = arr.length - 1;while (l < r) {int mid = l + (r - l + 1) / 2;if (arr[mid] <= target) {l = mid;} else {r = mid - 1;}}return l;}
}
浮点数二分算法模板
public class BinarySearchFloat {public static double bsearch_3(double l, double r) {final double eps = 1e-6;while (r - l > eps) {double mid = (l + r) / 2;if (check(mid)) {r = mid;} else {l = mid;}}return l;}private static boolean check(double x) {return false;}
}
高精度加法
import java.util.ArrayList;
import java.util.List;public class HighPrecisionAddition {public static List<Integer> add(List<Integer> A, List<Integer> B) {if (A.size() < B.size()) {return add(B, A);}List<Integer> C = new ArrayList<>();int t = 0;for (int i = 0; i < A.size(); i++) {t += A.get(i);if (i < B.size()) {t += B.get(i);}C.add(t % 10);t /= 10;}if (t != 0) {C.add(t);}while (C.size() > 1 && C.get(C.size() - 1) == 0) {C.remove(C.size() - 1);}return C;}
}
高精度减法
import java.util.ArrayList;
import java.util.List;public class HighPrecisionSubtraction {public static List<Integer> sub(List<Integer> A, List<Integer> B) {List<Integer> C = new ArrayList<>();int t = 0;for (int i = 0; i < A.size(); i++) {t = A.get(i) - t;if (i < B.size()) {t -= B.get(i);}C.add((t + 10) % 10);if (t < 0) {t = 1;} else {t = 0;}}while (C.size() > 1 && C.get(C.size() - 1) == 0) {C.remove(C.size() - 1);}return C;}
}
高精度乘低精度
import java.util.ArrayList;
import java.util.List;public class HighPrecisionMultiplication {public static List<Integer> mul(List<Integer> A, int b) {List<Integer> C = new ArrayList<>();int t = 0;for (int i = 0; i < A.size() || t != 0; i++) {if (i < A.size()) {t += A.get(i) * b;}C.add(t % 10);t /= 10;}while (C.size() > 1 && C.get(C.size() - 1) == 0) {C.remove(C.size() - 1);}return C;}
}
高精度除以低精度
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class HighPrecisionDivision {public static List<Integer> div(List<Integer> A, int b, int[] r) {List<Integer> C = new ArrayList<>();int remainder = 0;for (int i = A.size() - 1; i >= 0; i--) {remainder = remainder * 10 + A.get(i);C.add(remainder / b);remainder %= b;}Collections.reverse(C);while (C.size() > 1 && C.get(C.size() - 1) == 0) {C.remove(C.size() - 1);}r[0] = remainder;return C;}
}
一维前缀和
import java.util.ArrayList;
import java.util.List;public class PrefixSum1D {public static List<Integer> getPrefixSum(List<Integer> arr) {List<Integer> prefixSum = new ArrayList<>();prefixSum.add(0);for (int num : arr) {prefixSum.add(prefixSum.get(prefixSum.size() - 1) + num);}return prefixSum;}public static int querySum(List<Integer> prefixSum, int l, int r) {return prefixSum.get(r) - prefixSum.get(l - 1);}
}
二维前缀和
import java.util.ArrayList;
import java.util.List;public class PrefixSum2D {public static List<List<Integer>> getPrefixSum(List<List<Integer>> matrix) {int rows = matrix.size();int cols = matrix.get(0).size();List<List<Integer>> prefixSum = new ArrayList<>();for (int i = 0; i <= rows; i++) {List<Integer> row = new ArrayList<>();for (int j = 0; j <= cols; j++) {row.add(0);}prefixSum.add(row);}for (int i = 1; i <= rows; i++) {for (int j = 1; j <= cols; j++) {prefixSum.get(i).set(j, matrix.get(i - 1).get(j - 1) + prefixSum.get(i - 1).get(j) + prefixSum.get(i).get(j - 1) - prefixSum.get(i - 1).get(j - 1));}}return prefixSum;}public static int querySum(List<List<Integer>> prefixSum, int x1, int y1, int x2, int y2) {return prefixSum.get(x2).get(y2) - prefixSum.get(x1 - 1).get(y2) - prefixSum.get(x2).get(y1 - 1) + prefixSum.get(x1 - 1).get(y1 - 1);}
}
一维差分
import java.util.ArrayList;
import java.util.List;public class Difference1D {public static List<Integer> getDifference(List<Integer> arr) {List<Integer> diff = new ArrayList<>();diff.add(arr.get(0));for (int i = 1; i < arr.size(); i++) {diff.add(arr.get(i) - arr.get(i - 1));}return diff;}public static void applyDifference(List<Integer> arr, int l, int r, int c) {arr.set(l, arr.get(l) + c);if (r + 1 < arr.size()) {arr.set(r + 1, arr.get(r + 1) - c);}}
}
二维差分
import java.util.ArrayList;
import java.util.List;public class Difference2D {public static List<List<Integer>> getDifference(List<List<Integer>> matrix) {int rows = matrix.size();int cols = matrix.get(0).size();List<List<Integer>> diff = new ArrayList<>();for (int i = 0; i < rows; i++) {List<Integer> row = new ArrayList<>();row.add(matrix.get(i).get(0));for (int j = 1; j < cols; j++) {row.add(matrix.get(i).get(j) - matrix.get(i).get(j - 1));}diff.add(row);}return diff;}public static void applyDifference(List<List<Integer>> diff, int x1, int y1, int x2, int y2, int c) {diff.get(x1).set(y1, diff.get(x1).get(y1) + c);diff.get(x1).set(y2 + 1, diff.get(x1).get(y2 + 1) - c);diff.get(x2 + 1).set(y1, diff.get(x2 + 1).get(y1) - c);diff.get(x2 + 1).set(y2 + 1, diff.get(x2 + 1).get(y2 + 1) + c);}
}
位运算
public class BitOperations {public static int getKthBit(int n, int k) {return (n >> k) & 1;}public static int lowbit(int n) {return n & -n;}
}
双指针算法
import java.util.ArrayList;
import java.util.List;public class TwoPointers {public static List<Integer> twoSum(List<Integer> nums, int target) {int i = 0, j = nums.size() - 1;while (i < j) {int sum = nums.get(i) + nums.get(j);if (sum < target) {i++;} else if (sum > target) {j--;} else {return List.of(i, j);}}return List.of();}
}
离散化
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class Discretization {public static List<Integer> discretize(List<Integer> arr) {List<Integer> sortedArr = new ArrayList<>(arr);Collections.sort(sortedArr);sortedArr = new ArrayList<>(sortedArr.stream().distinct().toList());List<Integer> res = new ArrayList<>();for (int num : arr) {int idx = Collections.binarySearch(sortedArr, num);res.add(idx + 1);}return res;}
}
区间合并
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;public class IntervalMerge {public static List<int[]> merge(List<int[]> intervals) {List<int[]> res = new ArrayList<>();if (intervals.isEmpty()) {return res;}intervals.sort(Comparator.comparingInt(a -> a[0]));int start = intervals.get(0)[0];int end = intervals.get(0)[1];for (int i = 1; i < intervals.size(); i++) {int[] interval = intervals.get(i);if (end < interval[0]) {res.add(new int[]{start, end});start = interval[0];end = interval[1];} else {end = Math.max(end, interval[1]);}}res.add(new int[]{start, end});return res;}
}