常用算法代码模板 Java版 (1) :基础算法

常用算法模板 Java版——基础算法:排序、二分、高精度、前缀和与差分、位运算、双指针、离散化、区间合并



1 排序

Arrays.sort(arr [, fromIndex, toIndex])
Arrays.sort(arr, comparator)

Collections.sort(list)
Collections.sort(list, comparator)

1.1 直接插入排序

public class InsertSort {
	// 插入排序
    public static void insertSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            for (int j = i; j >= 1 && arr[j] > arr[j - 1]; j--) {
                swap(arr, j, j - 1);
            }
        }
    }

	// 交换数组中两个元素
    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

1.2 快速排序

  1. 确定枢轴:通常从 arr[l]arr[l + r >> 1]arr[r]之中任选一个
  2. 划分子区间:双指针 ij初始位于待排区间两侧外,先 ij相向而行,最终使得左右子区间 arr[l ... j]arr[j+1 ... r]左小右大
  3. 递归排序左右子区间(该写法左子区间右端点必须为 j

快速排序

public class QuickSort {
    // 快速排序 arr[l ... r]
    public static void quickSort(int[] arr, int l, int r) {
        if (l >= r) return;

        int x = arr[l + (r - l) / 2];	// 枢轴(选择中间元素)
        int i = l - 1, j = r + 1;		// 双指针初始位于两侧外(追加1偏移量)

        while (i < j) {
            do {
                i++;
            } while (arr[i] < x);
            do {
                j--;
            } while (arr[j] > x);
            if (i < j) {
                swap(arr, i, j);	// 交换元素
            }
        }

        quickSort(arr, l, j);		// 递归排序左子区间
        quickSort(arr, j + 1, r);	// 递归排序右子区间
    }

    // 交换数组中两个元素的方法
    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

1.3 归并排序

  1. 确定分界点:mid = l + r >> 1
  2. 递归排序左右子区间
  3. 归并左右子区间为有序子区间:挑出两者较小值,相等则优先归并 arr[i],使得排序稳定

二路归并排序

public class MergeSort {
    // 归并排序 arr[l ... r]
    public void mergeSort(int[] arr, int l, int r) {
        if (l >= r) return;

        int mid = l + r >> 1;
        mergeSort(arr, l, mid);			// 递归排序左半部分
        mergeSort(arr, mid + 1, r);		// 递归排序右半部分
        
        int[] temp = new int[r - l + 1];    // 辅助数组
        int i = l, j = mid + 1, k = 0;      // 初始化指针

        // 归并左右子区间为有序子区间
        while (i <= mid && j <= r) {
            if (arr[i] <= arr[j]) {
                temp[k++] = arr[i++];
            } else {
                temp[k++] = arr[j++];
            }
        }

        // 并入区间剩余元素
        while (i <= mid) {
            temp[k++] = arr[i++];
        }
        while (j <= r) {
            temp[k++] = arr[j++];
        }

        // 将排序后的结果复制回原始数组
        for (i = l, j = 0; i <= r; i++, j++) {
            arr[i] = temp[j];
        }
    }
}

2 二分

2.1 整数二分

AcWing 789. 数的范围

  1. 中点将区间划分出左右两子区间
  2. 判断中间点是否满足某侧区间的性质 check(mid),查找x边界,目标在x区间,检测x区间性质。易知该种写法条件检测始终为"≥"或"≤",对应下文check_ge()(greater_equal)、check_le()(less_equal),对比目标和中点的位置关系即可得出条件检测函数。
  3. 返回所检测的x区间的端点x

当查找右边界时中点应为l + r + 1 >> 1,简记:有(“右”) 加必有(“右”) 减

// 查找左边界,即第一个满足条件的元素下标 (lower_bound)
public int binarySearchL(int l, int r) {
    while (l < r) {
        int mid = l + r >> 1;	// 计算中间值
        if (check_ge(mid, target)) {
            r = mid;			// 如果中间的值符合条件,则继续在左边查找
        } else {
            l = mid + 1;		// 否则在右边查找
        }
    }
    return l;	// 返回左边界
}

// 查找右边界,即最后一个满足条件的元素下标 (upper_bound的前驱)
public int binarySearchR(int l, int r) {
    while (l < r) {
        int mid = l + r + 1 >> 1;	// 计算中间值,向右偏移
        if (check_le(mid, target)) {
            l = mid;				// 如果中间的值符合条件,则继续在右边查找
        } else {
            r = mid - 1;			// 否则在左边查找
        }
    }
    return r;	// 返回右边界
}

2.2 浮点数二分

类似整数二分的查找左边界,常写作f(mid) >= target的形式。解唯一,无需处理边界。要注意浮点精度问题。

public double binarySearchF(double l, double r) {
    final double eps = 1e-8;		// 精度,视题目而定
    while (r - l > eps) {
        double mid = (l + r) / 2;	// 计算中间值
        if (check_ge(mid, target)) {
            r = mid;				// 目标在左边,更新右边界
        } else {
            l = mid;				// 否则更新左边界
        }
    }
    return l;	// 返回左边界,即为目标值的估计
}

3 高精度运算

Java内置大数类:BigInteger、BigDecimal


4 前缀和、差分

以下前缀和与差分数组必须从下标1开始存储

4.1 一维前缀和

对于数列 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an ,规定 a i a_{i} ai前缀和为前 i i i 个数的和: S i = a 1 + a 2 + . . . + a i   ( i ≥ 1 ) S_i=a_1+a_2+...+a_i\ (i≥1) Si=a1+a2+...+ai (i1)

求法: S 0 = 0 ,   S i = S i − 1 + a i   ( i ≥ 1 ) S_0=0,\ S_i=S_{i-1}+a_i\ (i≥1) S0=0, Si=Si1+ai (i1)

应用:求下标区间 [ l ,   r ] [l,\ r] [l, r]上的片段和 S r − S l − 1 S_r-S_{l-1} SrSl1

一维前缀和

/* int a[1 ... n], s[1 ... n] */

/* 初始化前缀和数组 */
for (int i = 1; i <= n; i++) {
	s[i] = s[i - 1] + a[i];
}

/* 求下标区间[l, r]上的片段和 */
int sum = s[r] - s[l - 1];	// sum = a[l] + ... + a[r]

4.2 二维前缀和

对于矩阵 ( a i j ) n × m (a_{ij})_{n\times m} (aij)n×m ,规定 a i j a_{ij} aij二维前缀和 S i j S_{ij} Sij 为元素 a i j a_{ij} aij 左上角所有元素的和。

求法: S 0 j = S i 0 = S 00 = 0 ,   S i j = S i − 1 , j + S i , j − 1 − S i − 1 , j − 1 + a i j   ( i , j ≥ 1 ) S_{0j}=S_{i0}=S_{00}=0,\ S_{ij}=S_{i-1,j}+S_{i,j-1}-S_{i-1,j-1} + a_{ij}\ (i,j≥1) S0j=Si0=S00=0, Sij=Si1,j+Si,j1Si1,j1+aij (i,j1)

应用:求下图以 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) 为左上角、 ( x 2 , y 2 ) (x_2,y_2) (x2,y2) 为右下角的子矩阵(含边界)上的片段和,只需将整块左上矩形面积减去红、绿区域(不含待求区域边界)面积再补上多减去的重叠区域面积,即 S = S x 2 y 2 − S x 2 , y 1 − 1 − S x 1 − 1 , y 2 + S x 1 − 1 , y 1 − 1 S=S_{x_2y_2}-S_{x_2,y_1-1}-S_{x_1-1,y_2}+S_{x_1-1,y_1-1} S=Sx2y2Sx2,y11Sx11,y2+Sx11,y11

二维前缀和

/* int a[1 ... n][1 ... m], s[1 ... n][1 ... m] */

/* 初始化前缀和数组 */
for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
        s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
	}
}

