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

这篇具有很好参考价值的文章主要介绍了【状态压缩】【动态规划】【C++算法】691贴纸拼词。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

作者推荐

视频算法专题

本文涉及知识点

动态规划汇总

状态压缩

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;

};

【状态压缩】【动态规划】【C++算法】691贴纸拼词,# 算法题,算法,动态规划,c++,LeetCode,状态压缩,贴纸,拼词

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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++**实现。

【状态压缩】【动态规划】【C++算法】691贴纸拼词,# 算法题,算法,动态规划,c++,LeetCode,状态压缩,贴纸,拼词文章来源地址https://www.toymoban.com/news/detail-805831.html

到了这里,关于【状态压缩】【动态规划】【C++算法】691贴纸拼词的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++算法 —— 动态规划(3)多状态

    每一种算法都最好看完第一篇再去找要看的博客,因为这样会帮你梳理好思路,看接下来的博客也就更轻松了。当然,我也会尽量在写每一篇时都可以让不懂这个算法的人也能边看边理解。 动规的思路有五个步骤,且最好画图来理解细节,不要怕麻烦。当你开始画图,仔细阅

    2024年02月09日
    浏览(38)
  • AcWing算法学习笔记:动态规划(背包 + 线性dp + 区间dp + 计数dp + 状态压缩dp + 树形dp + 记忆化搜索)

    算法 复杂度 时间复杂度0(nm) 空间复杂度0(nv) 代码 算法 通过滚动数组对01背包朴素版进行空间上的优化 f[i] 与 f[i - 1]轮流交替 若体积从小到大进行遍历,当更新f[i, j]时,f[i - 1, j - vi] 已经在更新f[i, j - vi]时被更新了 因此体积需要从大到小进行遍历,当更新f[i, j]时,f[i - 1,

    2024年02月21日
    浏览(43)
  • 蓝桥杯-回路计数(状态压缩、动态规划)

    蓝桥学院由 21 21 21 栋教学楼组成,教学楼编号 11 11 11 ​​ 到 21 21 21 ​​。对于两栋教学楼 a a a 和 b b b ​,当 a a a 和 b b b 互质时, a a a 和 b b b 之间有一条走廊直接相连,两个方向皆可通行,否则没有直接连接的走廊。 小蓝现在在第一栋教学楼,他想要访问每栋教学楼正

    2024年02月08日
    浏览(60)
  • [动态规划,二进制状态压缩] 旅行商问题

    题目描述 一个国家有 n 个城市,每两个城市之间都开设有航班,从城市 i 到城市 j 的航班价格为 cost[i, j] ,而且往、返航班的价格相同。 售货商要从一个城市出发,途径每个城市 1 次(且每个城市只能经过 1 次),最终返回出发地,而且他的交通工具只有航班,请求出他旅

    2024年01月24日
    浏览(43)
  • 【动态规划】【记忆化搜索】【状态压缩】1681. 最小不兼容性

    【数位dp】【动态规划】【状态压缩】【推荐】1012. 至少有 1 位重复的数字 动态规划汇总 状态压缩 记忆化搜索 给你一个整数数组 nums​​​ 和一个整数 k 。你需要将这个数组划分到 k 个相同大小的子集中,使得同一个子集里面没有两个相同的元素。 一个子集的 不兼容性 是

    2024年02月19日
    浏览(43)
  • 【动态规划】【广度优先搜索】【状态压缩】847 访问所有节点的最短路径

    视频算法专题 动态规划汇总 广度优先搜索 状态压缩 存在一个由 n 个节点组成的无向连通图,图中的节点按从 0 到 n - 1 编号。 给你一个数组 graph 表示这个图。其中,graph[i] 是一个列表,由所有与节点 i 直接相连的节点组成。 返回能够访问所有节点的最短路径的长度。你可

    2024年01月23日
    浏览(41)
  • 【LeetCode动态规划#07】01背包问题一维写法(状态压缩)实战,其二(目标和、零一和)

    力扣题目链接(opens new window) 难度:中等 给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。 返回可以使最终数组和为目标数 S 的所有添加符号的方法数。 示例: 输入

    2023年04月18日
    浏览(63)
  • 算法提高-动态规划-状态机模型

    这题比较简单,主要是学习一下状态机的模版(如何定义状态,dp方程如何推导)。 再学一个知识点:线性dp(i由i-1递推过来)可以用滚动数组优化空间复杂度 限制购买天数 这里也是线性dp,当然可以用滚动数组优化,但是之前大盗阿福写过了,这里就朴素版本了 限制了卖

    2024年02月15日
    浏览(62)
  • 【算法学习】简单多状态-动态规划

            本篇博客记录动态规划中的简单多状态问题。         在之前的动态规划类型的题中,我们每次分析的都只是一种或者某一类的状态,定义的dp表也是围绕着一种状态来的。         现在可能对于一种状态,存在几种不同的子状态,在状态转移过程中相互影响。此时

    2024年01月18日
    浏览(40)
  • 【计算机算法设计与分析】图像压缩问题(C++_动态规划)

    在计算机中常用像素点灰度值序列 { p 1 , p 2 , . . . , p n } { p_1, p_2, ..., p_n } { p 1 ​ , p 2 ​ , ... , p n ​ } 表示图像。其中整数 p i ( 1 ≤ i ≤ n ) p_i(1leq i leq n) p i ​ ( 1 ≤ i ≤ n ) ,表示像素点i的灰度值。通常灰度值的范围是0~255。因此,需要用8位表示一个像素。 图像的变位压

    2024年02月03日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包