AK F.*ing leetcode 流浪计划之最近公共祖先(倍增算法)

news2024/11/25 12:38:52

欢迎关注更多精彩
关注我,学习常用算法与数据结构,一题多解,降维打击。

本期话题:在树上查找2个结点的最近公共祖先

问题提出

最近公共祖先定义

最近公共祖先简称 LCA(Lowest Common Ancestor)。两个节点的最近公共祖先,就是这两个点的公共祖先里面,离根最远(深度最深)的那个。

问题

参考地址:https://www.luogu.com.cn/problem/P3379
给定一棵树,询问每两个结点的最近公共祖先,一般会询问多次。

朴素做法

  1. 利用dfs求出所有结点的深度和父亲结点。
  2. 查询时把深度大的结点往上移,直到两个结点深度一样。然后两个结点同时往上移,直到两结点相遇。

复杂度分析

第1步求深度和父亲结点,需要遍历所有结点,复杂度是O(n)。
第2步在极端情况下是O(n) , 在多次查询的情况下,效率很低。

空间换时间

试想一下我们给每1个结点分配1个空间来存储往上移n个位置到达的祖先结点。
当我们要查询两个公共祖先时,就可以使用二分查找的方法来加速。


以A, B为例,可以看到后面黄色部分是公共祖先,我们要找的是最左边的10号祖先。只要利用二分查找即可找到。
该方法可以把查询复杂度降低到log(n). 但同时空间复杂度是O(n^2)。

优化空间(倍增算法)

参考资料:https://oi-wiki.org//graph/lca/#%E5%80%8D%E5%A2%9E%E7%AE%97%E6%B3%95
上面的方法的问题是空间分配的太多了,而且仔细观察,空间是冗余的。
比如A往上1个的祖先分配的数组和A的数组是高度重合的,可以看出是有递归或继承关系的。而且我们每次都是取的数组的一半。

那么我们可以存储往上数2^n个的祖先。
即存储往上1个,2个,4个。。。的祖先分别是谁。
查询的时候,由于任意数字都可以用2进制进行组合而成,可以遍历到所有祖先。
具体算法可以类比二分算法。

代码模板

题目链接:https://www.luogu.com.cn/problem/P3379



#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<cmath>
#include<algorithm>

using namespace std;

const int M = 500000 + 10;
const int N = 500000 + 10;
const int bitL = 22;
int head[N];
int to[M * 2], nextEdge[M * 2];
int len;
int h[N];
int father[bitL][N];

void initPara(int n)
{
	len = 0;
	for (int i = 0; i < n; i++)
	{
		head[i] = -1;
	}
}

void add(int a, int b)
{
	to[len] = b;
	nextEdge[len] = head[a];
	head[a] = len++;
}

void dfs(int x, int fa)
{
	if (fa == -1) h[x] = 0;
	else {
		h[x] = h[fa] + 1;
		father[0][x] = fa;
		// 利用倍增算法初始化father
		for (int t = 1; t < bitL && (1<<t)<=h[x]; t++) {
			father[t][x] = father[t-1][father[t - 1][x]];
		}
	}
	int i;
	for (i = head[x]; i != -1; i = nextEdge[i])
	{
		int j = to[i];
		if (fa==j)continue;
		dfs(j, x);
	}
}

int lca(int a, int b) {
	if (h[a] < h[b]) {
		return lca(b, a);
	}

	// 先将两个结点跳到一样高度
	int gap = h[a] - h[b];
	for (int t = bitL-1; t>=0; t--) {
		if (gap & (1 << t))a = father[t][a];
	}
	if (a == b)return a;
	gap = h[a];
	// 利用二分查找找到深度最低的且不一样的结点。
	for (int t = bitL-1; t >= 0; t--) {
		if (gap <=(1 << t))continue;
		if (father[t][a] == father[t][b])continue;
		a = father[t][a];
		b = father[t][b];
		gap -= 1 << t;
	}
	
	return father[0][a]; // 再往上1个既是公共祖先
}

