常见算法框架

一、BFS框架

// 计算从起点 start 到终点 target 的最近距离
int BFS(Node start, Node target) {
    Queue<Node> q; // 核心数据结构
    Set<Node> visited; // 避免走回头路

    q.offer(start); // 将起点加入队列
    visited.add(start);
    int step = 0; // 记录扩散的步数

    while (q not empty) {
        int sz = q.size();
        /* 将当前队列中的所有节点向四周扩散 */
        for (int i = 0; i < sz; i++) {
            Node cur = q.poll();
            /* 划重点:这里判断是否到达终点 */
            if (cur is target)
                return step;
            /* 将 cur 的相邻节点加入队列 */
            for (Node x : cur.adj())
                if (x not in visited) {
                    q.offer(x);
                    visited.add(x);
                }
        }
        /* 划重点:更新步数在这里 */
        step++;
    }
}

二、二分查找

int left_bound(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    // 搜索区间为 [left, right]
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            // 搜索区间变为 [mid+1, right]
            left = mid + 1;
        } else if (nums[mid] > target) {
            // 搜索区间变为 [left, mid-1]
            right = mid - 1;
        } else if (nums[mid] == target) {
            // 收缩右侧边界
            right = mid - 1;
        }
    }
    // 检查出界情况
    if (left >= nums.length || nums[left] != target)
        return -1;
    return left;
}
int right_bound(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid - 1;
        } else if (nums[mid] == target) {
            // 这里改成收缩左侧边界即可
            left = mid + 1;
        }
    }
    // 这里改为检查 right 越界的情况,见下图
    if (right < 0 || nums[right] != target)
        return -1;
    return right;
}
int binary_search(int[] nums, int target) {
    int left = 0, right = nums.length - 1; 
    while(left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid - 1; 
        } else if(nums[mid] == target) {
            // 直接返回
            return mid;
        }
    }
    // 直接返回
    return -1;
}

三、滑动窗口

/* 滑动窗口算法框架 */
void slidingWindow(string s, string t) {
    unordered_map<char, int> need, window;
    for (char c : t) need[c]++;

    int left = 0, right = 0;
    int valid = 0; 
    while (right < s.size()) {
        // c 是将移入窗口的字符
        char c = s[right];
        // 右移窗口
        right++;
        // 进行窗口内数据的一系列更新
        ...

        /*** debug 输出的位置 ***/
        printf("window: [%d, %d)\n", left, right);
        /********************/

        // 判断左侧窗口是否要收缩
        while (window needs shrink) {
            // d 是将移出窗口的字符
            char d = s[left];
            // 左移窗口
            left++;
            // 进行窗口内数据的一系列更新
            ...
        }
    }
}

四、线段树

static int n = 10; // n是元素个数
static int[] array = {0, 1, 5, 1, 3, 4, 2, 0, 9, 0, 9};
// array是原序列(第一个0是占array[0]位的)
static Node[] tree = new Node[4*n]; // tree是线段树

public static void main(String[] args) {
    initTree();
    build(1, 10, 1); // 利用build函数建树
    System.out.println("操作1:[2,5]的区间和是:" + query(2, 5, 1));
    // 利用query函数搜索区间和
    modify(5, 9, 1); // 利用modify函数实现单点修改(元素5从4改为9)
    System.out.println("操作2:元素5从4改为9,此时[2,5]的区间和是:" + query(2, 5, 1));
    modifySegment(3, 4, 3, 1);
    // 利用modifySegment函数将[3,4]每个元素增加3
    System.out.println("操作3:区间[3,4]每个元素+3,此时[2,5]的区间和是:" + query(2, 5, 1));
}

static void initTree (){
    for(int i = 0; i < tree.length; i++){
        tree[i] = new Node(0, 0, 0, 0);
    }
}

static void updateNode (int num) { // num是当前节点序号
    tree[num].sum = tree[num * 2].sum + tree[num * 2 + 1].sum;
}

