【树上倍增】【割点】 【换根法】3067. 在带权树网络中统计可连接服务器对数目

作者推荐

视频算法专题

本文涉及知识点

树上倍增 树 图论 并集查找 换根法 深度优先 割点

LeetCode3067. 在带权树网络中统计可连接服务器对数目

给你一棵无根带权树,树中总共有 n 个节点,分别表示 n 个服务器,服务器从 0 到 n - 1 编号。同时给你一个数组 edges ,其中 edges[i] = [ai, bi, weighti] 表示节点 ai 和 bi 之间有一条双向边,边的权值为 weighti 。再给你一个整数 signalSpeed 。
如果两个服务器 a ,b 和 c 满足以下条件,那么我们称服务器 a 和 b 是通过服务器 c 可连接的 :
a < b ,a != c 且 b != c 。
从 c 到 a 的距离是可以被 signalSpeed 整除的。
从 c 到 b 的距离是可以被 signalSpeed 整除的。
从 c 到 b 的路径与从 c 到 a 的路径没有任何公共边。
请你返回一个长度为 n 的整数数组 count ,其中 count[i] 表示通过服务器 i 可连接 的服务器对的 数目 。

示例 1:
在这里插入图片描述

输入:edges = [[0,1,1],[1,2,5],[2,3,13],[3,4,9],[4,5,2]], signalSpeed = 1
输出:[0,4,6,6,4,0]
解释:由于 signalSpeed 等于 1 ,count[c] 等于所有从 c 开始且没有公共边的路径对数目。
在输入图中,count[c] 等于服务器 c 左边服务器数目乘以右边服务器数目。
示例 2:
在这里插入图片描述

输入:edges = [[0,6,3],[6,5,3],[0,3,1],[3,2,7],[3,1,6],[3,4,2]], signalSpeed = 3
输出:[2,0,0,0,0,0,2]
解释:通过服务器 0 ,有 2 个可连接服务器对(4, 5) 和 (4, 6) 。
通过服务器 6 ,有 2 个可连接服务器对 (4, 5) 和 (0, 5) 。
所有服务器对都必须通过服务器 0 或 6 才可连接,所以其他服务器对应的可连接服务器对数目都为 0 。

提示:

2 <= n <= 1000
edges.length == n - 1
edges[i].length == 3
0 <= ai, bi < n
edges[i] = [ai, bi, weighti]
1 <= weighti <= 106
1 <= signalSpeed <= 106
输入保证 edges 构成一棵合法的树。

树上倍增

本题有三个考点:
一,如何计算树上两个节点x1,x2的距离。
假定这两个节点的最早公共祖先是pub。以任意节点root为根,f(x)表示节点x到root的距离。
x1到x2的距离:f(x1)+f(x2)-2*f(pub)。
二,如何找到最早公共祖先:树上倍增。
记录各节点的1级祖先(父节点)、2级祖先、4级祖先…
三,如果判断ac和bc有公共边。
树是连通无向无环图,因为无环,所以两个节点的路径唯一。
假设公共边是x3x4。则x3到c的路径唯一,假定x3到c的倒数第二个端点是x5,则ab和bc的最后一条边都是 x 3 c → \overrightarrow{x3c} x3c 。断开所以和c相连的边,如果a和b在同一个连通区域,则有公共边。用并查集看是否在同一个连通区域。
时间复杂度: O(nnlogn)。 枚举c,时间复杂度O(n);枚举ab,时间复杂度O(n)。查公共路径O(logn)。

并集查找