void solve()
{
	int t;
	int n, m, s;

	scanf("%d%d%d", &n, &m, &s);
	s--;
	initPara(n);
	int a, b;
	for (int i = 0; i < n - 1; ++i) {
		scanf("%d%d", &a, &b);
		a--, b--;
		add(a, b);
		add(b, a);
	}

	dfs(s, -1);

	/*for (int i = 0; i < n; ++i) {
		printf("%d: %d\n", i, h[i]);
	}*/

	while (m--) {
		scanf("%d%d", &a, &b);
		a--, b--;
		printf("%d\n", 1+lca(a, b));
	}
}

void test() {
	int t;
	int n=5000, m=500000, s=1;

	//scanf("%d%d%d", &n, &m, &s);
	s--;
	initPara(n);
	int a, b;
	for (int i = 0; i < n - 1; ++i) {
		a = i, b = i + 1;
		add(a, b);
		add(b, a);
	}

	dfs(s, -1);
	//printf("%d\n", 1 + lca(10, 5000-1));
	while (m--) {
		a = (m+102)%n, b =( 3823+m*2)%n;
		//printf("%d\n", m);
		if(lca(a, b)!=min(a,b))
		printf("%d %d %d\n", 1 + lca(a, b), a+1, b+1);
	}
}

int main()
{
	solve();
	//test();
	return 0;
}



/*

5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5

12 11 8
8 1
8 9
8 12
1 5
1 7
7 6
9 4
9 11
9 2
4 3
12 10

1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
*/

练习一

链接:https://loj.ac/p/10135
注意点:需要对结点进行编号,无公共祖先时返回-1


#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <cmath>
#include <algorithm>
#include <map>

using namespace std;



const int M = 500000 + 10;
const int N = 500000 + 10;

map<int, int> num2Ind;
int indLen;

void initIndex() {
    num2Ind.clear();
    indLen = 0;
}

int getIndex(int n) {
    if (num2Ind.count(n) == 0)
        return -1;

    return num2Ind[n];
}

int addIndex(int n) {
    if (num2Ind.count(n) == 0)
        num2Ind[n] = indLen++;

    return num2Ind[n];
}

const int bitL = 22;
int head[N];
int to[M * 2], nextEdge[M * 2];
int len;
int h[N];
int father[bitL][N];

void initPara(int n) {
    len = 0;

    for (int i = 0; i < n; i++) {
        head[i] = -1;
    }
}

void add(int a, int b) {
    to[len] = b;
    nextEdge[len] = head[a];

    head[a] = len++;
}

void dfs(int x, int fa) {
    if (fa == -1)
        h[x] = 0;
    else {
        h[x] = h[fa] + 1;
        father[0][x] = fa;

        for (int t = 1; t < bitL && (1 << t) <= h[x]; t++) {
            father[t][x] = father[t - 1][father[t - 1][x]];
        }
    }

    int i;

    for (i = head[x]; i != -1; i = nextEdge[i]) {
        int j = to[i];

        if (fa == j)
            continue;

        dfs(j, x);
    }
}

int lca(int a, int b) {
    if (h[a] < h[b]) {
        return lca(b, a);
    }

    int gap = h[a] - h[b];

    for (int t = bitL - 1; t >= 0; t--) {
        if (gap & (1 << t))
            a = father[t][a];
    }

    if (a == b)
        return a;

    gap = h[a];

    for (int t = bitL - 1; t >= 0; t--) {
        if (gap <= (1 << t))
            continue;

        if (father[t][a] == father[t][b])
            continue;

        a = father[t][a];
        b = father[t][b];
        gap -= 1 << t;
    }

    return father[0][a];
}