/* 求以(x1, y1)为左上角、(x2, y2)为右下角的子矩阵(含边界)上的片段和 */
int sum = s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1];

4.3 一维差分

由数组 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an 构造差分数组 b 1 , b 2 , . . . , b n b_1, b_2, ..., b_n b1,b2,...,bn ,使得 a i = b 1 + b 2 + . . . + b i a_i=b_1+b_2+...+b_i ai=b1+b2+...+bi b i = a i − a i − 1 b_i=a_i-a_{i-1} bi=aiai1

操作:给区间 [ l ,   r ] [l,\ r] [l, r]上所有数加上 C C C ,时间复杂度 O ( 1 ) O(1) O(1)

  1. b l b_l bl 加上 C C C,使得 a l , a l + 1 . . . , a n a_l,a_{l+1}...,a_n al,al+1...,an 均加上 C C C
  2. b r + 1 b_{r+1} br+1 减去 C C C,使得 a r + 1 , a r + 2 , . . . , a n a_{r+1},a_{r+2},...,a_n ar+1,ar+2,...,an 均减去本不应加的 C C C

对于原差分数组的初始化亦可采用上述操作,赋值 a i a_i ai 即相当于给区间 [ i ,   i ] [i,\ i] [i, i] 加上 a i a_i ai

一维差分

