【数位dp】【动态规划】C++算法:233.数字 1 的个数

作者推荐

【动态规划】C++算法312 戳气球

本文涉及的基础知识点

动态规划 数位dp

LeetCode:233数字 1 的个数

给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。
示例 1:
输入:n = 13
输出:6
示例 2:
输入:n = 0
输出:0
提示:
0 <= n <= 109

数位dp的封装类

本题比较简单,主要讲封装类。m_vPre记录上一位所有状态,程序结束时,记录的是最后一位的所有状态。
m_vPre是二维向量,一维长度4,分别表示4种边界状态,下标0记录 非上下界,下标1记录下界,下标2记录上界,3记录同时上下界。二维长度由构造函数的参数iResutlCount决定。ResultType类记录状态。

ELE枚举的元素类型
minEle元素最小值
maxEle元素最大值
pLower下界
pHigh上界
iNum上下界的长度

使用的时完成OnEnumFirstBit和OnEnumOtherBit,OnEnumFirstBit会不重复不遗漏的枚举第一位的 元素和边界状态。
OnEnumOtherBit,此函数会不重复不遗漏的依次枚举其它位的元素和边界状态。
只会枚举在范围内的状态,不会枚举非法状态。
pre和dp 是对应边界状态的状态,所以是一维向量。
注意 : 同一位 同一元素 同一状态 可能枚举两次,这不会造成重复计算。因为是两层枚举,第一层枚举:前一元素的边界状态;第二层枚举:当前元素。

template<class ELE, class ResultType, ELE minEle, ELE maxEle>
class CLowUperr
{
public:CLowUperr(int iResutlCount):m_iResutlCount(iResutlCount){}void Init(const ELE* pLower, const ELE* pHigh, int iNum){m_vPre.assign(4, vector<ResultType>(m_iResutlCount));if (iNum <= 0){return;}InitPre(pLower, pHigh);iNum--;while (iNum--){pLower++;pHigh++;vector<vector<ResultType>> dp(4, vector<ResultType>(m_iResutlCount));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);}}/*ResultType Total(int iMinIndex, int iMaxIndex){ResultType ret;for (int status = 0; status < 4; status++){for (int index = iMinIndex; index <= iMaxIndex; index++){ret += m_vPre[status][index];}}return ret;}*/
protected:const int m_iResutlCount;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;
};

本题代码

核心代码

//pair<int, int> first记录在范围内符合要求的子串数量 second 记录1的数量
class CCharLowerUper : public CLowUperr<char, pair<int, int>, '0', '9'>
{
public:using CLowUperr<char, pair<int, int>, '0', '9'>::CLowUperr;int Total(int iMinIndex, int iMaxIndex){int ret = 0;		for (int index = iMinIndex; index <= iMaxIndex; index++){int cur = 0;for (int status = 0; status < 4; status++){cur += m_vPre[status][index].second;}ret += cur;std::cout << " index:" << index << " " << cur << std::endl;}return ret;}
protected:virtual void OnEnumFirstBit(vector<pair<int, int>>& vPre, const char curValue){const int index = curValue - '0';vPre[index].first =1 ;vPre[index].second = 1 == index;}virtual void OnEnumOtherBit(vector<pair<int,int>>& dp, const vector<pair<int, int>>& vPre, char curValue){const int index = curValue - '0';for (int i = 0; i < 10; i++){dp[index].first += vPre[i].first;dp[index].second += vPre[i].second;if (1 == index){dp[index].second += vPre[i].first;}}		}};
class Solution {
public:int countDigitOne(int n) {const string strN = std::to_string(n);const int len = strN.length();int iRet = 0;for (int i = 1; i < len; i++){CCharLowerUper lu(10);lu.Init(("1" + string(i - 1, '0')).c_str(),string(i,'9').c_str(),i);iRet += lu.Total(0, 9);}CCharLowerUper lu(10);lu.Init(("1" + string(len - 1, '0')).c_str(), strN.c_str(), len);iRet += lu.Total(0, 9);return iRet;}
};

测试用例

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<int> nums;{Solution sln;int n = 30;auto res = sln.countDigitOne(n);Assert(13, res);}{Solution sln;int n=13;auto res = sln.countDigitOne(n);Assert(6, res);}{Solution sln;int n = 0;auto res = sln.countDigitOne(n);Assert(0, res);}}

2023年1月版

class Solution {
public:
int countDigitOne(int n) {
int iNum = 0;
int iMul = 1;
for (int i = 0; i < 9; i++)
{
iNum += n / (iMul * 10) *iMul;
int tmp = n % (iMul * 10);
if (tmp >= iMul)
{
if (tmp >= iMul * 2)
{
tmp = iMul * 2 - 1;
}
iNum += tmp - (iMul - 1);
}
iMul *= 10;
}
if (1000 * 1000 * 1000 == n)
{
iNum++;
}
return iNum;
}
};