void solve() {
    int n, m;
    int a, b, s;
    scanf("%d", &n);
    initPara(n);

    for (int i = 0; i < n; ++i) {
        scanf("%d%d", &a, &b);

        if (b == -1) {
            s = addIndex(a);
            continue;
        }

        a = addIndex(a);
        b = addIndex(b);
        add(a, b);
        add(b, a);
    }

    dfs(s, -1);

    scanf("%d", &m);
    /*for (int i = 0; i < n; ++i) {
        printf("%d: %d\n", i, h[i]);
    }*/

    while (m--) {
        scanf("%d%d", &a, &b);

        a = getIndex(a);
        b = getIndex(b);

        if (a < 0 || b < 0 || a == b) {
            puts("0");
            continue;
        }

        int lcab = lca(a, b);

        if (lcab == a)
            puts("1");
        else if (lcab == b)
            puts("2");
        else
            puts("0");
    }
}


int main() {
    solve();
    return 0;
}



/*
3
2 -1
1 2
3 1
2
1 2
2 3

2
1 -1
1 2
2
1 2
2 1


12
8 -1
8 1
8 9
8 12
1 5
1 7
7 6
9 4
9 11
9 2
4 3
12 10
11
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12


10
234 -1
12 234
13 234
14 234
15 234
16 234
17 234
18 234
19 234
233 19
5
234 233
233 12
233 13
233 15
233 19
*/

练习二

链接:https://loj.ac/p/2610
算法思路:先用最小生成算法把所有大的边加入到树中。
利用倍增算法建立祖先关系,以及到祖先链路上的最小负载。
查询A,B最小负载为=min(A到公共祖先最小负载,B到公共祖先最小负载)。
具体实现分别从A,B查找最近公共祖先时记录链路上的最小值。
注意点:需要事先判断是否可达。题目中规定A!=B。
利用并查集点击前往判断是否在一棵树中。

#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<cmath>
#include<algorithm>
#include<vector>

using namespace std;


class UnionFindSet {
private:
	vector<int> father; // 父结点定义,father[i]=i时,i为本集合的代表
	vector<int> height; // 代表树高度,初始为1
	int nodeNum; // 集合中的点数

public:
	UnionFindSet(int n); // 初始化
	bool Union(int x, int y); // 合并
	int Find(int x);

	bool UnionV2(int x, int y); // 合并
	int FindV2(int x);
};

UnionFindSet::UnionFindSet(int n) : nodeNum(n + 1) {
	father = vector<int>(nodeNum);
	height = vector<int>(nodeNum);
	for (int i = 0; i < nodeNum; ++i) father[i] = i, height[i] = 1; // 初始为自己
}

int UnionFindSet::Find(int x) {
	while (father[x] != x) x = father[x];
	return x;
}

bool UnionFindSet::Union(int x, int y) {
	x = Find(x);
	y = Find(y);

	if (x == y)return false;
	father[x] = y;
	return true;
}


int UnionFindSet::FindV2(int x) {
	int root = x; // 保存好路径上的头结点
	while (father[root] != root) {
		root = father[root];
	}
	/*
	从头结点开始一直往根上遍历
	把所有结点的father直接指向root。
	*/
	while (father[x] != x) {
		// 一定要先保存好下一个结点,下一步是要对father[x]进行赋值
		int temp = father[x];
		father[x] = root;
		x = temp;
	}

	return root;
}

/*
需要加入height[]属性,初始化为1.
*/
//合并结点
bool UnionFindSet::UnionV2(int x, int y) {
	x = Find(x);
	y = Find(y);
	if (x == y) {
		return false;
	}
	if (height[x] < height[y]) {
		father[x] = y;
	}
	else if (height[x] > height[y]) {
		father[y] = x;
	}
	else {
		father[x] = y;
		height[y]++;
	}
	return true;
}

const int M = 500000 + 10;
const int N = 500000 + 10;
const int bitL = 22;
int head[N];
int to[M * 2], nextEdge[M * 2], weight[M * 2];
int len;
int h[N];
int father[bitL][N];
int dis[bitL][N];

void initPara(int n)
{
	len = 0;
	for (int i = 0; i < n; i++)
	{
		head[i] = -1;
		h[i] = -1;
	}
}

void add(int a, int b, int w)
{
	to[len] = b;
	weight[len] = w;
	nextEdge[len] = head[a];

	head[a] = len++;
}