class CNeiBo
{
public:	static vector<vector<int>> Two(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0) {vector<vector<int>>  vNeiBo(n);for (const auto& v : edges){vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase);if (!bDirect){vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase);}}return vNeiBo;}	static vector<vector<std::pair<int, int>>> Three(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0){vector<vector<std::pair<int, int>>> vNeiBo(n);for (const auto& v : edges){vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase, v[2]);if (!bDirect){vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase, v[2]);}}return vNeiBo;}
};
class CUnionFind
{
public:CUnionFind(int iSize) :m_vNodeToRegion(iSize){for (int i = 0; i < iSize; i++){m_vNodeToRegion[i] = i;}m_iConnetRegionCount = iSize;}	CUnionFind(vector<vector<int>>& vNeiBo):CUnionFind(vNeiBo.size()){for (int i = 0; i < vNeiBo.size(); i++) {for (const auto& n : vNeiBo[i]) {Union(i, n);}}}int GetConnectRegionIndex(int iNode){int& iConnectNO = m_vNodeToRegion[iNode];if (iNode == iConnectNO){return iNode;}return iConnectNO = GetConnectRegionIndex(iConnectNO);}void Union(int iNode1, int iNode2){const int iConnectNO1 = GetConnectRegionIndex(iNode1);const int iConnectNO2 = GetConnectRegionIndex(iNode2);if (iConnectNO1 == iConnectNO2){return;}m_iConnetRegionCount--;if (iConnectNO1 > iConnectNO2){UnionConnect(iConnectNO1, iConnectNO2);}else{UnionConnect(iConnectNO2, iConnectNO1);}}bool IsConnect(int iNode1, int iNode2){return GetConnectRegionIndex(iNode1) == GetConnectRegionIndex(iNode2);}int GetConnetRegionCount()const{return m_iConnetRegionCount;}vector<int> GetNodeCountOfRegion()//各联通区域的节点数量{const int iNodeSize = m_vNodeToRegion.size();vector<int> vRet(iNodeSize);for (int i = 0; i < iNodeSize; i++){vRet[GetConnectRegionIndex(i)]++;}return vRet;}std::unordered_map<int, vector<int>> GetNodeOfRegion(){std::unordered_map<int, vector<int>> ret;const int iNodeSize = m_vNodeToRegion.size();for (int i = 0; i < iNodeSize; i++){ret[GetConnectRegionIndex(i)].emplace_back(i);}return ret;}
private:void UnionConnect(int iFrom, int iTo){m_vNodeToRegion[iFrom] = iTo;}vector<int> m_vNodeToRegion;//各点所在联通区域的索引,本联通区域任意一点的索引,为了增加可理解性,用最小索引int m_iConnetRegionCount;
};class CParents
{
public:CParents(vector<int>& vParent, const vector<int>& vLeve):m_vLeve(vLeve){const int iMaxLeve = *std::max_element(vLeve.begin(), vLeve.end());int iBitNum = 0;for (; (1 << iBitNum) < iMaxLeve; iBitNum++);const int n = vParent.size();m_vParents.assign(iBitNum+1, vector<int>(n, -1));m_vParents[0] = vParent;//树上倍增for (int i = 1; i < m_vParents.size(); i++){for (int j = 0; j < n; j++){const int iPre = m_vParents[i - 1][j];if (-1 != iPre){m_vParents[i][j] = m_vParents[i - 1][iPre];}}}}int GetParent(int iNode, int iLeve)const{int iParent = iNode;for (int iBit = 0; iBit < m_vParents.size(); iBit++){if (-1 == iParent){return iParent;}if (iLeve & (1 << iBit)){iParent = m_vParents[iBit][iParent];}}return iParent;}int GetPublicParent(int iNode1, int iNode2)const{int leve0 = m_vLeve[iNode1];int leve1 = m_vLeve[iNode2];if (leve0 < leve1){iNode2 = GetParent(iNode2, leve1 - leve0);leve1 = leve0;}else{iNode1 = GetParent(iNode1, leve0 - leve1);leve0 = leve1;}//二分查找int left = -1, r = leve0;while (r - left > 1){const auto mid = left + (r - left) / 2;const int iParent0 = GetParent(iNode1, mid);const int iParent1 = GetParent(iNode2, mid);if (iParent0 == iParent1){r = mid;}else{left = mid;}}return GetParent(iNode1, r);}
protected:vector<vector<int>> m_vParents;const vector<int> m_vLeve;
};class Solution {
public:vector<int> countPairsOfConnectableServers(vector<vector<int>>& edges, int signalSpeed) {m_c = edges.size() + 1;m_vDisToRoot.resize(m_c);m_vParent.resize(m_c);m_vLeve.resize(m_c);auto neiBo = CNeiBo::Three(m_c, edges, false, 0);DFS(neiBo, 0, -1, 0,0);	CParents par(m_vParent,m_vLeve);vector<int> vRet(m_c);for (int c = 0; c < m_c; c++){CUnionFind uf(m_c);for (const auto& v : edges){if ((v[0] == c) || (v[1] == c)){continue;}uf.Union(v[0], v[1]);}vector<int> vRegionCnt(m_c);for (int ab = 0; ab < m_c; ab++){if (ab == c ){continue;}const int pub = par.GetPublicParent(ab, c);const int len = m_vDisToRoot[ab] + m_vDisToRoot[c] - 2 * m_vDisToRoot[pub];if (0 != len % signalSpeed){continue;}vRegionCnt[uf.GetConnectRegionIndex(ab)]++;}int&iRet = vRet[c];const int total = std::accumulate(vRegionCnt.begin(), vRegionCnt.end(), 0);for (int c1 = 0; c1 < m_c; c1++){iRet += vRegionCnt[c1] * (total - vRegionCnt[c1]);}	iRet /= 2;}return vRet;}void DFS(vector<vector<std::pair<int, int>>>& neiBo, int cur, int par,int leve,int dis){m_vDisToRoot[cur] =dis;m_vParent[cur] = par;m_vLeve[cur] = leve;for (const auto& [next,len] : neiBo[cur]){if (next == par){continue;}DFS(neiBo, next, cur,leve+1,dis+len);}}vector<int> m_vDisToRoot,m_vParent,m_vLeve;int m_c;
};

测试用例

template<class T,class T2>
void Assert(const T& t1, const T2& t2)
{assert(t1 == t2);
}template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{if (v1.size() != v2.size()){assert(false);return;}for (int i = 0; i < v1.size(); i++){Assert(v1[i], v2[i]);}}int main()
{vector<vector<int>> edges;int signalSpeed;{Solution sln;edges = {  }, signalSpeed = 1;auto res = sln.countPairsOfConnectableServers(edges, signalSpeed);Assert({ 0 }, res);}{Solution sln;edges = { {0,1,1} }, signalSpeed = 1;auto res = sln.countPairsOfConnectableServers(edges, signalSpeed);Assert({ 0,0 }, res);}{Solution sln;edges = { {0,1,1},{1,2,1} }, signalSpeed = 1;auto res = sln.countPairsOfConnectableServers(edges, signalSpeed);Assert({ 0,1,0 }, res);}{Solution sln;edges = { {0,1,1},{1,2,5},{2,3,13},{3,4,9},{4,5,2} }, signalSpeed = 1;auto res = sln.countPairsOfConnectableServers(edges, signalSpeed);Assert({ 0,4,6,6,4,0 } , res);}{Solution sln;edges = { {0,6,3},{6,5,3},{0,3,1},{3,2,7},{3,1,6},{3,4,2} }, signalSpeed = 3;auto res = sln.countPairsOfConnectableServers(edges, signalSpeed);Assert({ 2,0,0,0,0,0,2 }, res);}
}

换根法DFS

树中删除一个节点,则各孩子各一个连通区域,除自己及后代外一个区域。如果这个节点是根,则简单得多。各孩子一个连通区域。
DSF(cur) 返回自己及子孙到当前根节点距离是signalSpeed 倍的节点数量。令当前根节点各孩子的返回值是{i1,i2, ⋯ \cdots ,im} 。i1*i2+(i1+i2)*i3 ⋯ \cdots +(I1+i2+ … \dots + i m − 1 _{m-1} m1)*im。这样不必除以二。
a<b ,表示a !=b ,(a,b)和(b,a)只取一个。

class CNeiBo
{
public:	static vector<vector<int>> Two(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0) {vector<vector<int>>  vNeiBo(n);for (const auto& v : edges){vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase);if (!bDirect){vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase);}}return vNeiBo;}	static vector<vector<std::pair<int, int>>> Three(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0){vector<vector<std::pair<int, int>>> vNeiBo(n);for (const auto& v : edges){vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase, v[2]);if (!bDirect){vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase, v[2]);}}return vNeiBo;}
};class Solution {
public:vector<int> countPairsOfConnectableServers(vector<vector<int>>& edges, int signalSpeed) {m_c = edges.size() + 1;m_iSignalSpeed = signalSpeed;		auto neiBo = CNeiBo::Three(m_c, edges, false, 0);		vector<int> vRet(m_c);for (int c = 0; c < m_c; c++){int& iRet = vRet[c];int left = 0;for (const auto& [next, len] : neiBo[c]){int cur = DFS(neiBo, next, c, len);iRet += left * cur;left += cur;}}return vRet;}int DFS(vector<vector<std::pair<int, int>>>& neiBo, int cur, int par,int dis){int iRet = (0 ==dis % m_iSignalSpeed);for (const auto& [next,len] : neiBo[cur]){if (next == par){continue;}iRet +=DFS(neiBo, next, cur,dis+len);}return iRet;}int m_iSignalSpeed;int m_c;
};