static void build (int l, int r, int num) { // 建树
    tree[num].l = l;
    tree[num].r = r;
    if (l == r) { // l = r说明到达叶子节点
        tree[num].sum = array[l];
        return;
    }
    int mid = (l + r) / 2;
    build(l, mid, num * 2); // 递归左儿子
    build(mid + 1, r, num * 2 + 1); // 递归右儿子
    updateNode(num);
}

static void modify (int i, int value, int num) { // 把元素i修改为值value
    if (tree[num].l == tree[num].r) { // 到达叶子节点
        tree[num].sum = value;
        return;
    }
    int mid = (tree[num].l + tree[num].r) / 2;
    if (i <= mid) {
        modify(i, value, num * 2); // 递归左儿子
    }
    else {
        modify(i, value, num * 2 + 1); // 递归右儿子
    }
    updateNode(num);
}

static void modifySegment(int l, int r, int value, int num) { // [l,r]每一项都增加value
    if (tree[num].l == l && tree[num].r == r) { // 找到当前区间
        tree[num].sum += ( r - l + 1 ) * value; // r-l+1是区间元素个数
        tree[num].lazy += value;
        return;
    }
    int mid = (tree[num].l + tree[num].r) / 2;
    if (r <= mid) { // 在左区间
        modifySegment(l, r, value, num * 2);
    }
    else if (l > mid) { // 在右区间
        modifySegment(l, r, value, num * 2 + 1);
    }
    else { // 分成2块
        modifySegment(l, mid, value, num * 2);
        modifySegment(mid + 1, r, value, num * 2 + 1);
    }
    updateNode(num);
}

static void pushDown(int num) {
    if(tree[num].l == tree[num].r) { // 叶节点不用下传标记
        tree[num].lazy = 0; // 清空当前标记
        return;
    }
    tree[num * 2].lazy += tree[num].lazy; // 下传左儿子的懒惰标记
    tree[num * 2 + 1].lazy += tree[num].lazy; // 下传右儿子的懒惰标记
    tree[num * 2].sum += (tree[num * 2].r - tree[num * 2].l + 1) * tree[num].lazy; // 更新左儿子的值
    tree[num * 2 + 1].sum += (tree[num * 2 + 1].r - tree[num * 2 + 1].l + 1) * tree[num].lazy; // 更新右儿子的值
    tree[num].lazy=0; // 清空当前节点的懒惰标记
}

static int query (int l, int r, int num) {
    if (tree[num].lazy != 0) { // 下传懒惰标记
        pushDown(num);
    }
    if (tree[num].l == l && tree[num].r == r) { // 找到当前区间
        return tree[num].sum;
    }
    int mid = (tree[num].l + tree[num].r) / 2;
    if (r <= mid) { // 在左区间
        return query(l, r, num * 2);
    }
    if (l > mid) { // 在右区间
        return query(l, r, num * 2 + 1);
    }
    return query(l, mid, num * 2) + query(mid + 1, r, num * 2 + 1); // 分成2块
}

static class Node {
    int l; // l是区间左边界
    int r; // r是区间右边界
    int sum; // sum是区间元素和
    int lazy; // lazy是懒惰标记

    public Node (int l, int r, int sum, int lazy){
        this.l = l;
        this.r = r;
        this.sum = sum;
        this.lazy = lazy;
    }
}

五、并查集

#include<bits/stdc++.h>
using namespace std;
int a[10005];
int unionfind(int root)
{
	if(a[root] == root)
		return root;
	return a[root] = unionfind(a[root]);	//路径压缩
}
int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n;i++)
	{
		a[i] = i;
	}
	while (m--)
	{
		int  x, y;
		cin >> x >> y;
		int root1 = unionfind(x);
		int root2 = unionfind(y);
		if(root1 != root2)
		{
			a[root2] = root1;
		}
		else
		{
			cout << root1 <<endl;
		}
	return 0;
}

六、Dijkstra算法

