并查集详解(原理+代码实现+应用)
文章目录
- 1. 并查集概念
- 2. 并查集原理
- 2.1 合并
- 2.1 找根
- 3. 并查集实现
- 3.1 结构定义
- 3.2 FindRoot(找根)
- 3.3 Union(合并)
- 3.4 IsInSet(判断两个值是否在一个集合里)
- 3.5 SetCount(并查集中集合个数)
- 3.6 测试
- 4. 并查集可以解决的问题
- 5. 并查集应用
- 5.1 省份数量
- 思路1
- AC代码
- 思路2
- AC代码
- 5.2 等式方程的可满足性
- 思路分析
- AC代码
- 6. 路径压缩
- 7. 源码
- 7.1 UnionFindSet.h
- 7.2 test.cpp
这篇文章我们来学习一个数据结构叫做并查集!
1. 并查集概念
首先我们来了解一下并查集的概念:
并查集是一种树型的数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题。常常在使用中以森林来表示。
在一些应用问题中,需要将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。
适合于描述这类问题的抽象数据结构称为并查集(union-find set)。
2. 并查集原理
那下面我们通过一个小故事给大家讲解一下并查集的原理
假设某公司今年校招全国总共招生10人,西安招4人,成都招3人,武汉招3人,10个人来自不同的学校,起先互不相识,每个学生都是一个独立的小团体,现给这些学生进行编号:{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
毕业后,学生们要去公司上班,每个地方的学生自发组织成小分队一起上路,于是:西安学生小分队s1={0,6,7,8},成都学生小分队s2={1,4,9},武汉学生小分队s3={2,3,5}就相互认识了,10个人形成了三个小团体。
这里呢它们就按照编号分成了三个集体。
那我们如何表示不同的集合呢?
那上面我们了解过了概念,并查集呢通常用森林来表示,一棵树就是一个集合。
上面是按编号分的,那如果我们拿到的是同学的名字,我如何知道它对应的编号是几呢?
那我就可以把名字和编号建立一个映射关系。
那我们来写写代码:
假设我们拿到的是一个名字的数组,个数为n
那我们如何存储这些数据并跟编号建立映射呢?
🆗,那其实我们用两个结构就可以搞定这个问题(后面我们图里面有些地方也会用到这种写法)
我们借助vector和map就可以搞定
我们可以用vector存名字数组里面的数据,那下标就可以做它们的编号,那这样用编号找名字是很方便的,编号是几,就找下标为几的元素就行了。
但是名字找编号就有点麻烦,所以我们可以借助map给名字和编号建立一个映射关系。
那我们来完善一下构造函数:
也很简单
搞一组数据数据试一下:
可以
🆗,这里只是讲这样一个方法,就是不管它给我们编号还是名字我们都可以搞。
那我们再回到上面的问题:它们分成了三个集合,那我们就可以一棵树表示一个集合,3棵树的话就构成了一个森林
那我们如何用一棵树表示一个集合呢?
西安学生小分队s1={0,6,7,8},成都学生小分队s2={1,4,9},武汉学生小分队s3={2,3,5}就相互认识了,10个人形成了三个小团体。
很简单,选一个做根,其它的做它的孩子就可以了。
假设选最小的做根(组长),负责大家的出行
那我们这里需要真的创建树吗?
🆗,其实不需要。
他这里用的是双亲表示法,用一个数组就可以搞定。
就跟我们之前学的堆有点类似,堆的逻辑结构是一棵完全二叉树,但底层的物理结构是一个数组。
那这里10个人,所以起始状态就可以这样表示
每个位置存一个-1(当然不一定非得是-1,但存-1比较好,后面会解释),现在就表示有10棵树,10个集合(还没有合并嘛)。
2.1 合并
那如何进行合并呢?
一趟火车之旅后,每个小分队成员就互相熟悉,称为了一个朋友圈,现在它们10个人分成了这样三个集体:
西安学生小分队s1={0,6,7,8},成都学生小分队s2={1,4,9},武汉学生小分队s3={2,3,5}
那我们如何在数组里把10个独立的个体合并成这样3棵树呢?
双亲表示法呢是这样搞的
解释一下
以第一棵树(0为根,6,7,8为孩子)为例,怎么做呢?
6,7,8是0的三个孩子,依次把6,7,8位置的值加到0位置上,所以0位置的值就变成了-4(起初都是-1嘛),然后6,7,8位置的值都变成0,即存它们双亲结点(或者说父结点)的下标。
另外两棵树也是同样的道理。
那这样表示呢有这样3个特点:
1. 数组的下标对应集合中元素的编号
2. 对于每个位置来说,如果它存的值是负数,那它就是根,如果不是负数,那它存的就是它的父/双亲结点的下标。
3. 根结点的位置(即值为负数的位置),该位置存的值得绝对值就是对应这棵树上结点的个数(当然前提是起始时每个位置存的都是-1,所以为什么我们上面选择了-1作为初始值)。
大家可以对照着看一下
故事继续:
在公司工作一段时间后,西安小分队中8号同学与成都小分队4号同学奇迹般的走到了一起,两个小圈子的学生相互介绍,最后融合成了一个朋友圈
那上面这种情况对应到数组中我们该怎么做呢?
可以直接像上面那样搞嘛
比如把8位置的值加到4位置上,然后8位置存4
我们一看这样肯定是不行的!
这样等于把8从原先的圈子脱离,然后加到4这棵树里面。
但是我们是要把这两个小集合合并啊,而且这样这两棵树根结点记录的个数也不对了
那正确的我们应该这样搞:
要找着两棵树的根,把它们的两个根合并了,这两棵树不就合并了嘛!
当然你也可以把0这棵树合并到1上边,让1做根
2.1 找根
那我们怎么找根呢?
那很简单,看这个位置存的值是不是负数,是负数的话就是根了;不是负数的话,存的就是根的下标,那就顺着父结点往上找,直到值为负数就是最上面的根了
那这里:
4找到根是1,8找到根是0
然后让这两个根合并就行了,两个根你合并到我,我合并到你都可以
那比如我们这里让1合并到0(保持根上面一样小的做根),怎么做呢?
那就还是一样的逻辑:
把1位置的值加到0位置上,然后1位置存0(即它的父亲的下标)
那此时0位置的值为-7,也表示0这棵树一共7个结点
现在0集合有7个人,2集合有3个人,总共两个朋友圈。
3. 并查集实现
那上面我们讲了一下并查集的原理,下面我们就来实现一个并查集,实现完再给大家做总结。
3.1 结构定义
那我们这里就不搞的像上面那样复杂了,因为我们上面的例子直接按编号去搞就行了。
那我们底层用一个vector就行了
起始全部初始化为-1
然后呢并查集主要提供以下几个接口
3.2 FindRoot(找根)
首先先来实现找根的接口,因为后面合并要用到这个接口。
怎么找呢?上面已经分析过了
如果当前位置的值是负数,那就是根了;如果不是负数,顺着父结点往上找就可以了(不是负数的话存的就是父结点的下标),遇到负数就是根了
比如:
找9的根,9位置的值不是负数,找它父亲下标为1的位置,该位置也不是负数,再找它的父亲是0,0位置是负数,所以0就是根
那我们写一下代码:
很简单
3.3 Union(合并)
那这里的合并呢就是给两棵树(集合)的根,把这两个集合合并为一个集合:
那这个接口怎么实现呢?
那我们上面其实已经分析过了:
不能直接合并,要找根。
如果是两个单个元素的集合合并可以直接合(因为可以认为它们自己就是根),但是如果是两个多个元素的集合就不能直接合并,而是要找到两个根,把两个根进行合并
但是找到根之后我们要判断一下这两个根一样不一样,一样的话就没必要合并了(证明它们俩本来就在一个集合里或者是同一个值)
然后不同的话就进行合并(如何合并我们前面讲过了)
写一下代码:
3.4 IsInSet(判断两个值是否在一个集合里)
那这个很简单,判断这两个值所在集合的根一不一样就行了,一样就在一个集合,不一样就不在:
3.5 SetCount(并查集中集合个数)
还有一个接口就是计算并查集中集合的个数:
非常简单,统计一下vector里面一共有多少个负数就有几个集合,因为一个负数对应的下标就是一棵树的根
写一下:
3.6 测试
简单测试一下:
没问题。
4. 并查集可以解决的问题
通过以上学习可知,并查集一般可以解决一下问题:
1. 查找元素属于哪个集合(找根)
沿着数组表示的树形关系往上一直找到根(即:树中中元素为负数的位置)
2. 查看两个元素是否属于同一个集合
沿着数组表示的树形关系往上一直找到树的根,如果根相同表明在同一个集合,否则不在
3. 将两个集合归并成一个集合
4. 集合的个数
遍历数组,数组中元素为负数的个数即为集合的个数
5. 并查集应用
那下面我们来做两个题
5.1 省份数量
题目链接: link
大家自己先看一下题
思路1
我们来分析一下题目:
题目给我们一共N*N的二维数组isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连
另外如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
让我们返回矩阵中 省份 的数量
这里对于省份的定义是:省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市
那这道题其实用并查集来解决就很简单:
其实就是找集合的个数嘛。
把我们实现的并查集拷过来,定义一个并查集,然后把相连的城市合并到一个集合里面,最终统计集合的个数就行了。
很简单!
AC代码
class UnionFindSet
{
public:UnionFindSet(size_t n):_ufs(n, -1){}int FindRoot(int x){int root = x;while (_ufs[root] >= 0){root = _ufs[root];}return root;}void Union(int s1, int s2){int root1 = FindRoot(s1);int root2 = FindRoot(s2);//如果两个根相同就没必要合并了if (root1 == root2)return;//不相等的话进行合并(我们这里还是以小的做根)if (root1 > root2){swap(root1, root2);}_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}bool IsInSet(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}size_t SetCount(){size_t count = 0;for (size_t i = 0; i < _ufs.size(); i++){if (_ufs[i] < 0)count++;}return count;}
private:vector<int> _ufs;
};class Solution {
public:int findCircleNum(vector<vector<int>>& isConnected) {UnionFindSet ufs(isConnected.size());for(int i=0;i<isConnected.size();i++){for(int j=0;j<isConnected[i].size();j++){if(isConnected[i][j]==1){ufs.Union(i,j);}}}return ufs.SetCount();}
};
思路2
然后呢想说的是:
我们上面的方法呢,很简单,但是前提是我们已经写好了一个并查集。
那以后遇到这种题都需要我们手撕一个并查集吗?
其实不需要完整的手撕一个,直接用并查集的思想解题就行了。
AC代码
我们来写一下:
class Solution {
public:int findCircleNum(vector<vector<int>>& isConnected) {vector<int> ufs(isConnected.size(),-1);auto FindRoot=[&ufs](int x){while(ufs[x]>=0){x=ufs[x];}return x;};for(int i=0;i<isConnected.size();i++){for(int j=0;j<isConnected[i].size();j++){if(isConnected[i][j]==1){int root1=FindRoot(i);int root2=FindRoot(j);if(root1!=root2){ufs[root1]+=ufs[root2];ufs[root2]=root1;}}}}int count=0;for(auto e:ufs){if(e<0)count++;}return count;}
};
5.2 等式方程的可满足性
题目链接: link
大家看一下题目
思路分析
这道题分析一下其实就是看他给我们的所有条件能不能全部同时成立。
用并查集去搞其实就很简单,我们来分析一下:
那这里呢我们还是用一个并查集,当然不一定非得写一个完整的并查集,就可以像上一题第二种方法那样,用到什么接口自己简单实现一下就行了。
然后呢我们可以这样搞:
因为题目给的变量之间的关系只有==
和!=
嘛。
首先,遍历一遍字符串方程的数组,把相等关系的变量放到一个集合里面;
然后第二遍遍历,判断不相等关系的变量是否在一个集合中,如果有在的,那他们就不能同时成立(返回false),如果没有就可以(返回true)
判断相不相等只需要看equations[i][1]就可以了
AC代码
我们来写一下代码:
class Solution {
public:bool equationsPossible(vector<string>& equations) {vector<int> ufs(26,-1);auto FindRoot=[&ufs](int x){while(ufs[x]>=0){x=ufs[x];}return x;};//第一次遍历把相等关系的变量放到一个集合里面for(auto str:equations){if(str[1]=='='){int root1=FindRoot(str[0]-'a');int root2=FindRoot(str[3]-'a');if(root1!=root2){ufs[root1]+=ufs[root2];ufs[root2]=root1;}}}//第二次遍历判断不相等关系的变量是否在一个集合中,//如果有在的,那他们就不能同时成立for(auto str:equations){if(str[1]=='!'){int root1=FindRoot(str[0]-'a');int root2=FindRoot(str[3]-'a');if(root1==root2){return false;}}}return true;}
};
6. 路径压缩
然后呢关于压缩路径的问题这里也简单提一下:
这个东西呢其实就是对并查集的一个优化。
其实我们平时写都不太需要考虑这个东西,除非数据量特别大的时候,可能有些路径会比较长,导致效率变慢,这时候可以考虑进行一下压缩。
那压缩呢其实就是在FindRoot这里面进行一些操作,举个例子简单给大家说一说:
比如现在是这样一个情况
那压缩的话就是查找谁就去压谁,当然不是所有的路径都需要压缩。
比如Find3的话,那里面判断一下,就一层,不需要压缩。
再比如,查找6
那最后发现它返回的root是2,但是6直接的上一层的父亲并不是2,
那说明它们之间有间隔层,那就可以对这条路径压缩一下。
可以直接把6变成2的孩子,那后续再查找6的话就快了。
然后也可以直接把6的上一层父亲,0直接变成2的孩子
所以我们这样是边找边压缩,比如后面再找9的话,就可以再把9变成2的孩子,然后顺着这条路径再把1变成2的孩子(如果更长的情况就一直往上就行了)
就是在FindRoot里面再加一个压缩路径的代码,其实就是先找到根结点,然后把这条查找路径上所有的结点都直接链接到根结点上。
当然数据量小的时候就完全没有必要做这个事情。
代码给大家写一下:
7. 源码
7.1 UnionFindSet.h
#pragma once//#include <map>
//
//template<class T>
//class UnionFindSet
//{
//public:
// UnionFindSet(const T* a, size_t n)
// {
// for (size_t i = 0; i < n; i++)
// {
// _a.push_back(a[i]);
// _indexMap[a[i]] = i;
// }
// }
//private:
// vector<T> _a;
// map<T, int> _indexMap;
//};class UnionFindSet
{
public:UnionFindSet(size_t n):_ufs(n, -1){}int FindRoot(int x){int root = x;while (_ufs[root] >= 0){root = _ufs[root];}return root;}void Union(int s1, int s2){int root1 = FindRoot(s1);int root2 = FindRoot(s2);//如果两个根相同就没必要合并了if (root1 == root2)return;//不相等的话进行合并(我们这里还是以小的做根)if (root1 > root2){swap(root1, root2);}_ufs[root1] += _ufs[root2];_ufs[root2] = root1;}bool IsInSet(int x1, int x2){return FindRoot(x1) == FindRoot(x2);}size_t SetCount(){size_t count = 0;for (size_t i = 0; i < _ufs.size(); i++){if (_ufs[i] < 0)count++;}return count;}
private:vector<int> _ufs;
};
7.2 test.cpp
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>//#include "UnionFindSet.h"
//int main()
//{
// string a[] = { "张三","李四","王五","赵六","钱七","杨八" };
// UnionFindSet<string> ufs(a, 6);
// return 0;
//}#include "UnionFindSet.h"
int main()
{UnionFindSet u(10);u.Union(0, 6);u.Union(7, 6);u.Union(7, 8);u.Union(1, 4);u.Union(4, 9);u.Union(2, 3);u.Union(2, 5);cout << u.SetCount() << endl;cout << u.FindRoot(8) << endl;cout << u.IsInSet(6, 5) << endl;return 0;
}
相关文章:
并查集详解(原理+代码实现+应用)
文章目录 1. 并查集概念2. 并查集原理2.1 合并2.1 找根 3. 并查集实现3.1 结构定义3.2 FindRoot(找根)3.3 Union(合并)3.4 IsInSet(判断两个值是否在一个集合里)3.5 SetCount(并查集中集合个数&…...
第k小的数
补充习题: 第k小的数 问题描述 有两个正整数数列,元素个数分别为 N N N和 M M M.从两个数列中分别任取一个数相乘,这样一共可以得到 N M N\times M NM个数,询问这 N M N\times M NM个数中第 K K K小的数是多少. 数据范围: N , M < 200000 , K < 2.1 ∗ 1 0 10 , …...
基于electron25+vite4创建多窗口|vue3+electron25新开模态窗体
在写这篇文章的时候,查看了下electron最新稳定版本由几天前24.4.0升级到了25了,不得不说electron团队迭代速度之快! 前几天有分享一篇electron24整合vite4全家桶技术构建桌面端vue3应用示例程序。 https://www.cnblogs.com/xiaoyan2017/p/17…...
红米手机 导出 通讯录 到电脑保存
不要搞什么 云服务 不要安装什么 手机助手 不要安装 什么app 用 usb 线 连接 手机 和 电脑 手机上会跳出 提示 选择 仅传输文件 会出现下面的 一个 盘 进入 MIUI目录 然后进入 此电脑\Redmi Note 5\内部存储设备\MIUI\backup\AllBackup\20230927_043337 如何没有上面的文件&a…...
常见web信息泄露
一、源码(备份文件)泄露 1、git泄露 Git是一个开源的分布式版本控制系统,在执行git init初始化目录的时候,会在当前目录下自动创建一个.git目录,用来记录代码的变更记录等。发布代码的时候,如果没有把.git这个目录删除ÿ…...
找不到VCRUNTIME140_1.dll怎么办,VCRUNTIME140_1.dll丢失的5个解决方法
在当今的数字时代,我们的生活和工作都离不开电脑。然而,随着科技的发展,我们也会遇到各种各样的问题。其中,VCRUNTIME140_1.dll丢失的问题是许多人都会遇到的困扰。这个问题可能会导致许多应用程序无法正常运行,给我们…...
C#生成自定义海报
安装包 SixLabors.ImageSharp.Drawing 2.0 需要的字体:宋体和微软雅黑 商用的需要授权如果商业使用可以使用方正书宋、方正黑体,他们可以免费商用 方正官网 代码 using SixLabors.Fonts; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Draw…...
BP神经网络的MATLAB实现(含源代码)
BP(back propagation)神经网络是1986年由Rumelhart和McClelland为首的科学家提出的概念,是一种按照误差逆向传播算法训练的多层前馈神经网络,是应用最广泛的神经网络模型之一 具体数学推导以及原理在本文不做详细介绍,本文将使用MATLAB进行B…...
AES和Rijndael的区别
快速链接: . 👉👉👉 个人博客笔记导读目录(全部) 👈👈👈 付费专栏-付费课程 【购买须知】:密码学实践强化训练–【目录】 👈👈👈“Rijndael” 这个词的中文谐音可以近似地发音为 “瑞恩达尔”。请注意,这只是一种近似的发音方式,因为该词是荷兰姓氏 “Ri…...
【数据结构】—堆详解(手把手带你用C语言实现)
食用指南:本文在有C基础的情况下食用更佳 🔥这就不得不推荐此专栏了:C语言 ♈️今日夜电波:水星—今泉愛夏 1:10 ━━━━━━️💟──────── 4:23 …...
关于算法复杂度的几张表
算法在改进今天的计算机与古代的计算机的区别 去除冗余 数据点 算法复杂度 傅里叶变换...
蓝桥杯每日一题2023.10.1
路径 - 蓝桥云课 (lanqiao.cn) 题目分析 求最短路问题,有多种解法,下面介绍两种蓝桥杯最常用到的两种解法 方法一 Floyd(求任意两点之间的最短路)注:不能有负权回路 初始化每个点到每个点的距离都为0x3f这样才能对…...
第三章:最新版零基础学习 PYTHON 教程(第十节 - Python 运算符—Python 中的运算符重载)
运算符重载意味着赋予超出其预定义操作含义的扩展含义。例如,运算符 + 用于添加两个整数以及连接两个字符串和合并两个列表。这是可以实现的,因为“+”运算符被 int 类和 str 类重载。您可能已经注意到,相同的内置运算符或函数对于不同类的对象显示不同的行为,这称为运算符…...
Nacos 实现服务平滑上下线(Ribbon 和 LB)
前言 不知道各位在使用 SpringCloud Gateway Nacos的时候有没有遇到过服务刚上线偶尔会出现一段时间的503 Service Unavailable,或者服务下线后,下线服务仍然被调用的问题。而以上问题都是由于Ribbon或者LoadBalancer的默认处理策略有关,其…...
c/c++里 对 共用体 union 的内存分配
对union 的内存分配,是按照最大的那个成员分配的。 谢谢...
博途SCL区间搜索指令(判断某个数属于某个区间)
S型速度曲线行车位置控制,停靠位置搜索功能会用到区间搜索指令,下面我们详细介绍区间搜索指令的相关应用。 S型加减速行车位置控制(支持点动和停车位置搜索)-CSDN博客S型加减速位置控制详细算法和应用场景介绍,请查看下面文章博客。本篇文章不再赘述,这里主要介绍点动动和…...
(三)激光线扫描-中心线提取
光条纹中心提取算法是决定线结构光三维重建精度以及光条纹轮廓定位准确性的重要因素。 1. 光条的高斯分布 激光线条和打手电筒一样,中间最亮,越像周围延申,光强越弱,这个规则符合高斯分布,如下图。 2. 传统光条纹中心提取算法 传统的光条纹中心提取算法有 灰度重心法、…...
递归与分治算法(1)--经典递归、分治问题
目录 一、递归问题 1、斐波那契数列 2、汉诺塔问题 3、全排列问题 4、整数划分问题 二、递归式求解 1、代入法 2、递归树法 3、主定理法 三、 分治问题 1、二分搜索 2、大整数乘法 一、递归问题 1、斐波那契数列 斐波那契数列不用过多介绍,斐波那契提出…...
Java之SpringCloud Alibaba【六】【Alibaba微服务分布式事务组件—Seata】
一、事务简介 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。 在关系数据库中,一个事务由一组SQL语句组成。 事务应该具有4个属性: 原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。 原子性(atomicity) ∶个事务…...
Android逆向学习(五)app进行动态调试
Android逆向学习(五)app进行动态调试 一、写在前面 非常抱歉鸽了那么久,前一段时间一直在忙,现在终于结束了,可以继续更新android逆向系列的,这个系列我会尽力做下去,然后如果可以的话我看看能…...
音频编辑软件Steinberg SpectraLayers Pro mac中文软件介绍
Steinberg SpectraLayers Pro mac是一款专业的音频编辑软件,旨在帮助音频专业人士进行精细的音频编辑和声音处理。它提供了强大的频谱编辑功能,可以对音频文件进行深入的频谱分析和编辑。 Steinberg SpectraLayers Pro mac软件特点 1. 频谱编辑ÿ…...
基于.Net Core实现自定义皮肤WidForm窗口
前言 今天一起来实现基于.Net Core、Windows Form实现自定义窗口皮肤,并实现窗口移动功能。 素材 准备素材:边框、标题栏、关闭按钮图标。 窗体设计 1、创建Window窗体项目 2、窗体设计 拖拉4个Panel控件,分别用于:标题栏、关…...
【Rust】操作日期与时间
目录 介绍 一、计算耗时 二、时间加减法 三、时区转换 四、年月日时分秒 五、时间格式化 介绍 Rust的时间操作主要用到chrono库,接下来我将简单选一些常用的操作进行介绍,如果想了解更多细节,请查看官方文档。 官方文档:chr…...
blender快捷键
1, shift a 添加物体 2,ctrl alt q 切换四格视图 3, ~ 展示物体的各个视图按钮,(~ 就是tab键上面的键) 4,a 全选,全选后,点 ctrl 鼠标框选 减去已经选择的;…...
java Spring Boot 自动启动热部署 (别再改点东西就要重启啦)
上文 java Spring Boot 手动启动热部署 我们实现了一个手动热部署的代码 但其实很多人会觉得 这叫说明热开发呀 这么捞 写完还要手动去点一下 很不友好 其实我们开发人员肯定是希望重启这种事不需要自己手动去做 那么 当然可以 我们就让它自己去做 Build Project 这个操作 我们…...
TouchGFX之后端通信
在大多数应用中,UI需以某种方式连接到系统的其余部分,并发送和接收数据。 它可能会与硬件外设(传感器数据、模数转换和串行通信等)或其他软件模块进行交互通讯。 Model类 所有TouchGFX应用都有Model类,Model类除了存…...
cesium gltf控制
gltf格式详解 glTF格式本质上是一个JSON文件。这一文件描述了整个3D场景的内容。它包含了对场景结构进行描述的场景图。场景中的3D对象通过场景结点引用网格进行定义。材质定义了3D对象的外观,动画定义了3D对象的变换操作(比如选择、平移操作)。蒙皮定义了3D对象如何进行骨骼…...
Spring的依赖注入(DI)以及优缺点
Spring的依赖注入(DI):解释和优点 依赖注入(Dependency Injection,简称DI)是Spring框架的核心概念之一,也是现代Java应用程序开发的重要组成部分。本文将深入探讨DI是什么,以及它的…...
【强化学习】05 —— 基于无模型的强化学习(Prediction)
文章目录 简介蒙特卡洛算法时序差分方法Example1 MC和TD的对比偏差(Bias)/方差(Variance)的权衡Example2 Random WalkExample3 AB 反向传播(backup)Monte-Carlo BackupTemporal-Difference BackupDynamic Programming Backup Boot…...
【计算机组成原理】考研真题攻克与重点知识点剖析 - 第 1 篇:计算机系统概述
前言 本文基础知识部分来自于b站:分享笔记的好人儿的思维导图,感谢大佬的开源精神,习题来自老师划的重点以及考研真题。此前我尝试了完全使用Python或是结合大语言模型对考研真题进行数据清洗与可视化分析,本人技术有限ÿ…...
网页设计页面设计/宁波seo推广外包公司
传送门: 设 dp[i][j]为第一个号i等级,第二个号j等级的期望值 a[i]存每个等级上分的概率 dp[i][j]a[i]*dp[i1][j](1-a[i])*dp[j][i]1 dp[j][i]a[j]*dp[j1][i](1-a[j])*dp[i][j]1 这个鬼东西改变上面值会影响下面值,所以要化简 联立得: dp[i][j…...
wordpress菜单用处/刷推广链接
2.1 自带tomcat如果是安装包直接安装的BI,可以直接在\FineBI目录下的文件中修改内存的大小。Windows以及linux/unix系统均修改FineBI.vmoptions(这里是以M为单位的)。注:Xmx与数字之间不要有空格!2.2 部署在tomcat上修改catalina文件修改的是tomcat的../…...
h5网站建设价格/网络营销心得体会300字
基于Cesium的材质线插件,引入即可使用,需要的自取。 插件地址:传送门 在线访问: 查看地址 使用 // 自定义纹理材质let MaterialLineImage [./src/line.png,./src/line2.png,./src/line3.png,]// colorlet colors [new Cesium.Color(77 …...
英文版wordpress安装/seo超级外链工具
欢迎关注头条号:老顾聊技术精品技术文章分享,知识的组装工目录前言先更新数据库,再更新缓存先更新缓存,再更新数据库先删除缓存,再更新数据库先更新数据库,再删除缓存删除缓存失败,导致不一致读…...
扁平化配色方案网站/在线域名查询网站
给定一个字符串s,将s分割成一些子串,使每个子串都是回文串。 返回s所有可能的回文串分割方案。 样例 给出 s "aab",返回 [ [“aa”, “b”], [“a”, “a”, “b”] ] 分析:采用深度优先搜索即可,这种回文串…...
做博客用什么系统做网站好/搜索引擎营销简称为
海度数据 MySQL同步到Oracle 一、数据表结构同步 将mysql表结构导出 将sql改为oracle表结构 将双引号去掉 不同数据字段类型改变 将表名改为要同步到oracle的名字 二、编写etl同步脚本 选择要同步表所在的工程 复制一个原有的表 右击选择【属性】一个一个的检查&am…...