剑指offer. 43 数字1的个数
题目描述:
给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。
示例:
输入: 13
输出: 6
解释: 数字 1 出现在以下数字中: 1, 10, 11, 12, 13 。
解题思路:
解法1: 挨个算1的次数 O(NlogN) (log以10为底)
解法2:递归算 左神p495 O(logn)
神仙代码: 计算每一位有几个1 O(logn)
分析:https://leetcode.com/problems/number-of-digit-one/discuss/64390/AC-short-Java-solution
常规代码:
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
int count=0;
if(n<1) return 0;
for(int i=1;i<=n;++i)
{
int temp=i;
while(temp){
if(temp%10==1)
++count;
temp/=10;
}
}
return count;
}
};
套路代码:
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
//以下都是n=123
if(n<1)
return 0;
if(n<10)
return 1;
int len = getlen(n); // 计算n有几位 len=3
int temp = pow(10,len-1); // temp = 100;
int first = n/temp; // 计算最高位值 first=1
//计算最高位 有多少个1,分情况讨论假如最高位是1,则有123-100+1 个1,假如大于1 则有100个1,即temp个
int firstnum = (first == 1?(n%temp+1):temp);
//计算24-123 中除了最高位,十位 个位有多少个1
//为啥是24-123呢 因为刚好有 最高位的数字*10^(len-1)个数,也就可以可以平移到1~最高位*10的(len-1)
//公式等于最高位的数字*除去最高位后剩下的位数*某一位固定是1,其他位都可以从0到9自由变化
int othernum = first*(len-1)*(temp/10);
//按照这样的方法递归计算 1-23;
return firstnum+othernum+NumberOf1Between1AndN_Solution(n% temp);
}
int getlen(int n){
int res=0;
while(n){
++res;
n /= 10;
}
return res;
}
};
神仙代码:
class Solution {
public:
int countDigitOne(int n) {
int count=0;
// 计算每一位上1的个数
for(long k=1;k<=n;k *= 10){
int r=n/k, m= n%k; // m表示第k位是几
count +=(r+8) / 10 *k + (r % 10 == 1? m+1:0);
}
return count;
}
};