void dfs(int x, int fa, int w)
{
	if (fa == -1) h[x] = 0;
	else {
		h[x] = h[fa] + 1;
		father[0][x] = fa;
		dis[0][x] = w;
		for (int t = 1; t < bitL && (1 << t) <= h[x]; t++) {
			father[t][x] = father[t - 1][father[t - 1][x]];
			dis[t][x] = min(dis[t - 1][x], dis[t - 1][father[t - 1][x]]);
		}
	}
	int i;
	for (i = head[x]; i != -1; i = nextEdge[i])
	{
		int j = to[i];
		if (fa == j)continue;
		dfs(j, x, weight[i]);
	}
}

int lca(int a, int b) {
	if (h[a] < h[b]) {
		return lca(b, a);
	}

	int gap = h[a] - h[b];
	for (int t = bitL - 1; t >= 0; t--) {
		if (gap & (1 << t))a = father[t][a];
	}
	if (a == b)return a;
	gap = h[a];
	for (int t = bitL - 1; t >= 0; t--) {
		if (gap <= (1 << t))continue;
		if (father[t][a] == father[t][b])continue;
		a = father[t][a];
		b = father[t][b];
		gap -= 1 << t;
	}

	return father[0][a];
}


int optDis(int a, int b) {
	if (h[a] < h[b]) {
		return optDis(b, a);
	}
	int d = 1e6;
	int gap = h[a] - h[b];
	for (int t = bitL - 1; t >= 0; t--) {
		if (gap & (1 << t)) {
			d=min(d, dis[t][a]);
			a = father[t][a];
		}
	}
	if (a == b)return d;
	gap = h[a];
	for (int t = bitL - 1; t >= 0; t--) {
		if (gap <= (1 << t))continue;
		if (father[t][a] == father[t][b])continue;
		d = min(d,dis[t][a]);
		d = min(d,dis[t][b]);
		a = father[t][a];
		b = father[t][b];
		gap -= 1 << t;
	}
	d = min(d, min(dis[0][a], dis[0][b]));
	return d;
}

bool cmp(vector<int> &a, vector<int> &b) {
	return a[2] > b[2];
}

void solve()
{
	int n, m;
	int a, b, w;
	scanf("%d%d", &n, &m);
	initPara(n);
	auto us = UnionFindSet(n);
	vector<vector<int>> eds;
	for (int i = 0; i < m; ++i) {
		scanf("%d%d%d", &a, &b, &w);
		a--, b--;
		eds.push_back({a,b,w});
	}

	sort(eds.begin(), eds.end(), cmp);
	for (auto ed : eds) {
		if (us.UnionV2(ed[0], ed[1])) {
			add(ed[0], ed[1], ed[2]);
			add(ed[1], ed[0], ed[2]);
		}
	}

	for (int i = 0; i < n; ++i) {
		if(h[i]<0)dfs(i, -1, 0);
	}

	scanf("%d", &m);

	while (m--) {
		scanf("%d%d", &a, &b);
		a--, b--;
		if (us.FindV2(a) != us.FindV2(b))puts("-1");
		else printf("%d\n", optDis(a, b));
	}
}

int main()
{
	solve();
	return 0;
}



/*
12 11
8 1 4
8 9 3
8 12 6
1 5 5
1 7 1
7 6 2
9 4 2
9 11 10
9 2 9
4 3 2
12 10 7

11
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12


12 11
8 1 1
8 9 1
8 12 1
1 5 1
1 7 1
7 6 1
9 4 1
9 11 1
9 2 1
4 3 1
12 10 1

11
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12

*/

练习三

https://loj.ac/p/10130
算法思路:
利用倍增算法建立祖先关系,以及到祖先链路上的距离。
查询A,B距离=A到公共祖先距离+B到公共祖先距离)。
具体实现与上一题类似。



#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<cmath>
#include<algorithm>

using namespace std;

