跳转至

基础算法

前缀和

一维

原理:利用\(s [i] = s [i-1] + a [i]\)求出任意区间 \([l, r]\) 的和,即 \(s [r] - s [l-1]\)

应用:快速求解数组中任意区间的和,例如在多次查询区间和的问题

二维

原理: 计算公式为\(s [i][j] = s [i-1][j] + s [i][j-1] - s [i-1][j-1] + a [i][j]\) 利用二维前缀和求出任意子矩阵的和,即 \(s [x2][y2] - s [x1-1][y2] - s [x2][y1-1] + s [x1-1][y1-1]\)

应用:快速计算二维数组中任意子矩阵的和

差分

一维差分

原理:对于一维数组 \(a [1...n]\),构造差分数组 \(d [1...n]\),使得 \(a [i] = d [1] + d [2] + ... + d [i]\),即 \(d [1] = a [1],d [i] = a [i] - a [i-1](i≥2)\)。当需要对原数组的区间 \([l, r]\) 进行加 c 操作时,只需在差分数组中 \(d [l] += c,d [r+1] -= c(若 r+1≤n)\),最后通过差分数组求前缀和即可得到更新后的原数组。

应用:高效处理数组的区间更新问题,当有大量区间更新操作时,使用差分可以将每次更新的时间复杂度降为 O (1)

二分

序列二分

原理:在有序序列中,通过不断将区间缩小为原来的一半,来查找目标元素。每次比较中间元素与目标元素的大小,确定下一步搜索的区间。

应用:在有序数组中查找元素是否存在、查找元素的第一个位置或最后一个位置等。

int binarySearch(int l, int r, int key) {
    int ret = -1;
    while (l <= r) {
            int mid = l + ((r - l) >> 1);
            if (arr[mid] < key) {
                l = mid + 1;
            } else if (arr[mid] > key) {
                r = mid - 1;
            } else {
                ret = mid;      // 记录位置
                r = mid - 1;  // 继续往左找
                //l =mid+1; 继续往右找
            }
        }
        return ret;
    }
答案二分

原理:将求解的问题转化为判断某个值是否满足条件,通过二分答案的可能范围,每次判断当前中间值是否满足条件,从而缩小答案的范围,直到找到满足条件的最小或最大值。

应用:求解满足某种条件的最优解问题,如求最小的满足条件的数值、最大的不满足条件的数值等。

static int find(int[] a, int n, int m) {
        int l = 1;
        int r = 1000000001; // 1e9 + 1,Java中直接使用整数常量

        while (l <= r) {
            int mid = (l + r) / 2;
            if (check(mid, a, n, m)) {
                l = mid+1;
            } else {
                r = mid-1;
            }
        }
        return r;//一般情况是r  根据check定义
}
浮点数二分

原理:与整数二分类似,但由于浮点数的精度问题,需要设置一个足够小的精度范围(如 1e-8),当区间长度小于该精度时停止二分,取中间值作为结果。

应用:求解浮点数的方程根、求浮点数的极值等问题。

double l = 0, r = 1e9;
    while(r - l > eps){
        double mid =  (r + l) / 2;
        if(check(mid))
            l = mid;
        else
            r = mid;
    }
    printf("%.2f",l);
    return 0;

双指针

前后指针

原理:使用两个指针,一个从前向后遍历,一个从后向前遍历,根据题目条件调整指针的位置,从而解决问题。

应用:常用于数组或字符串的遍历问题,如判断回文字符串(一个指针从开头,一个从结尾,向中间移动比较字符)、数组中的元素配对问题等。

左右指针

原理:两个指针都从数组的一端(通常是左端)开始,向右移动,根据特定条件调整其中一个或两个指针的位置,以找到满足条件的区间或元素。

应用:求解滑动窗口问题(如最小覆盖子串)、有序数组中的和为目标值的元素对问题等。

位运算

原理:直接对整数在二进制层面上进行操作,包括与(&)、或(|)、异或(^)、左移(<<)、右移(>>)等操作。利用位运算可以高效地处理二进制位相关的问题。

应用:判断整数的奇偶性(通过判断最后一位是否为 1)、求一个数的二进制中 1 的个数、整数的快速乘除(左移相当于乘 2,右移相当于除以 2)、状态压缩(如用一个整数表示多个开关的状态)等。

找规律

原理:

应用: