Java常用类、方法
内建类
基本型及其包装类
/* char || Character */
// string转化为char数组,以及Character判断是否为数字
for (char c : string.toCharArray()) {
if (!Character.isDigit(c)) {
return false;
}
}
/* int || Integer */
// 将string转换为整数
try {
int num = Integer.parseInt(string);
} catch (NumberFormatException e) {
return false;
}
// int最大值
Integer.MAX_VALUE;求最大、最小、均值、和
// Arrays计算数组均值、最大值、最小值、求和
Arrays.stream(nums).average().getAsDouble();
Arrays.stream(nums).max().getAsInt();
Arrays.stream(nums).min().getAsInt();
Arrays.stream(nums).sum();
// List流计算List均值、最大值、最小值、求和
Double avg = list.stream().mapToLong(Integer::intValue).average().getAsDouble();
int max = list.stream().mapToInt(Integer::intValue).max().getAsInt();
int min = list.stream().mapToInt(Integer::intValue).min().getAsInt();
int sum = list.stream().mapToInt(Integer::intValue).sum();
// Collections计算List最大值、最小值
int max = Collections.max(list);
int min = Collections.min(list);String、strBuilder
可编辑的string:StringBuilder
// 声明
String string = "string";
StringBuilder strBuilder = new StringBuilder(string);
// 取字符
string.charAt(index);
strBuilder.charAt(index);
// 长度
string.length();
strBuilder.length();
// 字符串拼接
string = string.concat("aaaa");
// 子串
string.substring(start, end); // [start, end)
// 判断开头元素是否为指定元素
string.startsWith("0");
// 替换
string.replace('a', 'b');
// 修改
strBuilder.setCharAt(index, 'a');
// 添加
strBuilder.append('a');
// 删除
strBuilder.deleteCharAt(index);
// 返回一个String
strBuilder.toString();
// String转化为字符数组
char[] ch = string.toCharArray();List、Array
// 声明
List<Integer> list = new ArrayList<>();
// 拿到list的副本
List<Integer> copy_list = new ArrayList<>(list);
// 排序
Arrays.sort(nums);
// 返回一个list
Arrays.asList({1, 2, 3});
// 填充数组
Arrays.fill(nums, 0);
// 数组转化为list
List<Integer> list = new ArrayList<>(Arrays.asList(nums));
List<Integer> list = Arrays.stream(nums).boxed().collect(Collectors.toList());
// list转化为数组
int[] array = list.stream().mapToInt(i -> i).toArray();
// 取数
list.get(index);
// 大小
list.size();
// 添加
list.add(item);
// 删除
list.remove(index);
// 清空
list.clear();HashSet
// 声明
Set<ListNode> set = new HashSet<>();
// 判断包含
set.contains();
// 添加
set.add();
// 大小
set.size();
// 迭代器
for (int elem : set) {}TreeSet
java 实现 Comparable 接口,便于 TreeSet 的 add() 方法使用
// 自定义类实现Comparable接口
class ListNode implements Comparable<ListNode> {
int val;
ListNode next;
ListNode(int x) { val = x; }
@Override
public int compareTo(ListNode o) {
// 这里的“等于返回1”,保证了相同value的元素不会被覆盖
if(o.val >= this.val) return 1;
else return -1;
}
}
// 声明
Set<ListNode> tree = new TreeSet<>();
// 添加
tree.add(new ListNode(1));
// 迭代器
for(ListNode e : tree) {}HashMap
// 声明
Map<Integer, Integer> map = new HashMap<>();
// 判断包含Key
map.containsKey(key);
// 用Key取Value
map.get(key);
// 添加
map.put(key, value);
// Entry迭代器
for(Map.Entry<Integer, Integer> e:map.entrySet()) {}Stack
// 声明
Stack<Integer> stack = new Stack<>();
// 判断空
stack.isEmpty();
// 添加
stack.push(item);
// 取出
stack.pop();
// 查看但不取出栈顶
stack.peek();Queue
// 声明
Queue<Integer> queue = new LinkedList<>();
// 判断空
queue.isEmpty();
// 添加
queue.offer(item);
// 取出
queue.poll();
// 查看但不取出队首
queue.peek();Deque
// 声明
Deque<Integer> deque = new LinkedList<>();
// 判断空
deque.isEmpty();
// 添加
deque.offerFirst(item);
deque.offerLast(item);
// 取出
deque.pollFirst();
deque.pollLast();
// 查看但不取出
deque.peekFirst();
deque.peekLast();PriorityQueue
/*Comparator接口说明:
* 返回负数,形参中第一个参数排在前面;返回正数,形参中第二个参数排在前面
* 对于队列:排在前面意味着往队头靠
* 对于堆(使用PriorityQueue实现):从队头到队尾按从小到大排就是最小堆(小顶堆),
* 从队头到队尾按从大到小排就是最大堆(大顶堆)--->队头元素相当于堆的根节点
* */
// 声明(模拟小顶堆)
PriorityQueue<Integer> pq = new PriorityQueue<>((e1, e2) -> e1 - e2);
// 判断空
pq.isEmpty();
// 添加
pq.offer(item);
// 取出
pq.poll();
// 查看但不取出
pq.peek();Collections
// 反转list
List<Integer> ans = new ArrayList<>();
Collections.reverse(ans);
// 随机排序
Collections.shuffle(ans);
// 交换两个索引位置的元素
Collections.swap(ans, i, j);
/* 自定义排序 */
// List<List<String>> tickets
// 以下排序可以按照 <List<String> 中第二个 String,将其以字典序排列
Collections.sort(tickets, (a, b) -> a.get(1).compareTo(b.get(1)));
// 以下排序可以先按 <List<String> 中第1个 String 再按第2个 String,将其以字典序排列
Collections.sort(tickets, new Comparator<List<String>>() {
@Override
public int compare(List<String> o1, List<String> o2) {
int cmp = o1.get(0).compareTo(o2.get(0));
if (cmp == 0) {
cmp = o1.get(1).compareTo(o2.get(1));
}
return cmp;
}
});
// 或者用list自己的sort方法
tickets.sort(Comparator.comparing((List<String> o) -> o.get(0))
.thenComparing(o -> o.get(1)));Math
// 取最大值
Math.max(a, b);
// 取最小值
Math.min(a, b);
// 取绝对值
Math.abs(a);
// 取幂
Math.pow(a, b);
// 取平方根
Math.sqrt(a);
// 取自然对数
Math.log(a);
// 取以10为底的对数
Math.log10(a);Scanner
// 声明
Scanner sc = new Scanner(System.in);
// 判断是否还有下一个整数
sc.hasNextInt();
// 读取整数
int num = sc.nextInt();
// 读取字符串
String str = sc.nextLine();正则表达式
String input = "[1(2), 1(1), -1(3)]";
Pattern pattern = Pattern.compile("(-?\\d+)\\((\\d+)\\)");
Matcher matcher = pattern.matcher(input);
List<List<Integer>> result = new ArrayList<>();
while (matcher.find()) {
List<Integer> pair = new ArrayList<>();
pair.add(Integer.parseInt(matcher.group(1)));
pair.add(Integer.parseInt(matcher.group(2)));
result.add(pair);
}
System.out.println(result);
// 输出:[[1, 2], [1, 1], [-1, 3]]Java模板
ACM模板
import java.util.*;
// import java.util.List;
// import java.util.Scanner;
public class AcmInputOutput {
public static void main(String [] args) {
AcmInputOutput acm = new AcmInputOutput();
acm.inputNumberWithLine();
}
// 主要掌握scan.hasNext()、scan.hasNextInt()、scan.nextInt()、
// scan.hasNextLine()、scan.nextLine()的使用
// 1. 数字处理
// 读取 Long:in.hasNextLong() 和 in.nextLong();
// 读取小数:in.nextFloat() 或 in.nextDouble();
// 及其hasNextFloat() 或 hasNextDouble();
// 1.1. 基础数字,数量未知
// 多组空格分隔的两个数
public void twoNumberInLine() {
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
int a = in.nextInt();
int b = in.nextInt();
System.out.println(a + b);
}
}
// 1.2. 告知数量
// 先输入数据个数,后面输入空格分隔的数,可换行
public void inputNumber() {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
for (int i = 0; i < n; i++) {
int a = in.nextInt();
System.out.println(a);
}
}
// 1.3. 告知结束符
// 输入空格分隔的数,以某个特定数结束,例如0
public void inputEndWith() {
Scanner in = new Scanner(System.in);
while (in.hasNextInt()) {
int a = in.nextInt();
if (a == 0) {
break;
}
System.out.println(a);
}
}
// 1.4. 数组或链表:按行处理,每行数量不定,行数也不定,行内数字空格分隔
// 按字符串处理,先读取一行,再按空格分隔
public void inputNumberWithLine() {
Scanner in = new Scanner(System.in);
while (in.hasNextLine()) {
List<Integer> list = new ArrayList<>();
String[] nums = in.nextLine().split(" ");
for (String x : nums) {
list.add(Integer.parseInt(x));
}
System.out.println(list.toString());
int[] array = list.stream().mapToInt(i -> i).toArray();
}
}
// 2. 字符串处理
// 2.1. 基础字符串,空格分隔,可能有多行,每行存为一个数组
public void inputString() {
Scanner in = new Scanner(System.in);
while (in.hasNextLine()) {
String[] s = in.nextLine().split(" ");
for (String str : s) {
System.out.println(str);
}
}
}
// 2.2. 告知行数
// 先输入行数,后面输入每行的字符串
public void inputStringWithLine() {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
in.nextLine(); // 重要!!跳到下一行,避免读到空行
for (int i = 0; i < n; i++) {
String s = in.nextLine();
System.out.println(s);
}
}
// 3. 二叉树的输入
static class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int x) {
this.val = x;
this.left = null;
this.right = null;
}
}
/**
* 根据数组构建二叉树
* @param arr 树的数组表示
* @return 构建成功后树的根节点
*/
public TreeNode constructBinaryTree(final int[] arr) {
// 构建和原数组相同的树节点列表
List<TreeNode> treeNodeList = arr.length > 0 ? new ArrayList<>(arr.length) : null;
TreeNode root = null;
// 把输入数值数组,先转化为二叉树节点列表
for (int i = 0; i < arr.length; i++) {
TreeNode node = null;
if (arr[i] != -1) { // 用 -1 表示null
node = new TreeNode(arr[i]);
}
treeNodeList.add(node);
if (i == 0) {
root = node;
}
}
// 遍历一遍,根据规则左右孩子赋值就可以了
// 注意这里 结束规则是 i * 2 + 1 < arr.length,避免空指针
// 为什么结束规则不能是i * 2 + 2 < arr.length呢?
// 如果i * 2 + 2 < arr.length 是结束条件
// 那么i * 2 + 1这个符合条件的节点就被忽略掉了
// 例如[2,7,9,-1,1,9,6,-1,-1,10] 这样的一个二叉树,最后的10就会被忽略掉
for (int i = 0; i * 2 + 1 < arr.length; i++) {
TreeNode node = treeNodeList.get(i);
if (node != null) {
// 线性存储转连式存储关键逻辑
node.left = treeNodeList.get(2 * i + 1);
// 再次判断下 不忽略任何一个节点
if(i * 2 + 2 < arr.length)
node.right = treeNodeList.get(2 * i + 2);
}
}
return root;
}
// 3. 输出格式化相关
}二分查找
可以查找元素的第一个和最后一个位置(支持数组中存在重复元素)
// 自己写的,其中高亮行即为和普通无重复元素的二分查找不同的地方
class Solution {
public int[] searchRange(int[] nums, int target) {
int left = binary(nums, target, true);
int right = binary(nums, target, false) - 1;
if (left <= right && nums[left] == target && nums[right] == target) {
return new int[]{left, right};
}
else {
return new int[]{-1, -1};
}
}
public int binary(int[] nums, int target, boolean first_loc) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = (left + right ) / 2;
if (nums[mid] > target) {
right = mid - 1;
}
else if (first_loc && nums[mid] == target) {
right = mid - 1;
}
else if (!first_loc && nums[mid] == target) {
left = mid + 1;
}
else if (nums[mid] < target) {
left = mid + 1;
}
}
return left;
}
}树的层次遍历
// 自己的
// 我这里用null来隔开每一层,这样就不用记录每一层的节点数了。
// 当然也可以记录每一层的节点数,然后用for循环来遍历每一层。
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ans = new ArrayList<>();
List<Integer> layer = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
// 初始判断:树空?
if(root != null) {
queue.offer(root);
queue.offer(null); // 压入null表示隔开这一层
}
else return ans;
// 遍历
while(!queue.isEmpty()) {
if(queue.peek() != null) {
// 顶部非空,正在遍历这一层
layer.add(queue.peek().val); // 当前节点入layer
System.out.println(layer);
if(queue.peek().left != null) queue.offer(queue.peek().left); // 压入左
if(queue.peek().right != null) queue.offer(queue.peek().right); // 压入右
queue.poll(); // 弹出顶
}
else {
// 顶部空,这一层遍历完毕
System.out.println(layer);
ans.add(layer); // 当前layer入ans
layer = new ArrayList<>(); // 当前layer清空
queue.poll(); // 弹出空
if(!queue.isEmpty()) queue.offer(null);
}
}
return ans;
}
}// 代码随想录
class Solution {
public List<List<Integer>> resList = new ArrayList<List<Integer>>();
public List<List<Integer>> levelOrder(TreeNode root) {
//checkFun01(root,0);
checkFun02(root);
return resList;
}
//DFS--递归方式
public void checkFun01(TreeNode node, Integer deep) {
if (node == null) return;
deep++;
if (resList.size() < deep) {
//当层级增加时,list的Item也增加,利用list的索引值进行层级界定
List<Integer> item = new ArrayList<Integer>();
resList.add(item);
}
resList.get(deep - 1).add(node.val);
checkFun01(node.left, deep);
checkFun01(node.right, deep);
}
//BFS--迭代方式--借助队列
public void checkFun02(TreeNode node) {
if (node == null) return;
Queue<TreeNode> que = new LinkedList<TreeNode>();
que.offer(node);
while (!que.isEmpty()) {
List<Integer> itemList = new ArrayList<Integer>();
int len = que.size();
while (len > 0) {
TreeNode tmpNode = que.poll();
itemList.add(tmpNode.val);
if (tmpNode.left != null) que.offer(tmpNode.left);
if (tmpNode.right != null) que.offer(tmpNode.right);
len--;
}
resList.add(itemList);
}
}
}快速幂
// 底数factor,指数power,模MOD
private final long MOD = (long) 1e9 + 7;
public long quickPow(long factor, long power) {
if (power == 0) return 1;
if (power == 1) return factor;
long part = quickPow(factor, power / 2);
if (power % 2 == 1) {
return (((part % MOD) * (part % MOD)) % MOD * (factor % MOD)) % MOD;
}
else {
return ((part % MOD) * (part % MOD)) % MOD;
}
}简单哈希
public class SimpleHash {
// capacity: 哈希表的容量,哈希值将在0到capacity-1之间
private int capacity;
public SimpleHash(int capacity) {
this.capacity = capacity;
}
public int hash(String key) {
int hash = 0;
int length = key.length();
// 遍历输入字符串中的每一个字符
for (int i = 0; i < length; i++) {
// 将当前的哈希值乘以31(一个质数),然后加上当前字符的ASCII值,
// 然后对capacity取模,以确保结果在0到capacity-1之间
hash = (31 * hash + key.charAt(i)) % capacity;
}
return hash;
}
}最大公约数、最小公倍数
private static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
private static int lcm(int a, int b) {
return a * b / gcd(a, b);
}并查集
以1971. 寻找图中是否存在路径 (opens in a new tab)为例
class Solution {
int[] father;
public boolean validPath(int n, int[][] edges, int source, int destination) {
father = new int[n];
init();
for (int i = 0; i < edges.length; i++) {
join(edges[i][0], edges[i][1]);
}
return isSame(source, destination);
}
// 并查集初始化
public void init() {
for (int i = 0; i < father.length; i++) {
father[i] = i;
}
}
// 并查集里寻根的过程
public int find(int u) {
if (u == father[u]) {
return u;
} else {
father[u] = find(father[u]);
return father[u];
}
}
// 判断 u 和 v是否找到同一个根
public boolean isSame(int u, int v) {
u = find(u);
v = find(v);
return u == v;
}
// 将v->u 这条边加入并查集
public void join(int u, int v) {
u = find(u); // 寻找u的根
v = find(v); // 寻找v的根
if (u == v) return; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回
// 注意以上写法不能替换为if(isSame(u, v)) return;
// 否则可能会断开原有的连接
father[v] = u;
}
}最小生成树
以1584. 连接所有点的最小费用 (opens in a new tab)为例
kruskal算法:(还用到了并查集)
class Solution {
public int minCostConnectPoints(int[][] points) {
List<Edge> edges = new ArrayList<>();
for (int i = 0; i <= points.length - 2; i++) {
for (int j = i + 1; j <= points.length - 1; j++) {
edges.add(new Edge(i, j,
Math.abs(points[i][0] - points[j][0]) + Math.abs(points[i][1] - points[j][1])));
}
}
Collections.sort(edges, new Comparator<Edge>() {
public int compare(Edge o1, Edge o2) {
return o1.dis - o2.dis;
}
});
int n = points.length;
int cost = 0;
int count = 1;
int index = 0;
Union un = new Union(n);
while (count < n) {
Edge now_edge = edges.get(index);
if (!un.isSame(now_edge.x, now_edge.y)) {
un.join(now_edge.x, now_edge.y);
cost += now_edge.dis;
count++;
}
index++;
}
return cost;
}
}
class Union {
int[] father;
public Union(int n) {
father = new int[n];
for (int i = 0; i < n; i++) {
father[i] = i;
}
}
public int find(int u) {
if (u == father[u]) return u;
else return father[u] = find(father[u]);
}
public boolean isSame(int u, int v) {
return find(u) == find(v);
}
public void join(int u, int v) {
u = find(u);
v = find(v);
father[v] = u;
}
}
class Edge {
public int x;
public int y;
public int dis;
public Edge(int x, int y, int dis) {
this.x = x;
this.y = y;
this.dis = dis;
}
public String toString() {
return "x: " + x + ", y: " + y + ", dis: " + dis;
}
}Prim算法:
class Solution {
// 和 Dijkstra 一样,堆优化都必须自定义数据结构(Java中)
class Node implements Comparable<Node> {
int val;
int dis;
public Node(int v, int d) {
val = v;
dis = d;
}
public int compareTo(Node node) {
if (dis == node.dis) {
return val - node.val; // 养成习惯,不轻易定义相等
}
return dis - node.dis;
}
}
public int minCostConnectPoints(int[][] points) {
int n = points.length;
// 典型稠密图,邻接矩阵存图。
// 注意,用什么存图,和是否自定义Node没有关系。取决于图的疏密程度。
int[][] g = new int[n][n];
for (int i = 0; i < n; i++) {
g[i][i] = 0;
for (int j = i + 1; j < n; j++) {
g[i][j] = g[j][i] = Math.abs(points[i][0] - points[j][0])
+ Math.abs(points[i][1] - points[j][1]);
}
}
// 和最短路径一样,用这两个数据结构就够了
int[] dis = g[0]; // 0 表示已遍历,大于0表示 距离已遍历点群的最短距离
PriorityQueue<Node> heap = new PriorityQueue<>();
for (int i = 1; i < n; i++) {
heap.add(new Node(i, dis[i]));
}
// 开始遍历
int rs = 0;
while (!heap.isEmpty()) {
Node node = heap.poll();
if(dis[node.val] == 0) {
// Java 优先队列没有删除方法,使用延迟删除:遇到遍历过的点就跳过。
continue;
}
dis[node.val] = 0;
rs += node.dis;
for(int i = 0; i < dis.length; i++) {
if(dis[i] == 0) {
continue;
}
// 新距离是到刚加入的点的距离 g[node.val][i]。
// 如果是最短路径,还要加上 刚加入的点到起点的距离 node.val。
int newDis = g[node.val][i];
if(newDis < dis[i]) {
dis[i] = newDis;
// 更新的话,直接再存一个,反正有延迟删除
heap.add(new Node(i, newDis));
}
}
}
return rs;
}
}手写堆(最小堆为例)
public class MinHeap {
private int[] heap;
private int size;
public MinHeap(int capacity) {
heap = new int[capacity];
size = 0;
}
// 获取父节点
private int getParentIndex(int childIndex) {
return (childIndex - 1) / 2;
}
// 获取左子节点
private int getLeftChildIndex(int parentIndex) {
return 2 * parentIndex + 1;
}
// 获取右子节点
private int getRightChildIndex(int parentIndex) {
return 2 * parentIndex + 2;
}
// 判断是否有父节点
private boolean hasParent(int index) {
return getParentIndex(index) >= 0;
}
// 判断是否有左子节点
private boolean hasLeftChild(int index) {
return getLeftChildIndex(index) < size;
}
// 判断是否有右子节点
private boolean hasRightChild(int index) {
return getRightChildIndex(index) < size;
}
// 交换两个节点
private void swap(int indexOne, int indexTwo) {
int temp = heap[indexOne];
heap[indexOne] = heap[indexTwo];
heap[indexTwo] = temp;
}
// 确保堆的性质
private void heapifyUp() {
int index = size - 1;
while (hasParent(index) && heap[getParentIndex(index)] > heap[index]) {
swap(getParentIndex(index), index);
index = getParentIndex(index);
}
}
// 确保堆的性质
private void heapifyDown() {
int index = 0;
while (hasLeftChild(index)) {
int smallerChildIndex = getLeftChildIndex(index);
if (hasRightChild(index) && heap[getRightChildIndex(index)] < heap[getLeftChildIndex(index)]) {
smallerChildIndex = getRightChildIndex(index);
}
if (heap[index] < heap[smallerChildIndex]) {
break;
} else {
swap(index, smallerChildIndex);
}
index = smallerChildIndex;
}
}
// 添加元素
public void add(int item) {
heap[size] = item;
size++;
heapifyUp();
}
// 删除元素
public int poll() {
if (size == 0) throw new IllegalStateException();
int item = heap[0];
heap[0] = heap[size - 1];
size--;
heapifyDown();
return item;
}
// 查看堆顶元素
public int peek() {
if (size == 0) throw new IllegalStateException();
return heap[0];
}
}