const int M = 500000 + 10;
const int N = 500000 + 10;
const int bitL = 22;
int head[N];
int to[M * 2], nextEdge[M * 2], weight[M * 2];
int len;
int h[N];
int father[bitL][N];
int dis[bitL][N];

void initPara(int n)
{
	len = 0;
	for (int i = 0; i < n; i++)
	{
		head[i] = -1;
	}
}

void add(int a, int b, int w)
{
	to[len] = b;
	weight[len] = w;
	nextEdge[len] = head[a];

	head[a] = len++;
}

void dfs(int x, int fa, int w)
{
	if (fa == -1) h[x] = 0;
	else {
		h[x] = h[fa] + 1;
		father[0][x] = fa;
		dis[0][x] = w;
		for (int t = 1; t < bitL && (1 << t) <= h[x]; t++) {
			father[t][x] = father[t - 1][father[t - 1][x]];
			dis[t][x] = dis[t - 1][x] + dis[t - 1][father[t - 1][x]];
		}
	}
	int i;
	for (i = head[x]; i != -1; i = nextEdge[i])
	{
		int j = to[i];
		if (fa == j)continue;
		dfs(j, x, weight[i]);
	}
}

int lca(int a, int b) {
	if (h[a] < h[b]) {
		return lca(b, a);
	}

	int gap = h[a] - h[b];
	for (int t = bitL - 1; t >= 0; t--) {
		if (gap & (1 << t))a = father[t][a];
	}
	if (a == b)return a;
	gap = h[a];
	for (int t = bitL - 1; t >= 0; t--) {
		if (gap <= (1 << t))continue;
		if (father[t][a] == father[t][b])continue;
		a = father[t][a];
		b = father[t][b];
		gap -= 1 << t;
	}

	return father[0][a];
}


int optDis(int a, int b) {
	if (h[a] < h[b]) {
		return optDis(b, a);
	}
	int d = 0;
	int gap = h[a] - h[b];
	for (int t = bitL - 1; t >= 0; t--) {
		if (gap & (1 << t)) {
			d += dis[t][a];
			a = father[t][a];
		}
	}
	if (a == b)return d;
	gap = h[a];
	for (int t = bitL - 1; t >= 0; t--) {
		if (gap <= (1 << t))continue;
		if (father[t][a] == father[t][b])continue;
		d += dis[t][a];
		d += dis[t][b];
		a = father[t][a];
		b = father[t][b];
		gap -= 1 << t;
	}
	d += dis[0][a] + dis[0][b];
	return d;
}

void solve()
{
	int n, m;
	int a, b;
	scanf("%d", &n);
	initPara(n);
	for (int i = 0; i < n - 1; ++i) {
		scanf("%d%d", &a, &b);
		a--, b--;
		add(a, b, 1);
		add(b, a, 1);
	}

	dfs(0, -1, 0);

	scanf("%d", &m);

	while (m--) {
		scanf("%d%d", &a, &b);
		a--, b--;
		printf("%d\n", optDis(a, b));
	}
}

int main()
{
	solve();
	return 0;
}



/*
6
1 2
1 3
2 4
2 5
3 6
2
2 6
5 6


12
8 1
8 9
8 12
1 5
1 7
7 6
9 4
9 11
9 2
4 3
12 10
11
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12

*/

练习四

https://acm.hdu.edu.cn/showproblem.php?pid=2586
与练习三类似



#include<stdio.h>
#include<malloc.h>
#include<string.h>
#include<cmath>
#include<algorithm>

using namespace std;

const int M = 500000 + 10;
const int N = 500000 + 10;
const int bitL = 22;
int head[N];
int to[M * 2], nextEdge[M * 2],weight[M*2];
int len;
int h[N];
int father[bitL][N];
int dis[bitL][N];

void initPara(int n)
{
	len = 0;
	for (int i = 0; i < n; i++)
	{
		head[i] = -1;
	}
}

void add(int a, int b, int w)
{
	to[len] = b;
	weight[len] = w;
	nextEdge[len] = head[a];

	head[a] = len++;
}