/* int a[1 ... n], s[1 ... n] */

/* 给区间[l, r]上所有数加上c */
public void insert(int l, int r, int c) {
	b[l] += c;
    b[r + 1] -= c;
}

/* 初始化差分数组 */
for (int i = 1; i <= n; i++) {
	insert(i, i, a[i]);
}

/* 将操作过的差分数组变为原数组(前缀和与差分互为逆运算) */
for (int i = 1; i <= n; i++) {
	b[i] += b[i - 1];
}

4.4 二维差分

参考一维差分与二维前缀和,差分矩阵中每个数都蕴含于其右下矩阵中的每个数。

操作:给下图以 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) 为左上角、 ( x 2 , y 2 ) (x_2,y_2) (x2,y2) 为右下角的子矩形(含边界)加上 C C C,只需给整个右下角加 C C C,给红、绿区域各减 C C C,最后再给重叠区域加上多减的 C C C 即可

对于原差分矩阵初始化操作亦可采用上述操作,参考一维差分

二维差分

/* int a[1 ... n][1 ... m], s[1 ... n][1 ... m] */

/* 给以(x1, y1)为左上角、(x2, y2)为右下角的子矩阵(含边界)加上c */
public void insert(int x1, int y1, int x2, int y2, int c) {
    b[x1][y1] += c;
    b[x2 + 1][y1] -= c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y2 + 1] += c;
}

/* 初始化差分矩阵 */
for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
        insert(i, j, i, j, a[i][j]);
	}
}

/* 将操作过的差分矩阵变为原矩阵:求差分矩阵的前缀和 */
for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
        b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];
	}
}

5 位运算

例题

  1. n n n 的二进制表示中第 k k k 位数字:n >> k & 1 (先把第 k k k 位数字移到最后一位,再看个位是几,即和 1 1 1按位与运算)
  2. lowbit(n):返回 n n n 的最后一位 1 1 1
public int lowbit(int x) {
    return x & -x;  // -n = ~n + 1
}

/* 应用 */
// 输出整数x的二进制表示(31位)
for (int i = 0; i < 31; i++) {
	System.out.print(x >> i & 1);
}

// 统计x的二进制表示中有几位1
int cnt = 0;
while (x) {
    x -= lowbit(x);
    cnt++;
}

6 双指针算法

常见的双指针问题:

  1. 对于一个序列,用两个指针维护一段区间
  2. 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作
/* 朴素算法 O(n^2) */
// for (int i = 0; i < n; i++) {
//	 for (int j = i; j < n; j++) {
//		 ...
//	 }
// }

/* 双指针优化后的算法 O(n) */
/* 例1 */
for (int i = 0, j = 0; i < n; i++) {	// i为子序列右端点,j为左端动点
    while (j < i && check(i, j)) {
        ...
        j++;
    }
    ...
}
/* 例2 */
for (int i = 0; i < n;) {	// i为子序列左端点,j为动态右端动点
    int j = i;
    while (j < n && check(i, j)) {
        ...
        j++;
    }
    ...
    i = j + 1;	// 将i直接移至j附近
}

7 离散化

高度分散的整数 → 0 , 1 , 2 , . . . , n − 1 \rightarrow 0, 1, 2, ..., n-1 0,1,2,...,n1 1 , 2 , . . . , n 1, 2, ..., n 1,2,...,n

List<Integer> alls = new ArrayList<>();		// 存储所有待离散化的值

/* 离散化(保序) */
Collections.sort(alls);		// 将所有值排序
alls = new ArrayList<>(new HashSet<>(alls));	// 去重

/* 根据离散化的值k获取原来的值 x */
int x = alls.get(k);

/* 二分求出x对应的离散化的值 */
int find(int x) {
    int l = 0, r = alls.size() - 1;
    while (l < r) { // 找到第一个大于等于x的位置(唯一)
        int mid = l + r >> 1;
        if (alls.get(mid) >= x) r = mid;
        else l = mid + 1;
    }
    return r + 1;	// 这里+1是为了映射到1, 2, ..., alls.size()
}

