本文涉及知识点
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++**实现。