void dfs(int x, int fa, int w)
{
	if (fa == -1) h[x] = 0;
	else {
		h[x] = h[fa] + 1;
		father[0][x] = fa;
		dis[0][x] = w;
		for (int t = 1; t < bitL && (1<<t)<=h[x]; t++) {
			father[t][x] = father[t-1][father[t - 1][x]];
			dis[t][x] = dis[t-1][x]+ dis[t - 1][father[t - 1][x]];
		}
	}
	int i;
	for (i = head[x]; i != -1; i = nextEdge[i])
	{
		int j = to[i];
		if (fa==j)continue;
		dfs(j, x, weight[i]);
	}
}

int lca(int a, int b) {
	if (h[a] < h[b]) {
		return lca(b, a);
	}

	int gap = h[a] - h[b];
	for (int t = bitL-1; t>=0; t--) {
		if (gap & (1 << t))a = father[t][a];
	}
	if (a == b)return a;
	gap = h[a];
	for (int t = bitL-1; t >= 0; t--) {
		if (gap <=(1 << t))continue;
		if (father[t][a] == father[t][b])continue;
		a = father[t][a];
		b = father[t][b];
		gap -= 1 << t;
	}
	
	return father[0][a];
}


int optDis(int a, int b) {
	if (h[a] < h[b]) {
		return optDis(b, a);
	}
	int d = 0;
	int gap = h[a] - h[b];
	for (int t = bitL - 1; t >= 0; t--) {
		if (gap & (1 << t)) {
			d += dis[t][a];
			a = father[t][a];
		}
	}
	if (a == b)return d;
	gap = h[a];
	for (int t = bitL - 1; t >= 0; t--) {
		if (gap <= (1 << t))continue;
		if (father[t][a] == father[t][b])continue;
		d += dis[t][a];
		d += dis[t][b];
		a = father[t][a];
		b = father[t][b];
		gap -= 1 << t;
	}
	d += dis[0][a] + dis[0][b];
	return d;
}

void solve()
{
	int t;
	int n, m;
	int a, b, w;
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d", &n, &m);
		initPara(n);
		for (int i = 0; i < n - 1; ++i) {
			scanf("%d%d%d", &a, &b, &w);
			a--, b--;
			add(a, b,w);
			add(b, a,w);
		}

		dfs(0, -1, 0);

		/*for (int i = 0; i < n; ++i) {
			printf("%d: %d\n", i, h[i]);
		}*/

		while (m--) {
			scanf("%d%d", &a, &b);
			a--, b--;
			printf("%d\n", optDis(a,b));
		}
	}
}

void test() {
	int t;
	int n = 5000, m = 500000;

	//scanf("%d%d%d", &n, &m, &s);
	initPara(n);
	int a, b;
	for (int i = 0; i < n - 1; ++i) {
		a = i, b = i + 1;
		add(a, b,1);
		add(b, a,1);
	}

	dfs(0, -1,0);
	//printf("%d\n", 1 + lca(10, 5000-1));
	while (m--) {
		a = (m+102)%n, b =( 3823+m*2)%n;
		//printf("%d\n", m);
		if(lca(a, b)!=min(a,b))
		printf("%d %d %d\n", 1 + lca(a, b), a+1, b+1);
	}
}

int main()
{
	solve();
	//test();
	return 0;
}



/*
2
3 2
1 2 10
3 1 15
1 2
2 3

2 2
1 2 100
1 2
2 1

1
12 11
8 1 4
8 9 3
8 12 6
1 5 5
1 7 1
7 6 2
9 4 2
9 11 10
9 2 9
4 3 2
12 10 7

1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12

1
12 11
8 1 1
8 9 1
8 12 1
1 5 1
1 7 1
7 6 1
9 4 1
9 11 1
9 2 1
4 3 1
12 10 1

1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
*/

本人码农,希望通过自己的分享,让大家更容易学懂计算机知识。创作不易,帮忙点击公众号的链接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1071049.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32MP157汇编流水灯

