【状态压缩】【动态规划】【C++算法】691贴纸拼词

作者推荐

【动态规划】【数学】【C++算法】18赛车

本文涉及知识点

状态压缩 动态规划

LeetCode:691 贴纸拼词

我们有 n 种不同的贴纸。每个贴纸上都有一个小写的英文单词。
您想要拼写出给定的字符串 target ,方法是从收集的贴纸中切割单个字母并重新排列它们。如果你愿意,你可以多次使用每个贴纸,每个贴纸的数量是无限的。
返回你需要拼出 target 的最小贴纸数量。如果任务不可能,则返回 -1 。
注意:在所有的测试用例中,所有的单词都是从 1000 个最常见的美国英语单词中随机选择的,并且 target 被选择为两个随机单词的连接。
示例 1:
输入: stickers = [“with”,“example”,“science”], target = “thehat”
输出:3
解释:
我们可以使用 2 个 “with” 贴纸,和 1 个 “example” 贴纸。
把贴纸上的字母剪下来并重新排列后,就可以形成目标 “thehat“ 了。
此外,这是形成目标字符串所需的最小贴纸数量。
示例 2:
输入:stickers = [“notice”,“possible”], target = “basicbasic”
输出:-1
解释:我们不能通过剪切给定贴纸的字母来形成目标“basicbasic”。

提示:
n == stickers.length
1 <= n <= 50
1 <= stickers[i].length <= 10
1 <= target.length <= 15
stickers[i] 和 target 由小写英文单词组成

封装类

假定target串有个n1字符,数量分别为m_vMax[0] m_vMax[1]…m_vMax[n1-1]。
对于某个stickers串,忽略target中没有的字符。target第0 1 2… 个字符在sticker的数量为vNum[0],vNum[1]…
则第0个字符的mask为1*vNum[0]
第1个字符的mask为(m_vMax[0]+1)*vNum[1]

第i个字符的mask为:Mul [ 0 , i − 1 ] j \Large^j_{[0,i-1]} [0,i1]j(vMax[j]+1)*vNum[i]
总mask 为各字符mask之和。
注意: 无论如何vNum[i]都大于等于0,小于等于m_vMax[i]

class CMask
{
public:void Add(int iMax)//当前最高位范围[0,iMax]{m_vMax.emplace_back(iMax);m_iMaskCount *= (iMax + 1);}vector<int> FromMask(int iMask){vector<int> vNums;for (int i = 0; i < m_vMax.size(); i++){vNums.emplace_back(iMask % (m_vMax[i] + 1));iMask /= (m_vMax[i] + 1);}return vNums;}int ToMask(const vector<int>& vNums,int iMul=1){int iMask = 0;int iUnit = 1;for (int i = 0; i < m_vMax.size(); i++){iMask += iUnit * min(m_vMax[i],vNums[i]* iMul);iUnit *= (m_vMax[i]+1);}return iMask;}int MaskSubVector(int iMask, const vector<int>& vNums, const int iMul = 1){int iNewMask = 0;int iUnit = 1;for (int i = 0; i < m_vMax.size(); i++){int cur = iMask % (m_vMax[i] + 1);cur -= vNums[i] * iMul;cur = max(0, cur);iNewMask += iUnit * cur;iMask /= (m_vMax[i] + 1);iUnit *= (m_vMax[i]+1);}return iNewMask;}int NeedGroupCount(const vector<int>& need, const vector<int>& has){int iMax = 0;for (int i = 0; i < m_vMax.size(); i++){if (has[i] <= 0){continue;}iMax = max(iMax,need[i] / has[i]+ (0 != need[i] % has[i]));}return iMax;}
public:int MaskCount()const{return m_iMaskCount;}	int BitCount()const{return m_vMax.size();}
protected:int m_iMaskCount = 1;vector<int> m_vMax;
};class CStrMask : public CMask
{
public:CStrMask(const string& target){vector<int> vCount;for (const auto& ch : target){if (mCharToIndex.count(ch)){vCount[mCharToIndex[ch]]++;}else{mCharToIndex[ch] = vCount.size();vCount.emplace_back(1);}}for (const auto& cnt : vCount){CMask::Add(cnt);}}vector<int> GetVector(const string& s ){vector<int> vCharNums(m_vMax.size());for (const char& ch : s){if (mCharToIndex.count(ch)){auto& i = vCharNums[mCharToIndex[ch]];if (i < m_vMax[mCharToIndex[ch]]){i++;}				}}return vCharNums;}
protected:unordered_map<char, int> mCharToIndex;
private:void Add(int iMax) {};
};