2023年8月

class CTest : public CLowUperr<char,int,‘0’,‘9’>
{
public:
CTest():CLowUperr(10)
{
}
// 通过 CLowUperr 继承
virtual void OnDo(vector<vector>& dp, int preStatus, int curStatus, int cur) override
{
dp[curStatus][cur] += m_vPreCan[preStatus];
m_vCurOneNum[curStatus] += m_vPreOneNum[preStatus];
}
virtual void OnInitDP(vector<vector>& dp)
{
for (int i = 0; i < 4; i++)
{
m_vPreCan[i] = std::accumulate(MACRO_BEGIN_END(m_vPre[i]), 0);
m_vPreOneNum[i] = m_vCurOneNum[i] + m_vPre[i][1];
}
memset(m_vCurOneNum, 0, sizeof(m_vCurOneNum));
}
int Total()
{
int iRet = 0;
for (int i = 0; i < 4; i++)
{
iRet += m_vCurOneNum[i] + m_vPre[i][1];
}
return iRet;
}
int m_vPreCan[4] = { 0 };//前四中状态的可能
int m_vPreOneNum[4] = { 0 };//前面4种状态1的数量
int m_vCurOneNum[4] = { 0 };//前面4种状态1的数量
};

class Solution {
public:
int countDigitOne(int n) {
string str = std::to_string(n);
int len = 1;
for (; len < str.length(); len++)
{
Do(“1” + string(len - 1, ‘0’), string(len, ‘9’));
}
Do(“1” + string(len - 1, ‘0’), str);
return m_iRet;
}
void Do(string s1, string s2)
{
CTest test;
test.Init(s1.data(), s2.data(), s1.length());
m_iRet += test.Total();
}
int m_iRet;
};

扩展阅读

视频课程

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

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

相关文章

类和对象的定义以及使用

文章目录 1. 类和对象的基本概念1.1 JAVA是面向对象语言1.2 类和对象的描述 2. 类与对象的定义与使用2.1 类的定义格式2.2 类的实例化(对象的创建)2.3 举个例子 3. 对象的构造及初始化3.1构造方法3.1.1构造方法的定义3.1.2 构造方法的特性 4.2 默认初始化5.4 就地初始化 4.this…

二叉树题目:好叶子结点对的数量

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;好叶子结点对的数量 出处&#xff1a;1530. 好叶子结点对的数量 难度 6 级 题目描述 要求 给定二叉树的根结点 root \texttt{root} root 和整数 …

【Python学习】Python学习5-条件语句

目录 【Python学习】Python学习5-条件语句 前言if语句if语句判断条件简单的语句组参考 文章所属专区 Python学习 前言 本章节主要说明Python的条件语句&#xff0c;Python条件语句是通过一条或多条语句的执行结果&#xff08;True或者False&#xff09;来决定执行的代码块。 …

如何查看崩溃日志

目录 描述 思路 查看ipa包崩溃日志 简单查看手机崩溃信息几种方式 方式1:手机设置查看崩溃日志 方式2: Xocde工具 方式3: 第三方软件克魔助手 环境配置 实时日志 奔溃日志分析 方式四&#xff1a;控制台资源库 线上崩溃日志 线上监听crash的几种方式 方式1: 三方平…

如何启用Windows电脑的内置Administrator账户

前言 不知道从什么时候开始&#xff0c;新电脑或者新系统开机之后都会出现一个界面让你创建一个账户&#xff0c;但这个账户有可能是本地账户&#xff08;Windows10&#xff09;还有强制你登录微软账户的&#xff08;Windows11&#xff09;。 好像曾经熟悉的电脑Administrator…

Taro +vue3 中 实现 选择城市页面 主要逻辑市 选择了某个城市返回之前的页面

1.需求 当我选中了某个城市 这个页面肯定 从某个页面跳转过来的 此时我先选择了城市 再跳转回去 所以有一个问题就是如何写这个逻辑 2.实现 //当前城市页面 onMounted(() > {const instance: any Taro.getCurrentInstance();if (instance.router.params.url) {sourceUr…

Uncaught (in promise) ReferenceError: require is not defined

在 Vue3 中加载项目路径下的资源图片,起初按照之前 vue 的写法 require 但浏览器却抛出了异常 Uncaught (in promise) ReferenceError: require is not defined 因为 require 采用的 webpack 加载方式,而 vue3 中通过 vite 的方式,两者存在差异,所以才产生了刚开始的一目; vu…

C++中的虚函数

