基础算法
一.二分查找
1.模版
boolean check(int x) {
}
int search(int left, int right) {
while (left < right) {
int mid = (left + right) >> 1;
if (check(mid)) {
//满足条件,向寻找范围继续寻找,例如我要找更靠左的:r = m
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
boolean check(int x) {
}
int search(int left, int right) {
while (left < right) {
int mid = (left + right + 1) >> 1;
if (check(mid)) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
}
2.使用场景
2.1.普通二分查找
2.2.最小化最大值(本质是二分求最小值)
2.3.最大化最小值(本质是二分求最大值)
二.前缀和与差分数组
1.一维前缀和
class NumArray {
// 前缀和数组
private int[] preSum;
/* 输入一个数组,构造前缀和 */
public NumArray(int[] nums) {
// preSum[0] = 0,便于计算累加和
preSum = new int[nums.length + 1];
// 计算 nums 的累加和
for (int i = 1; i < preSum.length; i++) {
preSum[i] = preSum[i - 1] + nums[i - 1];
}
}
/* 查询闭区间 [left, right] 的累加和 */
public int sumRange(int left, int right) {
return preSum[right + 1] - preSum[left];
}
}
2.二维前缀和
class NumMatrix {
int[][] preSum ;
public NumMatrix(int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
preSum = new int[m+1][n+1];
for(int i = 0;i<m;i++){
for(int j = 0;j<n;j++){
preSum[i+1][j+1] = preSum[i+1][j] + preSum[i][j+1] - preSum[i][j] + matrix[i][j];
}
}
}
public int sumRegion(int row1, int col1, int row2, int col2) {
return preSum[row2+1][col2+1] - preSum[row2+1][col1] - preSum[row1][col2+1] + preSum[row1][col1];
}
}
/**
* Your NumMatrix object will be instantiated and called as such:
* NumMatrix obj = new NumMatrix(matrix);
* int param_1 = obj.sumRegion(row1,col1,row2,col2);
*/
3.哈希+前缀和(子数组统计计数)
类似两数之和思路,要学会等式转换,注意设置map的下标,是否加1
LeetCode例题前缀异或和
4.一维差分数组
差分数组的主要适用场景是频繁对原始数组的某个区间的元素进行增减。
public class Solution {
public void modifyArray(int[] nums, int k) {
int n = nums.length;
int[] d = new int[n + 1]; // 差分数组
int sumD = 0; // 累积差分值
for (int i = 0; i < n; i++) {
sumD += d[i];
// 更新nums[i]的逻辑,根据具体问题调整
nums[i] += sumD;
// 根据条件更新差分数组
if (需要更新条件) {
int change = 计算需要的变化值;
sumD -= change; // 应用变化到sumD
d[i] += change; // 当前位置开始应用变化
if (i + k < n) {
d[i + k] -= change; // 在i+k处抵消前面的变化
}
}
}
// 可以在这里添加逻辑,根据需要处理nums数组
}
}
5.二维差分数组
class Solution {
public int[][] rangeAddQueries(int n, int[][] queries) {
// 二维差分模板
//往nn矩阵左上加一行一列,主要是为了前缀和舒服,
//往nn矩阵右下加一行一列,主要是为了操作差分数组方便。
int[][] diff = new int[n + 2][n + 2], ans = new int[n][n];
for (int[] q : queries) {
int r1 = q[0], c1 = q[1], r2 = q[2], c2 = q[3];
++diff[r1 + 1][c1 + 1];
--diff[r1 + 1][c2 + 2];
--diff[r2 + 2][c1 + 1];
++diff[r2 + 2][c2 + 2];
}
// 用二维前缀和复原
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
ans[i - 1][j - 1] = diff[i][j] += diff[i][j - 1] + diff[i - 1][j] - diff[i - 1][j - 1];
return ans;
}
}