动态规划

动态规划的状态表示

pre[iMask] 表示利用前i-1个贴纸,达到未完成的字符状态为iMask的消耗的最少贴纸数。1000表示无法达成。
dp[iMask] 表示利用前i 个贴纸,达到未完成的字符状态为iMask的消耗的最少贴纸数。

动态规划的转移方程

iPreMask 当前贴纸 使用的贴纸数量 如果状态发生变化,则更新状态。

动态规划的填表顺序

对于每个合法的iPreMask,计算当前贴纸最多需要多少份。三层循环:第一层,枚举各贴纸。第二层,枚举pre各状态。第三层:枚举当前贴纸使用的数量。每次处理还要枚举各字符。
故总时间复杂度为:O(50*2151515)

动态规划的初始状态

pre[iMaskCount-1=0 其它值为1000。

动态规划的返回值

pre[0]

代码

核心代码

class Solution {
public:int minStickers(vector<string>& stickers, string target) {CStrMask mask(target);vector<vector<int>> vMaskToCounts(mask.MaskCount());for (int i = 0; i < mask.MaskCount(); i++){vMaskToCounts[i] = mask.FromMask(i);}vector<int> vPre(mask.MaskCount(), 1000);vPre[mask.MaskCount() - 1] = 0;for (const auto s : stickers){auto vCharNums = mask.GetVector(s);vector<int> dp = vPre;//不选择for (int iPre = 0; iPre < mask.MaskCount(); iPre++){if (vPre[iPre] >= 1000){continue;}const int iSelMax = mask.NeedGroupCount(vMaskToCounts[iPre], vCharNums);for (int iSel = 1; iSel <= iSelMax; iSel++){const int iNewMask = mask.MaskSubVector(iPre, vCharNums, iSel);dp[iNewMask] = min(dp[iNewMask], vPre[iPre] + iSel);}}vPre.swap(dp);}return (vPre[0] >= 1000) ? -1 : vPre[0];}
};

测试用例

template<class T>
void Assert(const T& t1, const T& 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<string> stickers;string target;{Solution sln;stickers = { "travel", "quotient", "nose", "wrote", "any" }, target = "lastwest";auto res = sln.minStickers(stickers, target);Assert(4, res);}{Solution sln;stickers = { "with", "example", "science" }, target = "thehat";auto res = sln.minStickers(stickers, target);Assert(3, res);}{Solution sln;stickers = { "notice", "possible" }, target = "basicbasic";auto res = sln.minStickers(stickers, target);Assert(-1, res);}{Solution sln;stickers = { "right", "ten", "year", "share", "period", "paper", "expect", "village", "home", "happen", "ring", "sat", "even", "afraid", "paint", "self", "range", "camp", "note", "read", "paragraph", "run", "basic", "fill", "week", "his", "star", "power", "any", "colony", "object", "free", "dark", "said", "chick", "true", "glad", "child", "room", "lost", "am", "cry", "quiet", "crease", "while", "race", "fun", "found", "dream", "once" }, target = "materialhalf";auto res = sln.minStickers(stickers, target);Assert(4, res);}{Solution sln;stickers = { "indicate","why","finger","star","unit","board","sister","danger","deal","bit","phrase","caught","if","other","water","huge","general","read","gold","shall","master","men","lay","party","grow","view","if","pull","together","head","thank","street","natural","pull","raise","cost","spoke","race","new","race","liquid","me","please","clear","could","reply","often","huge","old","nor" }, target = "fhhfiyfdcwbycma";auto res = sln.minStickers(stickers, target);Assert(9, res);}}

改进简洁版,性能略差

不区分dp pre,因为一个贴纸可以无限使用。无论是pre[iMask]和dp[iMask] 都可增加贴纸。

动态规划的状态表示

状态压缩:如果target第i位已经贴好,则此位为1;否则此位为0。
dp[iMask] 已经完成iMask 消耗的最少贴纸数。

动态规划的转移方程。

对应每个mask,只需要考虑一个当前贴纸。比如: 目标串为aaa,贴纸为a。状态0只考虑一个贴纸。状态1只考虑1个贴纸,总共2个贴纸。状态3只考虑1个贴纸,总共3个贴纸。
如果目标串有多个相同字符,只需要匹配第一字符。“???” 第一张贴纸后,变成"a??" 不需要考虑“?a?"
方案一:第i步匹配第1个a,第j个步匹配第2个a。
方案二:第i步匹配第2个a,第j个步匹配第1个a。
如果方案二,能达到目标,那方案一显然也能达到目标。
iPreMask等于iNewMask 也不用排除,因为新值比旧值大1,必定被淘汰。

class Solution {
public:int minStickers(vector<string>& stickers, string target) {const int iMaskCount = 1 << target.size();vector<int> dp(iMaskCount, 1000);dp[0] = 0;for (const auto s : stickers){int cnt1[26] = { 0 };for (const auto& ch : s){cnt1[ch - 'a']++;}for (int iPreMask = 0; iPreMask < iMaskCount; iPreMask++){int cnt[26] = { 0 };memcpy(cnt, cnt1, sizeof(cnt1));int iNewMask = iPreMask;for (int j = 0; j < target.size(); j++){if (iPreMask & (1 << j)){continue;//已经拼成}if (cnt[target[j] - 'a']){cnt[target[j] - 'a']--;iNewMask |= (1 << j);}}dp[iNewMask] = min(dp[iNewMask], dp[iPreMask] + 1);}		}return (dp.back() >= 1000) ? -1 : dp.back();}
};

2023年1月第一版

class Solution {
public:
int minStickers(vector& stickers, string target) {
m_target = target;
for (auto& ch : target)
{
m_mTarget[ch]++;
}
std::unordered_set hasMask;
hasMask.insert(0);
std::unordered_map<int,int> preMaskNum;
preMaskNum[0] = 0;
for (auto& s : stickers)
{
std::unordered_map<char, int> mCur;
for (auto& ch : s)
{
if (m_mTarget.count(ch))
{
mCur[ch]++;
}
}
std::unordered_map<int, int> dp = preMaskNum;
const int iCurMask = MakeMask(mCur);
if (hasMask.count(iCurMask))
{
continue;
}
hasMask.insert(iCurMask);
for (const auto& preMask : preMaskNum )
{
std::unordered_map<char, int> mPre;
ParseMask(mPre, preMask.first);
bool bAdd = true;
int iNum = preMask.second;
while (bAdd)
{
bAdd = false;
for (const auto it : mCur)
{
if (m_mTarget[it.first] > mPre[it.first])
{
bAdd = true;
mPre[it.first] = min(m_mTarget[it.first], mPre[it.first] + mCur[it.first]);
}
}
if (bAdd)
{
iNum++;
const int iMask = MakeMask(mPre);
if (dp.count(iMask))
{
dp[iMask] = min(dp[iMask], iNum);
}
else
{
dp[iMask] = iNum;
}
}
}
}
preMaskNum.swap(dp);
}
int iMaskTargt = MakeMask(m_mTarget);
if (preMaskNum.end() == preMaskNum.find(iMaskTargt))
{
return -1;
}
return preMaskNum[iMaskTargt];
}
int MakeMask(const std::unordered_map<char, int>& nums)const
{
int iMask = 0;
for (const auto& mm : m_mTarget )
{
auto it = nums.find(mm.first);
if ((nums.end() != it) && ( it->second > 0 ))
{
iMask = iMask * (mm.second + 1) + min(mm.second, it->second);
}
else
{
iMask = iMask * (mm.second + 1);
}
}
return iMask;
}
void ParseMask(std::unordered_map<char, int>& nums, int iMask)
{
int iMul = 1;
for (auto& it : m_mTarget)
{
iMul *= (it.second+1);
}
for (auto it = m_mTarget.begin(); it != m_mTarget.end(); ++it)
{
iMul /= (it->second+1);
nums[it->first] = iMask / iMul;
iMask %= iMul;
}
}
std::string m_target;
std::unordered_map<char, int> m_mTarget;
};

2023年1月第2版

class Solution {
public:
int minStickers(vector& stickers, string target) {
m_target = target;
Init();
vector<std::unordered_map<char, int>> mAllCharNum;
{
std::unordered_set hasMask;
hasMask.insert(0);
for (int i = stickers.size() - 1; i >= 0; i–)
{
std::unordered_map<char, int> mCur;
for (auto& ch : stickers[i])
{
if (m_mTarget.count(ch))
{
mCur[ch]++;
}
}
const int iCurMask = MakeMask(mCur);
if (hasMask.count(iCurMask))
{
continue;
}
hasMask.insert(iCurMask);
mAllCharNum.push_back(mCur);
}
}
std::unordered_set setPreMask,setHasDo;
setPreMask.insert(m_iTargetMask);
setHasDo.insert(m_iTargetMask);
for (int iOpeNum = 1; iOpeNum <= target.length(); iOpeNum++)
{
std::unordered_set dp;
for (auto& preMask : setPreMask)
{
std::unordered_map<char, int> mPre;
ParseMask(mPre, preMask);
for (auto& mCur : mAllCharNum)
{
const int iSubMask = GetSubMask(mPre, mCur);
if (0 == iSubMask)
{
continue;
}
const int iNewMask = preMask - iSubMask;
if (setHasDo.count(iNewMask))
{
continue;
}
if (iNewMask == 0 )
{
return iOpeNum;
}
setHasDo.insert(iNewMask);
dp.insert(iNewMask);
}
}
setPreMask.swap(dp);
vector<std::unordered_map<char, int>> mAllTmp;
for (auto& it : setPreMask)
{
std::unordered_map<char, int> tmp;
ParseMask(tmp, it);
mAllTmp.push_back(tmp);
}
}
return -1;
}
int GetSubMask(const std::unordered_map<char, int>& mPre, const std::unordered_map<char, int>& mCur)
{
int iSubMask = 0;
for (auto& cur : mCur)
{
auto pre = mPre.find(cur.first);
if (pre->second )
{
iSubMask += min(pre->second, cur.second) * m_vCharMul[cur.first-‘a’];
}
}
return iSubMask;
}
int MakeMask(const std::unordered_map<char, int>& nums)const
{
int iMask = 0;
for (const auto& mm : m_mTarget )
{
auto it = nums.find(mm.first);
if ((nums.end() != it) && ( it->second > 0 ))
{
iMask = iMask * (mm.second + 1) + min(mm.second, it->second);
}
else
{
iMask = iMask * (mm.second + 1);
}
}
return iMask;
}
void ParseMask(std::unordered_map<char, int>& nums, int iMask)
{
for (auto it = m_mTarget.begin(); it != m_mTarget.end(); ++it)
{
const int iMul = m_vCharMul[it->first-‘a’];
nums[it->first] = iMask / iMul;
iMask %= iMul;
}
}
void Init()
{
for (auto& ch : m_target)
{
m_mTarget[ch]++;
}
m_iTargetMask = MakeMask(m_mTarget);
int iMul = 1;
for (auto& it : m_mTarget)
{
iMul *= (it.second + 1);
}
for (auto it = m_mTarget.begin(); it != m_mTarget.end(); ++it)
{
iMul /= (it->second + 1);
m_vCharMul[it->first - ‘a’] = iMul;
}
}
std::string m_target;
int m_iTargetMask;
std::unordered_map<char, int> m_mTarget;
int m_vCharMul[26] ;
};

2023年1月第三版

class Solution {
public:
int minStickers(vector& stickers, string target) {
m_target = target;
Init();

	 vector<std::unordered_map<char, int>> mAllCharNum;{std::unordered_set<int> hasMask;hasMask.insert(0);for (int i = stickers.size() - 1; i >= 0; i--){std::unordered_map<char, int> mCur;for (auto& ch : stickers[i]){if (m_mTarget.count(ch)){mCur[ch]++;}}const int iCurMask = MakeMask(mCur);if (hasMask.count(iCurMask)){continue;}hasMask.insert(iCurMask);mAllCharNum.push_back(mCur);}}std::unordered_set<int> setPreMask,setHasDo;setPreMask.insert(m_iTargetMask);setHasDo.insert(m_iTargetMask);for (int iOpeNum = 1; iOpeNum <= target.length(); iOpeNum++){std::unordered_set<int> dp;for (auto& preMask : setPreMask){std::unordered_map<char, int> mPre;ParseMask(mPre, preMask);char chFristNeedChar = 0;for (auto& it : mPre){if (it.second > 0){chFristNeedChar = it.first;break;}}for (auto& mCur : mAllCharNum){if ((0 == mCur.count(chFristNeedChar)) || (mCur[chFristNeedChar] <= 0 )){continue;}const int iSubMask = GetSubMask(mPre, mCur);if (0 == iSubMask){continue;}const int iNewMask = preMask - iSubMask;if (setHasDo.count(iNewMask)){continue;}if (iNewMask == 0 ){return iOpeNum;}setHasDo.insert(iNewMask);dp.insert(iNewMask);}}setPreMask.swap(dp);vector<std::unordered_map<char, int>> mAllTmp;for (auto& it : setPreMask){std::unordered_map<char, int> tmp;ParseMask(tmp, it); mAllTmp.push_back(tmp);}}return -1;}int GetSubMask(const std::unordered_map<char, int>& mPre, const std::unordered_map<char, int>& mCur){int iSubMask = 0;for (auto& cur : mCur){auto pre = mPre.find(cur.first);if (pre->second ){iSubMask += min(pre->second, cur.second) * m_vCharMul[cur.first-'a'];}}return iSubMask;}int MakeMask(const std::unordered_map<char, int>& nums)const{int iMask = 0;for (const auto& mm : m_mTarget ){auto it = nums.find(mm.first);if ((nums.end() != it) && ( it->second > 0 ))			{iMask = iMask * (mm.second + 1) + min(mm.second, it->second);}else{iMask = iMask * (mm.second + 1);}}return iMask;}void ParseMask(std::unordered_map<char, int>& nums, int iMask){for (auto it = m_mTarget.begin(); it != m_mTarget.end(); ++it){const int iMul = m_vCharMul[it->first-'a'];nums[it->first] = iMask / iMul;iMask %= iMul;}}void Init(){for (auto& ch : m_target){m_mTarget[ch]++;}m_iTargetMask = MakeMask(m_mTarget);int iMul = 1;for (auto& it : m_mTarget){iMul *= (it.second + 1);}for (auto it = m_mTarget.begin(); it != m_mTarget.end(); ++it){iMul /= (it->second + 1);m_vCharMul[it->first - 'a'] = iMul;}}std::string m_target;int m_iTargetMask;std::unordered_map<char, int> m_mTarget;int m_vCharMul[26] ;

};

2023年1月 第4版

class CCTestHash
{
public:
std::size_t operator()(const std::unordered_map<char, int>& nums) const
{
return MakeMask(nums);
}
static int MakeMask(const std::unordered_map<char, int>& nums)
{
int iMask = 0;
for (const auto& mm : m_mTarget)
{
auto it = nums.find(mm.first);
if ((nums.end() != it) && (it->second > 0))
{
iMask = iMask * (mm.second + 1) + min(mm.second, it->second);
}
else
{
iMask = iMask * (mm.second + 1);
}
}
return iMask;
}

static void Init(){m_mTarget.clear();for (auto& ch : m_target){m_mTarget[ch]++;}m_iTargetMask = MakeMask(m_mTarget);int iMul = 1;for (auto& it : m_mTarget){iMul *= (it.second + 1);}for (auto it = m_mTarget.begin(); it != m_mTarget.end(); ++it){iMul /= (it->second + 1);m_vCharMul[it->first - 'a'] = iMul;}}static std::string m_target;
static int m_iTargetMask;
static std::unordered_map<char, int> m_mTarget;
static int m_vCharMul[26];

};
std::string CCTestHash::m_target;
int CCTestHash::m_iTargetMask;
std::unordered_map<char, int> CCTestHash::m_mTarget;
int CCTestHash::m_vCharMul[26];

class Solution {
public:
int minStickers(vector& stickers, string target) {
CCTestHash::m_target = target;
CCTestHash::Init();

	 std::unordered_set<std::unordered_map<char, int>, CCTestHash> hasMask;{			 for (int i = stickers.size() - 1; i >= 0; i--){std::unordered_map<char, int> mCur;for (auto& ch : stickers[i]){if (m_testHask.m_mTarget.count(ch)){mCur[ch]++;}}if (0 == mCur.size()){continue;}if (hasMask.count(mCur)){continue;}hasMask.insert(mCur);}}std::unordered_set<std::unordered_map<char, int>, CCTestHash> setPreMask, setHasDo;setPreMask.insert(CCTestHash::m_mTarget);setHasDo.insert(CCTestHash::m_mTarget);for (int iOpeNum = 1; iOpeNum <= target.length(); iOpeNum++){std::unordered_set<std::unordered_map<char, int>, CCTestHash> dp;for (auto& mPre : setPreMask){char chFristNeedChar = 0;for (auto& it : mPre){if (it.second > 0){chFristNeedChar = it.first;break;}}for (auto& mCur : hasMask){if ((0 == mCur.count(chFristNeedChar)) || (mCur.find(chFristNeedChar)->second <= 0 )){continue;}auto newMask = GetSubMask(mPre, mCur);if (setHasDo.count(newMask)){continue;}if (CCTestHash::MakeMask(newMask) == 0){return iOpeNum;}setHasDo.insert(newMask);dp.insert(newMask);}}setPreMask.swap(dp);}return -1;}std::unordered_map<char, int> GetSubMask(const std::unordered_map<char, int>& mPre, const std::unordered_map<char, int>& mCur){std::unordered_map<char, int> vRet;for (auto& pre : mPre){auto cur = mCur.find(pre.first);if (mCur.end() != cur){vRet[pre.first] = max(0, pre.second - cur->second);}else{vRet[pre.first] = pre.second;}}return vRet;}/*int MakeMask(const std::unordered_map<char, int>& nums)const{int iMask = 0;for (const auto& mm : m_mTarget ){auto it = nums.find(mm.first);if ((nums.end() != it) && ( it->second > 0 ))			{iMask = iMask * (mm.second + 1) + min(mm.second, it->second);}else{iMask = iMask * (mm.second + 1);}}return iMask;}void ParseMask(std::unordered_map<char, int>& nums, int iMask){for (auto it = m_mTarget.begin(); it != m_mTarget.end(); ++it){const int iMul = m_vCharMul[it->first-'a'];nums[it->first] = iMask / iMul;iMask %= iMul;}}*/CCTestHash m_testHask;

};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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.hqwc.cn/news/415311.html

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

相关文章

MyBatisPlus学习笔记二

接上&#xff1a;MyBatisPlus学习笔记一&#xff1a; MyBatisPlus学习笔记一-CSDN博客 1、条件构造器 MyBatisPlus支持各种复杂的where条件&#xff0c;可以满足日常开发的所有需求。 1.1、集成体系 1.2、实例 查询 lambda查询 更新 1.3、总结 2、自定义sql 我们可以利用MyB…

SSL之mkcert构建本地自签名

文章目录 1. 什么是SSL2. mkcert&#xff1a;快速生成自签名证书2.1 mkcert的工作流程如下&#xff1a;2.2 window 本地实现自签证书2.2.1 下载安装2.2.2 下载,生成本地 SSL2.2.3 生成 pem 自签证书,可供局域网内使用其他主机访问。2.2.4 使用-psck12 生成*.p12 文件 2.3 Sprin…

竞赛保研 大数据房价预测分析与可视

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 大数据房价预测分析与可视 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&#xff0c;适合…

方案解决:5G基站节能及数字化管理

截至2023年10月&#xff0c;我国5G基站总数达321.5万个&#xff0c;占全国通信基站总数的28.1%。然而&#xff0c;随着5G基站数量的快速增长&#xff0c;基站的能耗问题也逐渐日益凸显&#xff0c;基站的用电给运营商带来了巨大的电费开支压力&#xff0c;降低5G基站的能耗成为…

Python高级编程之IO模型与协程

更多Python学习内容&#xff1a;ipengtao.com 在Python高级编程中&#xff0c;IO模型和协程是两个重要的概念&#xff0c;它们在处理输入输出以及异步编程方面发挥着关键作用。本文将介绍Python中的不同IO模型以及协程的概念、原理和用法&#xff0c;并提供丰富的示例代码来帮助…

视频号如何提取链接,新手怎么获取视频号链接!

视频号如何提取视频号链接&#xff0c;新手怎么获取视频号链接&#xff1f; 微信视频号是腾讯在2020年1月22日开启内侧的&#xff0c;视频号的视频链接在微信版本8.032中进行提及&#xff0c;也是微信在这个版本中增加的功能之一。 视频号链接怎么来的&#xff1f; 视频号链接…

Linux下进程子进程的退出情况

进程的退出分为了两大类&#xff0c;一类是正常的退出&#xff0c;另一类是非正常的退出。 正常退出时有五种情况&#xff0c;分别是 ①main函数调用return ②进程调用exit(),标准c库 ③进程调用_exit()或者_Exit()&#xff0c;属于系统调用 ④进程最后一个线程返回 ⑤最…

科普栏目|智能酒精壁炉 vs. 传统取暖:优势对比一目了然

随着科技的飞速发展&#xff0c;家居取暖方式也在逐渐朝着智能化、高效能源利用的方向迈进。在众多壁炉类型中&#xff0c;智能酒精壁炉以其独特的优势正成为现代家庭取暖的选择&#xff0c;下面将详细探讨智能酒精壁炉相较其他类型壁炉的卓越之处。 1.智能酒精壁炉采用酒精作为…

开发设计和迭代管理效率提升:PDManer元数建模

一、引言 在复杂多变的软件开发全生命周期中&#xff0c;数据库设计与建模扮演着举足轻重的角色。这一环节不仅关乎数据存储效率和应用性能优化&#xff0c;而且对于系统架构稳健性及业务逻辑清晰化具有深远影响。因此&#xff0c;选择一款功能强大且高效的数据库建模工具至关…

办公电脑监控软件推荐哪个 | 办公电脑监控软件价格

随着信息技术的不断发展&#xff0c;办公电脑监控软件已成为企业管理员工工作和保障信息安全的重要工具。 然而&#xff0c;市场上的办公电脑监控软件种类繁多&#xff0c;功能和价格也各不相同&#xff0c;让企业用户在选择时感到困惑。 一、办公电脑监控软件价格 办公电脑监…

FPC柔性化机器视觉缺陷检测

FPC(柔性电路板)在电子产品中扮演着至关重要的角色&#xff0c;其质量和可靠性直接影响到产品的性能和安全性。在FPC线路板加工过程中&#xff0c;由于制造工艺的复杂性&#xff0c;很容易产生各种缺陷&#xff0c;如焊锡不良、偏位、漏铜、短路等&#xff0c;因为有太多的环节…

2024年1月编程排行榜出炉!Python遥遥领先!

2024年1月TIOBE编程语言排行榜出炉啦&#xff01;Python依然位于榜首&#xff0c;占比为13.97%。尽管本月有所下跌&#xff08;2.39%&#xff09;&#xff0c;但它仍然是排名第一的编程语言。 2023年人工智能、AI崛起的趋势&#xff0c;Python的热度也一直遥遥领先。不止TIOBE编…