算法模板题记录

前言

用于记录在算法学习过程中遇到典型的题目,方便日后个人查看。

一、线段树

模板题

LeetCode 307

代码实现

 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) ; 
    	
    }
}

二、拓扑排序

模板题

LeetCode 207

代码实现(链式前向星图)

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; 
    	
    		

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值