前言 本篇文章讲述C的虚函数 定义 在C语言中&#xff0c;基类将类型相关的函数和派生类不做改变直接继承的函数区分开来。对于有些函数&#xff0c;基类希望派生类各自定义适合自身的版本。那么基类就会将这些函数标记为virtual&#xff0c;这些被标记的函数就是虚函数。 下…

2024年如何使用WordPress构建克隆Udemy市场

您想创建像 Udemy 这样的学习管理 (LMS) 网站吗&#xff1f;最好的学习管理系统工具LifterLMS将帮助您制作像Udemy市场这样的 LMS 网站。 目录 Udemy市场是什么&#xff1f; 创建 Udemy 克隆所需的几项强制性技术&#xff1a; 步骤 1) 注册您的域名 步骤 2) 获取虚拟主…

springboot git配置文件自动刷新失败问题排查

http://{ip}:{port}/refresh 说明&#xff1a;springBoot版本是1.5.9&#xff0c;接口路径与2.x&#xff0c;不同 路径区别&#xff1a;/refresh VS /actuator/refresh 用postman调用refresh接口刷新git配置&#xff0c;报错如下&#xff0c;没有权限 在服务本地启动&#…

微信私密朋友圈被吐槽有BUG

日前&#xff0c;大量网友在各社交媒体上讨论微信私密朋友圈出现 Bug 的话题&#xff0c;起因是跨年期间一个网友发布了一条”私密朋友圈&#xff0c;但不一会就收到朋友发来的信息&#xff0c;”又偷偷发朋友圈了&#xff1f;“&#xff0c;估计此时网友可能已经”寒毛四起、汗…

D3篇之色卡

学习传送门&#xff1a;Sequential scales | D3 by Observable 1.scaleSequential(domain, interpolator)&#xff08;连续比例尺&#xff09; 是一种在D3.js中用于将一个范围内的连续值射到另一个范围内的连续值的方法。该比例尺通常用于将数值型数据映射到图表元素的属性上…

jenkins忘记密码后的操作

1、先停止 jenkins 服务 systemctl stop jenkins 关闭Jenkins服务 或者杀掉进程 ps -ef | grep jenkins &#xff5c;awk {print $2} | grep -v "grep" | xargs kill -9 2、找到 config.xml 文件 find /root -name config.xml3、备份config.xml文件 cp /root/.jen…

Java面试——框架篇

1、Spring框架中的单例bean是线程安全的吗&#xff1f; 所谓单例就是所有的请求都用一个对象来处理&#xff0c;而多例则指每个请求用一个新的对象来处理。 结论&#xff1a;线程不安全。 Spring框架中有一个Scope注解&#xff0c;默认的值就是singleton&#xff0c;单例的。一…

【STM32】STM32学习笔记-USART串口外设(26)

00. 目录 文章目录 00. 目录01. 串口简介02. 串口协议03. USART简介04. USART框图05. USART基本结构06. 数据帧07. 起始位侦测08. 数据采样09. 波特率发生器10. 附录 01. 串口简介 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式&#xff0c;因为它简单便…

基于FPGA的RLC测试仪

1. 系统设计 以FPGA为控制器&#xff0c;实现RLC(电阻、电容、电感)的检测&#xff0c;其测量电路如下&#xff1a;

性能优化-OpenMP基础教程(四)-Android上运行OpenMP

本文主要介绍如何在一个常规的Android手机上调试OpenMP程序&#xff0c;包括Android NDK的环境配置和使用JNI编写一个OpenMP程序运行在Android手机中。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;高性能&#…

2023 年精选:每个 DevOps 团队都应该了解的 5 种微服务设计模式

微服务彻底改变了应用程序开发世界&#xff0c;将大型整体系统分解为更小、更易于管理的组件。这种架构风格的特点是独立、松散耦合的服务&#xff0c;带来了从可扩展性、模块化到更高的灵活性等众多优势。 DevOps 团队如何最好地利用这种方法来实现最高效率&#xff1f;答案在…

vue中短时间内多次点击同一个按钮会向后端发送多个请求

在vue中&#xff0c;我们可能会遇到以下问题&#xff1a; 我们有两种方法解决&#xff1a; &#xff08;1&#xff09;可以通过设置一个标志位来防止用户在短时间内多次点击同一个按钮导致向后端发送多个请求。具体实现方式如下&#xff1a; 定义一个 isFetching变量来表示当…

欧盟食品接触材料测试1935/2004/EC介绍

欧盟官方公报(OJ)发布与食品接触的塑料制品法规(EU)10/2011的修订法规(EU)2017/752。欧盟食品级塑料法规从(EU)10/2011发布以来&#xff0c;已历经7次修订&#xff0c;前5次的修订版本均是针对EU10/2011法规里的附录1授权物质清单进行修订。第6次修订法规(EU)2016/1416澄清和纠…