前言
用于记录在算法学习过程中遇到典型的题目,方便日后个人查看。
一、线段树
模板题
代码实现
class NumArray {
private int[] segmentTree ;
private int n ;
public NumArray(int[] nums) {
n = nums.length ;
segmentTree = new int[4*n] ; // 线段 区间值
// 构建线段树
build(1, 1, n, nums);
}
// 构建 线段树
private void build(int node, int s ,int e ,int[] nums) {
// node 代表线段树的当前节点
// [s,e] 代表当前线段树 维护的区间
// nums 记录向线段树中要加入的值
if(s == e) {
segmentTree[node] = nums[s-1] ;
return ;
}
int mid =s + (e-s) / 2 ;
// 维护左子树
build(2*node, s ,mid , nums);
// 维护右子树
build(2*node+1, mid+1 ,e , nums);
// 维护当前节点 等于 左右子树的区间值之和
segmentTree[node] = segmentTree[2*node]+segmentTree[2*node+1] ;
}
// 更新线段树 某个节点的值
public void change(int node, int s, int e, int index, int val) {
if(s == e) {
segmentTree[node] = val;
return ;
}
int mid =s + (e-s) / 2 ;
// 根据index 进行查找,查找index 所在的区间
if(index<=mid) { // 查找 左子树
change(node*2, s, mid, index, val) ;
}else { // 查找 又子树
change(node*2+1, mid+1, e, index, val) ;
}
segmentTree[node] = segmentTree[2*node]+segmentTree[2*node+1] ;
}
// 根据范围查询区间值
private int range(int node ,int s, int e ,int L, int R) {
// 如果要查询的范围 包含当前节点所维护的范围,直接返回当前范围的值
if(L<=s && R>=e) {
return segmentTree[node] ;
}
int count = 0;
// 依次遍历左右子树 来获得最终的子段和
int mid = s+(e-s)/2;
if(L<=mid) {
count += range(2*node, s, mid, L, R);
}
if(R>mid) {
count+= range(2*node+1, mid+1, e, L, R) ;
}
return count ;
}
public void update(int index, int val) {
change(1, 1, n, index+1, val);
}
public int sumRange(int left, int right) {
return range(1, 1, n, left+1, right+1) ;
}
}
二、拓扑排序
模板题
代码实现(链式前向星图)
class Solution {
// 使用邻接表进行存在图(也称作链式前向星存图)
private int N = 2002 ; // 结点数
private int M = 5005 ; // 边数
private int[] he = new int[N] ; // 头结点
private int[] cnts = new int[N] ; // 每个节点的入度数 (同时也起到当前结点是否被标记)
private int[] e = new int[M] ; // 边结点
private int[] ne = new int[M] ; // 邻接表中头结点所连接的边结点
private int idx ; // 记录边的编号
private int[] w = new int[M] ; // 边的权重
public void add(int a, int b, int c) { // 向链式前向星存图中添加结点
// a: 代表头结点
// b: 代表边结点
// c: 代表当前边的权重信息
e[idx] = b ; // 将边进行存储
w[idx] = c ; // 权重信息
// 模拟头插法
ne[idx] = he[a] ;
he[a] = idx ;
idx++ ;
}
public boolean canFinish(int numCourses, int[][] prerequisites) {
//1. 构建前向星存图
Arrays.fill(he, -1);
for(int[] pre : prerequisites) {
cnts[pre[1]]++ ;
add(pre[0],pre[1],0) ;
}
// 2.进行拓扑排序
Deque<Integer> d = new ArrayDeque<>() ;
for(int i= 0; i< numCourses ;i++) {
if(cnts[i] == 0) {
d.addLast(i);
}
}
while(!d.isEmpty()) {
int poll = d.pollFirst() ;
System.out.println(poll) ;
for(int i=he[poll] ; i!=-1; i=ne[i]) {
int j= e[i] ;
if(--cnts[j] == 0) d.addLast(j);
}
}
// 判断是否存在环 全部结点等于-1 即不存在环,反之则存在环
for(int i=0 ; i<numCourses; i++) {
if(cnts[i] != 0) {
return false;
}
}
return true;
}
}