本文涉及知识点
数位dp
动态规划汇总
LeetCode2827. 范围中美丽整数的数目
给你正整数 low ,high 和 k 。
如果一个数满足以下两个条件,那么它是 美丽的 :
偶数数位的数目与奇数数位的数目相同。
这个整数可以被 k 整除。
请你返回范围 [low, high] 中美丽整数的数目。
示例 1:
输入:low = 10, high = 20, k = 3
输出:2
解释:给定范围中有 2 个美丽数字:[12,18]
- 12 是美丽整数,因为它有 1 个奇数数位和 1 个偶数数位,而且可以被 k = 3 整除。
- 18 是美丽整数,因为它有 1 个奇数数位和 1 个偶数数位,而且可以被 k = 3 整除。
以下是一些不是美丽整数的例子: - 16 不是美丽整数,因为它不能被 k = 3 整除。
- 15 不是美丽整数,因为它的奇数数位和偶数数位的数目不相等。
给定范围内总共有 2 个美丽整数。
示例 2:
输入:low = 1, high = 10, k = 1
输出:1
解释:给定范围中有 1 个美丽数字:[10] - 10 是美丽整数,因为它有 1 个奇数数位和 1 个偶数数位,而且可以被 k = 1 整除。
给定范围内总共有 1 个美丽整数。
示例 3:
输入:low = 5, high = 5, k = 2
输出:0
解释:给定范围中有 0 个美丽数字。 - 5 不是美丽整数,因为它的奇数数位和偶数数位的数目不相等。
提示:
0 < low <= high <= 109
0 < k <= 20
数位dp
直接使用封装类,枚举类型char,最小值’0’,最大值’9’,结果类型:int。
状态数量:400。
i1 = 奇数数数量-偶数位数量+10,取值范围 ∈ \in ∈[1,19]
i2 = 当前数字%k
状态压缩:20*i1+i2
代码
核心代码
template<class ELE, class ResultType, ELE minEle, ELE maxEle>
class CLowUperr
{
public:CLowUperr(int iCustomStatusCount) :m_iCustomStatusCount(iCustomStatusCount){}void Init(const ELE* pLower, const ELE* pHigh, int iNum){m_vPre.assign(4, vector<ResultType>(m_iCustomStatusCount));if (iNum <= 0){return;}InitPre(pLower, pHigh);iNum--;while (iNum--){pLower++;pHigh++;vector<vector<ResultType>> dp(4, vector<ResultType>(m_iCustomStatusCount));OnInitDP(dp);//处理非边界for (auto tmp = minEle; tmp <= maxEle; tmp++){OnEnumOtherBit(dp[0], m_vPre[0], tmp);}//处理下边界OnEnumOtherBit(dp[1], m_vPre[1], *pLower);for (auto tmp = *pLower + 1; tmp <= maxEle; tmp++){OnEnumOtherBit(dp[0], m_vPre[1], tmp);}//处理上边界OnEnumOtherBit(dp[2], m_vPre[2], *pHigh);for (auto tmp = minEle; tmp < *pHigh; tmp++){OnEnumOtherBit(dp[0], m_vPre[2], tmp);}//处理上下边界if (*pLower == *pHigh){OnEnumOtherBit(dp[3], m_vPre[3], *pLower);}else{OnEnumOtherBit(dp[1], m_vPre[3], *pLower);for (auto tmp = *pLower + 1; tmp < *pHigh; tmp++){OnEnumOtherBit(dp[0], m_vPre[3], tmp);}OnEnumOtherBit(dp[2], m_vPre[3], *pHigh);}m_vPre.swap(dp);}}
protected:const int m_iCustomStatusCount;void InitPre(const ELE* const pLower, const ELE* const pHigh){for (ELE cur = *pLower; cur <= *pHigh; cur++){int iStatus = 0;if (*pLower == cur){iStatus = *pLower == *pHigh ? 3 : 1;}else if (*pHigh == cur){iStatus = 2;}OnEnumFirstBit(m_vPre[iStatus], cur);}}virtual void OnEnumOtherBit(vector<ResultType>& dp, const vector<ResultType>& vPre, ELE curValue) = 0;virtual void OnEnumFirstBit(vector<ResultType>& vPre, const ELE curValue) = 0;virtual void OnInitDP(vector<vector<ResultType>>& dp){}vector<vector<ResultType>> m_vPre;
};class CMy : public CLowUperr<char, int, '0', '9'>
{
public:typedef int ResultType;typedef char ELE;CMy(int k) :CLowUperr<char, int, '0', '9'>(400), m_iK(k){}virtual void OnEnumOtherBit(vector<ResultType>& dp, const vector<ResultType>& vPre, ELE curValue){const int index = curValue - '0';for (int iPreMask = 0; iPreMask < m_iCustomStatusCount; iPreMask++){const int preK = iPreMask % 20;const int pre01 = iPreMask / 20 ;const int k = (preK*10+index) % m_iK;int i01 = (index & 1) ? 1 : -1;if ((pre01 + i01 < 0) || (pre01 + i01 >= 20)){continue;}const int mask = Mask(pre01+i01-10, k);dp[mask] += vPre[iPreMask];}}virtual void OnEnumFirstBit(vector<ResultType>& vPre, const ELE curValue){const int index = curValue - '0';const int k = index % m_iK;int i01 = (index & 1) ? 1 : -1;const int mask = Mask(i01,k);vPre[mask]++;}int Result()const{int iRet = 0;for (int status = 0; status < 4; status++){iRet += m_vPre[status][200];}return iRet;}
protected:int Mask(int i01, int k) { return (i01 + 10) * 20 + k; }const int m_iK;
};
class Solution {
public:int numberOfBeautifulIntegers(int low, int high, int iK) {string strLow = std::to_string(low);string strHigh = std::to_string(high);int iRet = 0;const int len1 = strLow.length();const int len2 = strHigh.length();if (len1 == len2){return Do(strLow, strHigh, iK);}iRet += Do(strLow, string(len1, '9'),iK);for (int i = len1 + 1; i < len2; i++){iRet += Do("1" + string(i - 1, '0'), string(i, '9'), iK);}iRet += Do("1" + string(len2 - 1, '0'), strHigh, iK);return iRet;}int Do(const string strLow,const string& strHigh,int k){CMy my(k);my.Init(strLow.data(), strHigh.data(), strLow.length());return my.Result();}
};
测试用例
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()
{int low = 1, high = 10, k = 1;{low = 1, high = 10, k = 1;auto res = Solution().numberOfBeautifulIntegers(low, high, k);Assert(1, res);}{low = 5, high = 5, k = 2;auto res = Solution().numberOfBeautifulIntegers(low, high, k);Assert(0, res);}{low = 10, high = 20, k = 3;auto res = Solution().numberOfBeautifulIntegers(low, high, k);Assert(2, res);}}
扩展阅读
视频课程
有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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++**实现。