前缀和
数组的前n项和就叫作前缀和,一般用于快速计算任意一段区间内元素的和,是一种常见的预处理方式。
一维前缀和
使用preSum数组存放前缀和,preSum[i]
代表[nums[0], nums[i-1]]
的累加和。
public class PrefixSum {
int[] preSum; // 前缀和数组
public PrefixSum(int[] nums) {
preSum = new int[nums.length+1];
// 计算前缀和
for (int i = 0; i < nums.length; i++){
preSum[i+1] = preSum[i]+nums[i];
}
}
// 计算[left, right]内的元素和
public int sumRange(int left, int right){
// 前left-1个元素的累加和 - 前right个元素的累加和
return preSum[right+1]-preSum[left];
}
}
二维前缀和
二维前缀和计算公式:
preSum[i][j] = preSum[i-1][j] + preSum[i][j-1] - preSum[i-1][j-1] + matrix[i-1][j-1];
preSum[i-1][j-1]
部分加了两次,要去掉一个。
public class TwoPrefixSum {
int[][] preSum; // 前缀和数组
public TwoPrefixSum(int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
preSum = new int[m+1][n+1];
// 计算前缀和
for (int i = 1; i <= m; i++){
for (int j = 1; j <= n; j++){
preSum[i][j] = preSum[i-1][j] + preSum[i][j-1] - preSum[i-1][j-1] + matrix[i-1][j-1];
}
}
}
// (a,b)是左上角坐标,(i,j)是右下角坐标
public int sumRange(int a, int b, int i, int j){
return preSum[i+1][j+1] - preSum[a][j+1] - preSum[i+1][b] + preSum[a][b];
}
}
并查集
并查集主要用于处理集合的查询和合并问题。
结构定义如下:
public class UnionFind {
// 记录每个元素的老大
private int[] parent;
// 构造函数
public UnionFind(int n){}
// 查找x的老大
public int find(int x){
// 递归法,一层一层找
if(x!=parent[x]) parent[x] = find(parent[x]);
return parent[x];
}
// 判断两个元素是否连通
public boolean isConnected(int x, int y){
return find(x) == find(y);
}
// 把两个元素及其分支连接,x所在阵营加入y所在阵营
public boolean union(int x, int y){
if(isConnected(x, y)) return false;
int xParent = find(x);
int yParent = find(y);
// y的老大是总老大
parent[xParent] = yParent;
return true;
}
}