.text .global _start _start: /* 使能GPIOE、GPIOF寄存器 RCC_MP_AHB4ENSETR * 基地址: 0x50000000 偏移地址: 0xA28 0x50000A28* RCC_MP_AHB4ENSETR[4]->1 RCC_MP_AHB4ENSETR[5]->1*/ LDR R0,0x50000A28LDR R1,[R0]ORR R1,R1,#(0x1<<4)STR R1,[R0]LDR R0,0x…

前端day23--JS进阶(作用域,垃圾回收机制,闭包,剩余参数,箭头函数,解构)

目录 作用域 局部作用域 函数作用域 块作用域 全局作用域 作用域链 JS垃圾回收机制 垃圾回收机制算法说明&#xff1a; 引用计数法(了解)&#xff1a; 标记清除法&#xff1a; 闭包 为什么要有闭包&#xff1f; 闭包的风险→内存泄漏 变量提升 函数进阶 函数提升…

前端uniapp如何修改下拉框uni-data-select下面的uni-icons插件自带的图片【修改uniapp自带源码图片/图标】

目录 未改前图片未改前源码未改前通过top和bottom 和修改后图片转在线base64大功告成最后 未改前图片 未改前源码 然后注释掉插件带的代码&#xff0c;下面要的 未改前通过top和bottom 和修改后 找到uni-icons源码插件里面样式 图片转在线base64 地址 https://the-x.cn/b…

防火墙是什么?F5保护Web应用的思路解读

Web 应用防火墙 (WAF) 是保护 Web 应用的必要措施。如今&#xff0c;WAF 需要在部署环境不断扩展但人员技能有限的情况下&#xff0c;保护数量日益增长的应用。那么防火墙是什么&#xff1f;作为一家提供多云应用安全和应用交付的公司&#xff0c;F5为保护Web应用又打造出哪些产…

javaWeb宠物领养系统

一、引言 1.1 系统背景 计算机网络的发展&#xff0c;促进了社会各行业的进步&#xff0c;带来了经济快速增长。管理员通过流浪宠物的信息&#xff0c;在平台上和领养人进行实时的交流&#xff0c;达成领养协议。用户登录后&#xff0c;把想要领养的宠物向本平台发起申请&…

软件安全测试的含义是什么?

早在信息行业发展的初期&#xff0c;就有互联网公司意识到了保护软件产品安全的重要性&#xff0c;可时至今日&#xff0c;我们总能够从报道中瞥见某某公司遭黑客入侵导致信息泄露的新闻&#xff0c;其中甚至不乏Facebook这些以用户通讯、身份信息为支柱产业的大厂。 信息安全事…

【全网最详细的OSPF原理总结,看这篇就够了!】

OSPF是一种基于链路状态的路由协议&#xff0c;也是专为 IP 开发的路由协议&#xff0c;直接运行在 IP 层上面。它从设计上保证了无路由环路。除此之外&#xff0c;IS-IS也是很常见的链路状态协议。 为什么会出现OSPF&#xff1f; 作为目前主流的IGP协议&#xff0c;OSPF主要…

vs code拉取代码到本地汉字乱码--解决

首先&#xff0c;默认情况下&#xff0c;我们使用VS Code打开一个utf-8编码的文件和一个gb2312编码的文件&#xff0c;期中gb2312文件乱码了。 VSCode通常默认UTF-8编码。 解决方法&#xff1a; 点击右下角的编码按钮&#xff08;图中为UTF-8&#xff09;&#xff0c;然后选…

46 二叉树展开为链表

二叉树展开为链表 理解题意&#xff1a;前序遍历的N种写法题解1 前序遍历题解2 反前序遍历(代码简洁)题解3 类似旋转的方法题解4 迭代题解5 同时遍历改左右子树 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNo…

判断当日是否为当月第一个交易日——时间相关函数3

本文介绍的函数用于判断当前交易日是否为当月的第一个交易日。 在某些策略中&#xff0c;可能会在每月的第一个交易日进行调仓换股。这时&#xff0c;就可以使用本文介绍的函数判断当日是否为当月的第一个交易日。 源码 def is_first_trading_day_of_month():""&q…

