Solution 30: 从1到n出现“1”的次数

问题描述

Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.

For example:
Given n = 13,
Return 6, because digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.

解决思路


1. 遍历+计数法(可以转成字符串计数):超时;

2. 数学法:寻找规律。规律就是:

----------------------------------------------------------------------------------------------------------

写一个函数f(N),返回1到N之间出现的"1"的个数,比如f(12) = 5。

假设N = abcde,这里a,b,c,d,e分别是十进制数N的各个数位上的数字。如果要计算百位上出现1

的次数,将受3方面因素影响:百位上的数字,百位以下(低位)的数字,百位(更高位)以上的数字。

如果百位上的数字为0,则可以知道百位上可能出现1的次数由更高位决定,比如12 013,则可以知

道百位出现1的情况可能是100-199,1 100-1 199,……,11 100-11 199,一共有1 200个。也就是

由更高位数字(12) 决定,并且等于更高位数字(12)×当前位数(100)。

如果百位上的数字为1,则可以知道,百位上可能出现1的次数不仅受更高位影响,还受低位影响,

也就是由更高位和低位共同决定。例如12 113, 受更高位影响,百位出现1的情况是100-199,1 100

-1 199,……,11 100-11 199,一共有1 200个,和上面第一种情况一样,等于更高位数字(12)×当

前位数(100)。但它还受低位影响,百位出现1的情况是12 100-12 113,一共114个,等于低位数字

(113)+1。

如果百位上数字大于1(即为2-9),则百位上可能出现1的次数也仅由更高位决定,比如12 213,则

百位出现1的情况是:100-199,1 100-1 199,……,11 100-11 199,12 100-12 199,共1300个

,并且等于更高位数字+1(12+1)×当前位数(100)。

----------------------------------------------------------------------------------------------------------------

举个例子,三位数的话,如下图:

程序

第二种方法:

public class NumOfOnes {
	    public int countDigitOne(int n) {
	    	long cnt = 0;
	    	long base = 1;

	        while (n >= base) {
	            long low = n % base;
	            long cur = (n / base) % 10;
	            long high = n / (base * 10);

	            if (cur == 0) {
	                cnt += high * base;
	            } else if (cur == 1) {
	                cnt += base * high + low + 1;
	            } else {
	                cnt += base * (high + 1);
	            }

	            base *= 10;
	        }

	        return (int) cnt;
	    }
}

值得注意的是,需要使用long甚至更大位数的单位存储cnt,否则容易越界。

时间: 2024-12-21 23:04:07

Solution 30: 从1到n出现“1”的次数的相关文章

[jzoj]1383.奇怪的问题

Link https://jzoj.net/senior/#main/show/1383 Problem Alice总是会提出很多奇怪的问题,一天他让他的朋友Bob跟他一起研究一个奇怪的问题.问题是:[A,B]中有多少个数满足组成这个数的数字之和为S,另一个问题是[A,B]内满足这一要求最小的数是哪个? 编程帮Bob解决这个问题. Solution 30分 显然可以使用暴力枚举,像我这样的渣渣,考试的时候想到数位DP,设完一个不完整的状态,根本不知道如何统计答案 100分 聪明的人都知道,若要求

Nested List Weight Sum II

Given a nested list of integers, return the sum of all integers in the list weighted by their depth. Each element is either an integer, or a list -- whose elements may also be integers or other lists. Different from the previous question where weight

NOIp DP 1003 爆零记

6道DP题只拿了220分,NOIp我不滚粗谁滚粗? 考试历程貌似并没有什么可说的QAQ,就是不停的来回推方程和写崩的状态中. 正经题解 六道题其实除了第六道比较恶心..其他的都还算可以. truck 水题,不多说. 1 //DP truck 2 //by Cydiater 3 //2016.10.3 4 #include <iostream> 5 #include <cstdio> 6 #include <cstdlib> 7 #include <cmath>

Vijos1921严厉的班长

传送门 在贴吧上看到了这道题,恰好最近在学相关的东西,觉得比较有意思就去做了. 第一眼看上去比较像搜索,其实是道状压DP.我简单讲一下思路: 首先明确,不管之前取了什么数,取1必定满足所有的数之间互质.而且如果出现最优的可以是1或者其他,那么1一定是更优的 再思考,对于每个读入的数,合适的范围必定是[1,2*a[i]-2] 而且a[i]<=30,这就很好搞了. 我们表出来所有小于58的素数,把每个数有哪几个素因子二进制表示出来.然后然后如果满足前一个状态&这个数,如果满足的话就更新条件. 1

2016.5.19——Excel Sheet Column Title

Excel Sheet Column Title 本题收获: 1.由int型转换为整型(string),如何转化, res = 'A'+(n-1)%26和之前由A-z转化为十进制相反,res = s[i]-'A'+1.(为什么有+1,-1还有点迷糊,貌似是十进制是0-9,26进制是) 2.十进制到26进制转化 题目: Given a positive integer, return its corresponding column title as appear in an Excel shee

NOI模拟(3.3)螺旋序列

Description S也想寻求真正的智慧,然而由于“抑制力”的存在,她必须先解决一系列询问.有一个长度为n的序列a,一个长度为m序列b被称为螺旋序列当且仅当b1=bm且对于1<=i<=m有bi<=b1.S需要回答q个询问,每个询问用l,r两个参数描述,表示询问区间[l,r]的最长连续子螺旋序列的长度. Input 第一行两个整数n,q,表示序列长度和询问数.第二行n个整数ai表示序列a.以下q行,每行两个整数l,r表示一次询问. Output 对每次询问输出一行一个整数表示最大连续螺

POJ 1038 Bugs Integrated, Inc.

AC通道 神坑的一道题,写了三遍. 两点半开始写的, 第一遍是直接维护两行的二进制.理论上是没问题的,看POJ discuss 上也有人实现了,但是我敲完后准备开始调了.然后就莫名其妙的以为会超时,就删掉了. 第二遍是想错了,因为和之前写过的一道题很像,那道题的正方形最中间不重合即可,所以我以为本质是一样的,然后按照那样的思路写.写写调调到五点半,样例搞掉后,提交,A2T7W1 然后随便找了组数组跟了一下,发现这个方块不允许重合导致这两道题的核心思路差别很大,所以删掉了. 第三遍开始按照自己想的

UVa 11889 (GCD) Benefit

好吧,被大白书上的入门题给卡了.=_=|| 已知LCM(A, B) = C,已知A和C,求最小的B 一开始我想当然地以为B = C / A,后来发现这时候的B不一定满足gcd(A, B) = 1 A要不断地除去gcd(A, B),直到满足gcd(A, B) = 1 B最后就应该乘上A除去的值 1 #include <cstdio> 2 3 typedef long long LL; 4 5 LL gcd(LL a, LL b) 6 { return b == 0 ? a : gcd(b, a%

Matlab:非线性热传导(抛物方程)问题

函数文件1:real_fun.m 1 function f=real_fun(x0,t0) 2 %精确解 3 f=4*x0*(1-x0)*sin(t0); 函数文件2:F.m 1 function f=F(N,u,U,t,h1,h2) 2 %非线性方程组 3 %h1是x的步长,h2是t的步长 4 %u表示迭代节点,上一时刻的数值解 5 %h表示时间节点上的步长 6 %N表示空间节点的步数 7 a0=0.5*t^4*h2*N^2; 8 f(1,1)=a0*(U(2)^2-2*U(1)^2)+h2*