8 区间合并

  1. 先将所有区间按左端点大小排序
  2. 当前维护区间与下一区间之间分三种情况:包含、有交集(含端点)、无交集
    • 包含:无需操作(实为有交集的特殊情况)
    • 有交集:更新当前区间右端点为较大的即可,继续维护
    • 无交集:结束维护当前区间并保存,更新为下一区间
  3. 迭代结束后保存当前维护区间

区间合并

// 使用 List<int[]> 存储区间,int[0]表示左端点,int[1]表示右端点

/* 合并区间 */
List<int[]> merge(List<int[]> segs) {
    List<int[]> res = new ArrayList<>();
    
    segs.sort(Comparator.comparingInt(a -> a[0])); // 按左端点大小排序
    
    int st = Integer.MIN_VALUE, ed = Integer.MIN_VALUE; // 当前维护区间(初始化为负无穷)
    for (int[] seg : segs) {
        if (ed < seg[0]) {	// 若与当前维护区间无交集
            if (st != Integer.MIN_VALUE) {
                res.add(new int[]{st, ed});	// 当前区间结束维护并保存
            }
            st = seg[0];	// 转移至此区间
            ed = seg[1];
        } else {
            ed = Math.max(ed, seg[1]);	// 有交集则比较右端点
        }
    }

    if (st != Integer.MIN_VALUE) {
        res.add(new int[]{st, ed});	// 保存最后一个区间
    }
    return res;
}
  • 27
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Algorithms   本次README修订为算法仓库Algorithms的第100次commit,首先我们庆祝自2016年8月4日本仓库建立以来Dev-XYS在算法学习方面取得的显著进步!   这里有各种算法的C++代码,任何人可以在自己的任何程序中使用,欢迎大家指出代码中的错误以及有待改进的地方。   本仓库内所有代码的授权方式为Unlicense,大家如果使用我的代码开发自己的软件挣了大钱,或是参考我的代码在NOI中得了金牌,我都会很高兴的。使用这里的代码之后,你可以自主选择是否公开源代码。总而言之,你可以把这里的代码当作你自己写的一样,无论怎样使用都是被允许的。但是,我不对本仓库内代码的正确性负责。大家要是使用我的代码开发软件而导致程序崩溃,或是参考我的代码考试时出错,请不要向我抱怨。如果你愿意,遇到问题可以在Issues中提出来,我们共同解决。我们不赞成Pull Request,因为本仓库主要储存作者已经学习的算法,全部代码均由作者本人负责维护与更新。   以下索引提供了本仓库内算法的中文名,方便大家查找。更新可能有很长时间的延迟,不保证所有算法的名称都在列表中出现。 Index --------------------------Contents-------------------------- --------------------------FileName-------------------------- AC自动机 Aho-Corasick-Automation 单源最短路径(SPFA) Bellman-Ford(Queue-Optimised) 单源最短路径(Bellman-Ford) Bellman-Ford 使用Edmonds-Karp进行二分图匹配 Bigrpah-Matching(Edmonds-Karp) 普通的二叉搜索树 Binary-Search-Tree 广度优先搜索 Breadth-First-Search 冒泡排序 Bubble-Sort 桶排序 Bucket-Sort 组合数的递推求解 Combination(Recursion) 枚举组合 Combination 基本的复数类 Complex-Number 割点 Cut-Vertex 深度优先搜索 Depth-First-Search 堆优化的Dijkstra算法 Dijkstra(Heap-Optimised) 并查集 Disjoint-Set-Union 最大流Edmonds-Karp算法 Edmonds-Karp 欧拉函数 Euler's-Totient-Function 有向图的欧拉回路 Eulerian-Tour(Digraph) 拓展欧几里得算法 Extended-Euclid 简单的快速幂 Fast-Exponentiation 树状数组 Fenwick-Tree 所有结点对之间的最短路径(Floyd) Floyd-Warshall 凸包算法(Graham扫描法) Graham-Scan 辗转相除法求最大公约数 Greatest-Common-Divisor 堆排序 Heap-Sort ISAP算法 Improved-Shortest-Augmenting-Path(Naive) 插入排序 Insertion-Sort 字符串匹配(KMP) Knuth-Morris-Pratt 最小生成树(Kruskal) Kruskal 最近公共祖先(Tarjan) Least-Common-Ancestor(Tarjan) 使用后缀数组求解最长公共子串 Longest-Common-Substring 最长上升子序列(n·log(n)) Longest-Increasing-Subsequence(n·log(n)) 倍增法求最近公共祖先 Lowest-Common-Ancestor(Doubling) 朴素的矩阵乘法 Matrix-Multiplication(Naive) 归并排序 Merge-Sort 最小堆 Min-Heap 乘法逆元 Modular-Multiplicative-Inverse 仅支持单点修改的可持久化线段树(维护区间和值) Persistent-Segment-Tree(Sum) 试除法素数测试 Prime-Check(Naive) 线性的素数筛法 Prime-Sieve(Linear) 队列的基本操作 Queue 快速排序的优化本 Quick-Sort(Extra-Optimised) 快速排序的随机化本 Quick-Sort(Randomized) 快速排序 Quick-Sort 使用向量叉积判断两个有向线段的时针关系 Segment-Direction 线段树维护区间最大值 Segment-Tree(Maximum) 线段树维护区间最小值 Segment-Tree(Minimum) 线段树维护区间和值 Segment-Tree(Sum) 普通的选择算法 Selection Eratosthenes素数筛法 Sieve-of-Erotosthenes 指针的单向链表 Singly-Linked-List(Pointer) 跳表 Skip-List ST表 Sparse-Table 伸展树 Splay 博弈论SG函数 Sprague-Grundy 栈的基本操作 Stack 递推法求解无符号第一类斯特林数 Stirling-Number(Cycle,Unsigned,Recursion) 递推法求解第二类斯特林数 Stirling-Number(Subset,Recursion) 倍增法求解后缀数组 Suffix-Array(Doubling) 倍增法求解后缀数组(附带Height数组) Suffix-Array-with-Height(Doubling) 使用Tarjan算法求解强连通分量 Tarjan(Strongly-Connected-Components) 数组的字典树 Trie(Array) 指针的字典树 Trie(Pointer)
目录 目录 1 Graph 图论 3 | DAG 的深度优先搜索标记 3 | 无向图找桥 3 | 无向图连通度(割) 3 | 最大团问题 DP + DFS 3 | 欧拉路径 O(E) 3 | DIJKSTRA 数组实现 O(N^2) 3 | DIJKSTRA O(E * LOG E) 4 | BELLMANFORD 单源最短路 O(VE) 4 | SPFA(SHORTEST PATH FASTER ALGORITHM) 4 | 第 K 短路(DIJKSTRA) 5 | 第 K 短路(A*) 5 | PRIM 求 MST 6 | 次小生成树 O(V^2) 6 | 最小生成森林问题(K 颗树)O(MLOGM). 6 | 有向图最小树形图 6 | MINIMAL STEINER TREE 6 | TARJAN 强连通分量 7 | 弦图判断 7 | 弦图的 PERFECT ELIMINATION 点排列 7 | 稳定婚姻问题 O(N^2) 7 | 拓扑排序 8 | 无向图连通分支(DFS/BFS 邻接阵) 8 | 有向图强连通分支(DFS/BFS 邻接阵)O(N^2) 8 | 有向图最小点基(邻接阵)O(N^2) 9 | FLOYD 求最小环 9 | 2-SAT 问题 9 Network 网络流 11 | 二分图匹配(匈牙利算法 DFS 实现) 11 | 二分图匹配(匈牙利算法 BFS 实现) 11 | 二分图匹配(HOPCROFT-CARP 的算法) 11 | 二分图最佳匹配(KUHN MUNKRAS 算法 O(M*M*N)) 11 | 无向图最小割 O(N^3) 12 | 有上下界的最小(最大)流 12 | DINIC 最大流 O(V^2 * E) 12 | HLPP 最大流 O(V^3) 13 | 最小费用流 O(V * E * F) 13 | 最小费用流 O(V^2 * F) 14 | 最佳边割集 15 | 最佳点割集 15 | 最小边割集 15 | 最小点割集(点连通度) 16 | 最小路径覆盖 O(N^3) 16 | 最小点集覆盖 16 Structure 数据结构 17 | 求某天是星期几 17 | 左偏树 合并复杂度 O(LOG N) 17 | 树状数组 17 | 二维树状数组 17 | TRIE 树(K 叉) 17 | TRIE 树(左儿子又兄弟) 18 | 后缀数组 O(N * LOG N) 18 | 后缀数组 O(N) 18 | RMQ 离线算法 O(N*LOGN)+O(1) 19 | RMQ(RANGE MINIMUM/MAXIMUM QUERY)-ST 算法 (O(NLOGN + Q)) 19 | RMQ 离线算法 O(N*LOGN)+O(1)求解 LCA 19 | LCA 离线算法 O(E)+O(1) 20 | 带权值的并查集 20 | 快速排序 20 | 2 台机器工作调度 20 | 比较高效的大数 20 | 普通的大数运算 21 | 最长公共递增子序列 O(N^2) 22 | 0-1 分数规划 22 | 最长有序子序列(递增/递减/非递增/非递减) 22 | 最长公共子序列 23 | 最少找硬币问题(贪心策略-深搜实现) 23 | 棋盘分割 23 | 汉诺塔 23 | STL 中的 PRIORITY_QUEUE 24 | 堆栈 24 | 区间最大频率 24 | 取第 K 个元素 25 | 归并排序求逆序数 25 | 逆序数推排列数 25 | 二分查找 25 | 二分查找(大于等于 V 的第一个值) 25 | 所有数位相加 25 Number 数论 26 1 |递推求欧拉函数 PHI(I) 26 |单独求欧拉函数 PHI(X) 26 | GCD 最大公约数 26 | 快速 GCD 26 | 扩展 GCD 26 | 模线性方程 A * X = B (% N) 26 | 模线性方程组 26 | 筛素数 [1..N] 26 | 高效求小范围素数 [1..N] 26 | 随机素数测试(伪素数原理) 26 | 组合数学相关 26 | POLYA 计数 27 | 组合数 C(N, R) 27 | 最大 1 矩阵 27 | 约瑟夫环问题(数学方法) 27 | 约瑟夫环问题(数组模拟) 27 | 取石子游戏 1 27 | 集合划分问题 27 | 大数平方根(字符串数组表示) 28 | 大数取模的二进制方法 28 | 线性方程组 A[][]X[]=B[] 28 | 追赶法解周期性方程 28 | 阶乘最后非零位,复杂度 O(NLOGN) 29 递归方法求解排列组合问题 30 | 类循环排列 30 | 全排列 30 | 不重复排列 30 | 全组合 31 | 不重复组合 31 | 应用 31 模式串匹配问题总结 32 | 字符串 HASH 32 | KMP 匹配算法 O(M+N) 32 | KARP-RABIN 字符串匹配 32 | 基于 KARP-RABIN 的字符块匹配 32 | 函数名: STRSTR 32 | BM 算法的改进的算法 SUNDAY ALGORITHM 32 | 最短公共祖先(两个长字符串) 33 | 最短公共祖先(多个短字符串) 33 Geometry 计算几何 34 | GRAHAM 求凸包 O(N * LOGN) 34 | 判断线段相交 34 | 求多边形重心 34 | 三角形几个重要的点 34 | 平面最近点对 O(N * LOGN) 34 | LIUCTIC 的计算几何库 35 | 求平面上两点之间的距离 35 | (P1-P0)*(P2-P0)的叉积 35 | 确定两条线段是否相交 35 | 判断点 P 是否在线段 L 上 35 | 判断两个点是否相等 35 | 线段相交判断函数 35 | 判断点 Q 是否在多边形内 35 | 计算多边形的面积 35 | 解二次方程 AX^2+BX+C=0 36 | 计算直线的一般式 AX+BY+C=0 36 | 点到直线距离 36 | 直线与圆的交点,已知直线与圆相交 36 | 点是否在射线的正向 36 | 射线与圆的第一个交点 36 | 求点 P1 关于直线 LN 的对称点 P2 36 | 两直线夹角(弧度) 36 ACM/ICPC 竞赛之 STL 37 ACM/ICPC 竞赛之 STL 简介 37 ACM/ICPC 竞赛之 STL--PAIR 37 ACM/ICPC 竞赛之 STL--VECTOR 37 ACM/ICPC 竞赛之 STL--ITERATOR 简介 38 ACM/ICPC 竞赛之 STL--STRING 38 ACM/ICPC 竞赛之 STL--STACK/QUEUE 38 ACM/ICPC 竞赛之 STL--MAP 40 ACM/ICPC 竞赛之 STL--ALGORITHM 40 STL IN ACM 41 头文件 42 线段树 43 求矩形并的面积(线段树+离散化+扫描线) 43 求矩形并的周长(线段树+离散化+扫描线) 44
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Akira37

💰unneeded

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值