老虎证券当前股价已严重背离基本面,下半年收入将下滑

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 老虎证券近期股价表现优异 在过去的一个月里&#xff0c;老虎证券(TIGR)的股价表现令人惊叹&#xff0c;其估值也大幅上升。 在过去一个月里&#xff0c;老虎证券的股价上涨了45.0%&#xff0c;而同期以标普500指数为代表的…

VMWare Vcenter Server克隆虚拟机所用端口

Vcenter server 管理ESXi主机时需要用到的端口主要有443和902端口&#xff0c;很多文档都要求双向通信&#xff0c;实际上可以通过查看ESXI主机的防火墙配置了解相关端口。 1. ESXi 对外提供的端口 主要是有 vsphere Web client 服务的入站端口&#xff1a; TCP 902 和 TCP 4…

Javascript之Object、Array

Object.keys 对象的键转化为数组 Object.values 对象的属性值转化为数组 Object.assign 对象的合并 Array.from() 伪数组对象的属性值转化为数组。类似Object.values Array. reduce(function(prev, currentValue, currentIndex, arr), initialValue) 数组多个元素的值合并减为单…

平板第三方电容笔怎么样?便宜的ipad触控笔推荐

苹果原装的电容笔与国产的平替电容笔最大的区别在于&#xff0c;平替电容笔只有一个斜面压力感应&#xff0c;而苹果电容笔既有斜面压力感应&#xff0c;又有重力压力感应。但是&#xff0c;如果你不经常使用它来进行绘画的话&#xff0c;你也不必买选择这款苹果电容笔&#xf…

Acwing.800 数组元素的目标和

题目 给定两个升序排序的有序数组A和B&#xff0c;以及一个目标值x。数组下标从0开始。请你求出满足A[i]Bi]x的数对(i, j)。 数据保证有唯一解。 输入格式 第一行包含三个整数n&#xff0c;m&#xff0c;x&#xff0c;分别表示A的长度&#xff0c;B的长度以及目标值x。第二行…

awk 命令

语法格式&#xff1a; awk [选项参数] ‘/pattern1/{action1} /pattern2/{action2}...’ filename pattern&#xff1a;表示 awk 在数据中查找的内容&#xff0c;就是匹配模式 action&#xff1a;在找到匹配内容时所执行的一系列命令awk常见参数选项&#xff1a; awk常见内置变…

❋JQuery的快速入门2 jq鼠标滚轮

onmousewheelscript当鼠标滚轮正在被滚动时运行的脚本。 主要是利用top与left进行上下移动和左右移动 【使用获取的角度正值还是负值&#xff0c;判断是向上还是上下滚动】 $(element).on("mousewheel", function(event){var de event.originalEvent.deltaY; //需要…

机器学习之旅-从Python 开始

你想知道如何开始机器学习吗&#xff1f;在这篇文章中&#xff0c;我将简要概括一下使用 Python 来开始机器学习的一些步骤。Python 是一门流行的开源程序设计语言&#xff0c;也是在人工智能及其它相关科学领域中最常用的语言之一。机器学习简称 ML&#xff0c;是人工智能的一…

Swift SwiftUI CoreData 过滤数据 2

预览 Code import SwiftUI import CoreDatastruct HomeSearchView: View {Environment(\.dismiss) var dismissState private var search_value ""FetchRequest(entity: Bill.entity(),sortDescriptors: [NSSortDescriptor(keyPath: \Bill.c_at, ascending: false)…

redis(4)-hiredis-API函数的调用

1.下载安装编译 windowslinuxredis下载 redis-plus-plus-master.zip文件的下载 http://download.redis.io/releases/redis-7.2.0.tar.gz tar -zxvf redis-7.2.0.tar.gz //-z:gzip属性 ;-x&#xff1a;解压&#xff1b;-v:显示&#xff1b;-f:文件 make make install //m…