#include <bits/stdc++.h>
using namespace std;
int dis[10005];
int visit[10005];
int edge[5000][5000];
int n, m, s;
void dijkstra()
{
	int minv;
	int u;
	visit[s] == 1;
	for (int i = 1; i <= n; i++) //附上初始值
	{
		if (i == s)
			dis[i] == 0;
		else
			dis[i] = edge[s][i] == 0 ? INT_MAX : edge[s][i];
	}
	for (int j = 1; j <= n; j++)
	{
		minv = INT_MAX;
		for (int i = 1; i <= n; i++) //找出距离出发点最近,且没有使用过的点
		{
			if (dis[i] < minv && visit[i] == 0)
			{
				minv = dis[i];
				u = i;
			}
		}
		visit[u] = 1;
		for (int i = 1; i <= n; i++) //松弛
		{
			if (visit[i] == 0 && edge[u][i] != 0)
				dis[i] = min(dis[i], dis[u] + edge[u][i]);
		}
	}
	for (int i = 1; i <= n; i++)
	{
		cout << dis[i];
		if (i != n)
			cout << " ";
	}
	cout << endl;
}
int main()
{
	int u, v, w;
	cin >> n >> m >> s;
	while (m--)
	{
		cin >> u >> v >> w;
		edge[u][v] = w;
	}
	dijkstra();
	return 0;
}

七、快速幂

#include <bits/stdc++.h>
using namespace std;
int solve(int basic, int p, int k)
{
	int res = 1;
	int a = basic;
	while (p)
	{
		if (p & 1)
		{
			res = res * a;
		}
		a = a * a;
		p = p >> 1;
	}
	return res;
}
int main()
{
	int b, p;
	cin >> b >> p;
	int res = solve(b, p);
	cout << res << endl;
	return 0;
}

八、堆排序(最小堆)

//最小堆
#include <bits/stdc++.h>
using namespace std;
int a[100] = {1, 3, 6, 4, 9, 2, 5, 4};
int n = 8;
void fixdown(int i)	//向下调整
{
	int temp = a[i];
	int j = 2 * i + 1;
	while (j <= n)
	{
		if (j + 1 < n && a[j] > a[j + 1])
		{
			j++;
		}
		if (a[j] >= temp)
		{
			break;
		}
		a[i] = a[j];
		i = j;
		j = 2 * i + 1;
	}
	a[i] = temp;
}
void fixup(int i)		//向上调整
{
	int temp = a[i];
	int j = (i - 1) / 2;
	while (j >= 0 && i != 0)
	{
		if (a[j] <= temp)
			break;
		a[i] = a[j];
		i = j;
		j = (i - 1) / 2;
	}
	a[i] = temp;
}
void buildheap()	//建堆
{
	for (int i = n / 2; i >= 0; i--)
	{
		fixdown(i);
	}
}
void insertNode(int i)	//插入一个数
{
	a[n] = i;
	n++;
	fixup(n - 1);
}
void deleteNode() 	//删除顶点
{	
	swap(a[0], a[n - 1]);
	n--;
	fixdown(0);
}
void printarray()	//打印数组
{
	for (int i = 0; i < n; i++)
	{
		cout << a[i] << " ";
	}
	cout << endl;
}
int main()
{
	buildheap();		//建堆
	printarray();		//打印
	insertNode(0);		//插入一个0
	printarray();		//打印
	deleteNode();		//删除顶点
	printarray();		//打印
	return 0;
}

九、线性筛素数

#include<cstdio>
#include<cstring>
using namespace std;
bool isPrime[100000010];
int prime[1000010];
void getPrime(int n)
{
	int cnt = 1;
	memset(isPrime, 1, sizeof(isPrime));
	isPrime[1] = 0;
	for (int i = 2; i <= n; i++)
	{
		if(isPrime[i])
			prime[cnt++] = i;
		for (int j = 1; j <= cnt && i * prime[j] <= n; j++)
		{
			isPrime[i * prime[j]] = 0;
			if(i % prime[j] == 0)
				break;
		}
	}
}
int main()
{
	int n, q, m;
	scanf("%d %d", &n, &q);
	getPrime(n);
	while(q--)
	{
		scanf("%d", &m);
		printf("%d\n", prime[m]);
	}
	return 0;
}
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值