割点

本解法过于复杂,除非用了提前封装好的割点扩展类,否则被使用。

class CNeiBo
{
public:	static vector<vector<int>> Two(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0) {vector<vector<int>>  vNeiBo(n);for (const auto& v : edges){vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase);if (!bDirect){vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase);}}return vNeiBo;}	static vector<vector<std::pair<int, int>>> Three(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0){vector<vector<std::pair<int, int>>> vNeiBo(n);for (const auto& v : edges){vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase, v[2]);if (!bDirect){vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase, v[2]);}}return vNeiBo;}
};
class CUnionFind
{
public:CUnionFind(int iSize) :m_vNodeToRegion(iSize){for (int i = 0; i < iSize; i++){m_vNodeToRegion[i] = i;}m_iConnetRegionCount = iSize;}	CUnionFind(vector<vector<int>>& vNeiBo):CUnionFind(vNeiBo.size()){for (int i = 0; i < vNeiBo.size(); i++) {for (const auto& n : vNeiBo[i]) {Union(i, n);}}}int GetConnectRegionIndex(int iNode){int& iConnectNO = m_vNodeToRegion[iNode];if (iNode == iConnectNO){return iNode;}return iConnectNO = GetConnectRegionIndex(iConnectNO);}void Union(int iNode1, int iNode2){const int iConnectNO1 = GetConnectRegionIndex(iNode1);const int iConnectNO2 = GetConnectRegionIndex(iNode2);if (iConnectNO1 == iConnectNO2){return;}m_iConnetRegionCount--;if (iConnectNO1 > iConnectNO2){UnionConnect(iConnectNO1, iConnectNO2);}else{UnionConnect(iConnectNO2, iConnectNO1);}}bool IsConnect(int iNode1, int iNode2){return GetConnectRegionIndex(iNode1) == GetConnectRegionIndex(iNode2);}int GetConnetRegionCount()const{return m_iConnetRegionCount;}vector<int> GetNodeCountOfRegion()//各联通区域的节点数量{const int iNodeSize = m_vNodeToRegion.size();vector<int> vRet(iNodeSize);for (int i = 0; i < iNodeSize; i++){vRet[GetConnectRegionIndex(i)]++;}return vRet;}std::unordered_map<int, vector<int>> GetNodeOfRegion(){std::unordered_map<int, vector<int>> ret;const int iNodeSize = m_vNodeToRegion.size();for (int i = 0; i < iNodeSize; i++){ret[GetConnectRegionIndex(i)].emplace_back(i);}return ret;}
private:void UnionConnect(int iFrom, int iTo){m_vNodeToRegion[iFrom] = iTo;}vector<int> m_vNodeToRegion;//各点所在联通区域的索引,本联通区域任意一点的索引,为了增加可理解性,用最小索引int m_iConnetRegionCount;
};class CParents
{
public:CParents(vector<int>& vParent, const int iMaxLeve){	int iBitNum = 0;for (; (1 << iBitNum) < iMaxLeve; iBitNum++);const int n = vParent.size();m_vParents.assign(iBitNum+1, vector<int>(n, -1));m_vParents[0] = vParent;//树上倍增for (int i = 1; i < m_vParents.size(); i++){for (int j = 0; j < n; j++){const int iPre = m_vParents[i - 1][j];if (-1 != iPre){m_vParents[i][j] = m_vParents[i - 1][iPre];}}}}int GetParent(int iNode, int iLeve)const{int iParent = iNode;for (int iBit = 0; iBit < m_vParents.size(); iBit++){if (-1 == iParent){return iParent;}if (iLeve & (1 << iBit)){iParent = m_vParents[iBit][iParent];}}return iParent;}	
protected:vector<vector<int>> m_vParents;
};class C2Parents : CParents
{
public:C2Parents(vector<int>& vParent, const vector<int>& vLeve) :m_vLeve(vLeve), CParents(vParent,*std::max_element(vLeve.begin(), vLeve.end())){		}	int GetPublicParent(int iNode1, int iNode2)const{int leve0 = m_vLeve[iNode1];int leve1 = m_vLeve[iNode2];if (leve0 < leve1){iNode2 = GetParent(iNode2, leve1 - leve0);leve1 = leve0;}else{iNode1 = GetParent(iNode1, leve0 - leve1);leve0 = leve1;}//二分查找int left = -1, r = leve0;while (r - left > 1){const auto mid = left + (r - left) / 2;const int iParent0 = GetParent(iNode1, mid);const int iParent1 = GetParent(iNode2, mid);if (iParent0 == iParent1){r = mid;}else{left = mid;}}return GetParent(iNode1, r);}
protected:vector<vector<int>> m_vParents;const vector<int> m_vLeve;
};class CCutPointEx
{
public:CCutPointEx(const vector<vector<int>>& vNeiB) : m_iSize(vNeiB.size()){m_vNodeToTime.assign(m_iSize, -1);m_vChildFirstEnd.resize(m_iSize);m_vNodeToRegion.assign(m_iSize, -1);m_vCut.assign(m_iSize, false);for (int i = 0; i < m_iSize; i++){if (-1 != m_vNodeToTime[i]){continue;}dfs(i, -1, vNeiB);m_iRegionCount++;}m_vTimeToNode.resize(m_iSize);for (int i = 0; i < m_iSize; i++){m_vTimeToNode[m_vNodeToTime[i]] = i;;}}bool Visit(int src, int dest, int iCut)const{if (m_vNodeToRegion[src] != m_vNodeToRegion[dest]){return false;//不在一个连通区域}if (!m_vCut[iCut]){return true;}const int r1 = GetCutRegion(iCut, src);const int r2 = GetCutRegion(iCut, dest);return r1 == r2;}vector<vector<int>> GetSubRegionOfCut(const int iCut)const{//删除iCut及和它相连的边后,iCut所在的区域会分成几个区域:父节点一个区域、各子节点一个区域//父节点所在区域可能为空,如果iCut所在的连通区域只有一个节点,则返回一个没有节点的区域。const auto& v = m_vChildFirstEnd[iCut];vector<vector<int>> vRet(1);			int j = 0;for (int iTime=0;iTime < m_iSize; iTime++ ){const int iNode	= m_vTimeToNode[iTime];if ((j < v.size()) && ( iTime  >= v[j].first )){j++;vRet.emplace_back();}if ((iCut != iNode) && (m_vNodeToRegion[iNode] == m_vNodeToRegion[iCut])){if (v.size()&&(iTime >= v.back().second)){vRet[0].emplace_back(iNode);}else{vRet.back().emplace_back(iNode);}}}return vRet;}
protected:int dfs(int cur, int parent, const vector<vector<int>>& vNeiB){auto& curTime = m_vNodeToTime[cur];m_vNodeToRegion[cur] = m_iRegionCount;curTime = m_iTime++;int iCutChild = 0;int iMinTime = curTime;for (const auto& next : vNeiB[cur]){if (-1 != m_vNodeToTime[next]){iMinTime = min(iMinTime, m_vNodeToTime[next]);continue;}int iChildBeginTime = m_iTime;const int iChildMinTime = dfs(next, cur, vNeiB);iMinTime = min(iMinTime, iChildMinTime);if (iChildMinTime >= curTime){iCutChild++;m_vChildFirstEnd[cur].push_back({ iChildBeginTime,m_iTime });};}m_vCut[cur] = (iCutChild + (-1 != parent)) >= 2;return iMinTime;}int GetCutRegion(int iCut, int iNode)const{const auto& v = m_vChildFirstEnd[iCut];auto it = std::upper_bound(v.begin(), v.end(), m_vNodeToTime[iNode], [](int time, const std::pair<int, int>& pr) {return time < pr.first; });if (v.begin() == it){return v.size();}--it;return (it->second > m_vNodeToTime[iNode]) ? (it - v.begin()) : v.size();}int m_iTime = 0;const int m_iSize;//时间戳int m_iRegionCount = 0;vector<int> m_vNodeToTime;//各节点到达时间,从0开始。 -1表示未处理vector<bool> m_vCut;//是否是割点vector<int> m_vNodeToRegion;//各节点所在区域vector<vector<pair<int, int>>> m_vChildFirstEnd;//左闭右开空间[0,m_vChildFirstEnd[0].first)和[m_vChildFirstEnd.back().second,iSize)是一个区域vector<int> m_vTimeToNode;
};

DFS代替树上倍增

时间复杂度的瓶颈在 树上倍增。

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 **C+

+17**
如无特殊说明,本算法用**C++**实现。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FPGA——三速自适应以太网设计(1)基本模块

FPGA——以太网设计&#xff08;1&#xff09;基本模块 1. 协议解析&#xff08;1&#xff09;MAC层&#xff08;2&#xff09;IP层 和 ARP层&#xff08;3&#xff09;UDP层 和 ICMP层 2.1 MAC接收模块2.2 MAC发送模块3.1 IP接收模块3.2 IP发送模块4.1 UDP接收模块4.2 UDP发送…

学习clickhouse 集群搭建和分布式存储

为什么要用集群 使用集群的主要原因是为了提高系统的可扩展性、可用性和容错性。 可扩展性&#xff1a;当单个节点无法处理增加的负载时&#xff0c;可以通过添加更多的节点到集群来增加处理能力。这使得系统可以处理更大的数据量和更高的查询负载。可用性&#xff1a;在集群…

html--3D爱心

文章目录 代码效果 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>爱心</title><style type"text/css">*{margin: 0px;border: 0px;}body{overflow: hidden;background-…

(C语言)深入理解指针1基础

指针是C语言中的一个难点&#xff0c;但如果真正理解了指针&#xff0c;其实没有很难&#xff0c;本篇文章介绍了指针的基础知识&#xff0c;后面还会继续更行指针的内容。感谢支持。 目录 1. 内存和地址 1.1 内存 1.2 究竟该如何理解编址 2. 指针变量和地址 2.1 取地址操…

深入探索HTTP/3协议:核心原理、创新优势与实战部署细节

引言 在互联网技术演进的过程中&#xff0c;HTTP协议扮演着至关重要的角色&#xff0c;它是现代Web应用程序通信的基础。自HTTP/1.1引入持久连接和管道化&#xff0c;再到HTTP/2引入多路复用&#xff0c;每一次迭代都是对网络传输效能的一次提升。如今&#xff0c;HTTP/3作为新…

计算机的基础知识

计算机的特点及应用&#xff1a; 图灵说–计算就是基于规则的符号串变换从20世纪80年代开始&#xff0c;发达国家开始研制第五代计算机&#xff0c;研究的目标是能够打破以往计算机固有的体系结构&#xff0c;使计算机能够具有像人一样的思维、推理和判断能力&#xff0c;向智…

重要通告 | 公司更名为“浙江实在智能科技有限公司”

更名公告 升级蜕变、砥砺前行 因业务快速发展和战略升级&#xff0c;经相关政府机构批准&#xff0c;自2024年3月1日起&#xff0c;原“杭州实在智能科技有限公司”正式更名为“浙江实在智能科技有限公司”。 更名后&#xff0c;公司统一社会信用代码不变&#xff0c;业务主体…

共享文件如何异地部署?

在现代信息化的时代背景下&#xff0c;不同地区之间的文件共享和异地部署是一项重要的任务。共享文件异地部署可以有效提高文件传输的效率&#xff0c;方便不同地区间的合作与协同工作。本文将介绍共享文件异地部署的概念、挑战以及解决方案。 天联组网的作用 天联组网是一种用…

chromedriverUnable to obtain driver for chrome using ,selenium找不到chromedriver

1、下载chromedriver chromedriver下载网址&#xff1a;CNPM Binaries Mirror 老版本在&#xff1a;chromedriver/ 较新版本在&#xff1a;chrome-for-testing/ 2、设置了环境变量还是找不到chromedriverUnable to obtain driver for chrome using NoSuchDriverException:…

上海亚商投顾:沪指震荡微涨 AI手机、军工板块集体走强

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日低开后震荡回升&#xff0c;黄白二线分化明显&#xff0c;银行等权重板块走势较强。AI手机概念股持续…

如何应对IT服务交付中的问题?看了本文DevOps就懂了

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

Maven入门(作用,安装配置,Idea基础maven,Maven依赖,Maven构建项目)【详解】

目录 一. Maven的作用 1.依赖管理 2.统一项目结构 3.项目构建 二.Maven安装配置 1. Maven的仓库类型 2 加载jar的顺序 3. Maven安装配置 4.安装Maven 5.配置仓库 三.idea集成maven 1.给当前project集成maven 2.给新建project集成maven 3.创建maven项目 4.pom…

Web安全:报错注入原理分析,报错注入步骤,报错注入常用函数

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全自学教程》 报错注入 一、什么是报错注入二、执行原理1. 代码逻辑…

okHttp MediaType MIME格式详解

一、介绍 我们在做数据上传时&#xff0c;经常会用到Okhttp的开源库&#xff0c;okhttp开源库也遵循html提交的MIME数据格式。 所以我们经常会看到applicaiton/json这样的格式在传。 但是如果涉及到其他文件等就需要详细的数据格式&#xff0c;否则服务端无法解析 二、okHt…

【ESP32 IDF快速入门】点亮第一个LED灯与流水灯

文章目录 前言一、有哪些工作模式&#xff1f;1.1 GPIO的详细介绍1.2 GPIO的内部框图输入模式输出部分 二、GPIO操作函数2.1 GPIO 汇总2.2 GPIO操作函数gpio_config配置引脚reset 引脚函数设置引脚电平选中对应引脚设置引脚的方向 2.3 点亮第一个灯 三、流水灯总结 前言 ESP32…

MybatisPlus入门详解

一、MyBatisPlus 简介 1.1 创建新模块 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version></dependency> 由于mp并未被收录到idea的系统内置配置,无法…

点胶缺陷视觉检测都是怎么检测的?

点胶工艺是许多工业生产中不可或缺的一环&#xff0c;而点胶缺陷的存在往往直接影响到产品质量。为了提升点胶工艺的品质控制&#xff0c;点胶缺陷的视觉检测成为了一个重要的技术手段。 一、点胶缺陷的类型 点胶缺陷主要包括胶点大小不均、位置偏移、漏点、多点等。这些缺陷如…

【详识JAVA语言】String类oj练习

1. 第一个只出现一次的字符 class Solution { public int firstUniqChar(String s) {int[] count new int[256];// 统计每个字符出现的次数for(int i 0; i < s.length(); i){count[s.charAt(i)];}// 找第一个只出现一次的字符for(int i 0; i < s.length(); i){if(1 …

Vue项目实战--空间论坛(1)

环境准备 安装好node.js,Vue后 添加插件 router---路由&#xff0c;多页面的应用 vuex---在多个组件之间维护同一个数据 添加依赖 bootstrap---美工 popperjs/core vue项目介绍 views-----对应vue文件&#xff0c;页面 router-----路由&#xff0c;页面&#xff0c;c…

Hack The Box-Perfection

目录 信息收集 nmap dirsearch gobuster whatweb WEB 信息收集 ffuf 漏洞探索 漏洞发现 模板注入 反弹shell 提权 get user and flag 信息收集 ssh登录&get root and flag 信息收集 nmap 端口探测┌──(root㉿ru)-[~/kali/hackthebox] └─# nmap -p- 10…