剑指offfer 43 (leetcode 233)整数中出现1的个数

这个题从想思路到实现再到debug,前后差不多用了1个小时时间,不过是因为昨晚十二点多做的,在碰到一种情况时脑子有点不清醒耽误了点时间。

这题作为hard来说 我觉得有点不太够,自认为hard的题应该是那种算法设计的特别巧妙的题,我做这题更像是找规律,不过也可能是别的大神有严谨的

数学推导,还是自己太菜了。

找规律

范围1的个数计算方法
0-91只有1
10 - 1911

十位上的1出现了10次

0-9个位上出现了1次

0-9920

0-9的1出现了1次

10 - 99的个位上的1循环了9次

10-19的十位上1循环了10次

所以0-99 一共出现 20次 1

1 + 9 * 1 + 10 = 20 即

10 * 1 + pow(10, 1) = 20

100 - 199120

百位的1循环了100次

100 - 199 的各位十位出现了 20次1

0 - 999300

0-99 出现了 20次1

从100 - 999的十位个位的1循环了9次0-99中1的个数

100 - 199 百位循环了100次

20 + 9*20 + 100 = 300 即

10 * 20 + pow(10, 2) = 300

0-9999400010 * 300 + pow(10, 3) = 4000

规律找的差不多了,我们把0-9,0-99,0-999,0-9999这种的记为基数

  • 那我们来看一个一般情况,比方说2567

2567 = 2000 + 500 + 60 + 7

对于2000 来说,出现1的个数是百位十位个位的0-999循环了2次,1000 - 1999千位的1循环了1000次,所以就是 2 * 300 + pow(10, 3) = 1600

对于500来说,出现1的个数是十位个位的0-99循环了5次,100-199的百位的1循环了100 次,所以是 5*20 + pow(10, 2) = 200

对于60来说,出现1的个数是个位的0-9循环了6次,10-19的十位循环了10次,所以是6*1 + pow(10, 1) = 16

对于7来说,出现1的个数是就是 7 * 0 + pow(10, 0) = 1

所以一共2567出现了1600 + 200 + 16 + 1 = 1817次

  • 特殊情况,因为2567的每一位都大于1,所以我们2000时就认为千位的1循环了1000次,计算500时百位的1循环了100次,60十位的1循环了10次

但是比方134,当百位是1时,百位并没有循环了100次,而是只循环了35次(100 - 134),因此要分开计算

上代码:

//从构思到解答到debug花了将近一个小时,吐了
class Solution {
public:
    int countDigitOne(int n) { // 3751
        vector<int> bit; // 1573
        bit.push_back(-1);
        while(n) {
            bit.push_back(n % 10);
            n /= 10;
        } //我们先把每一位都单独存出来
        int count = 0; //记录1的总个数
        vector<long> dp{0};
//用来记录基数,dp[0]对应0-9有1个1,dp[1]对应0-99有20个1,dp[2]对应0-999有300个1
        for (int i = 1; i < bit.size(); ++i) { //遍历每一位,累加
            if (bit[i]) { //当该位大于0时我们进行计算
                if (bit[i] > 1) { //当该位>1时,比方300,我们可以放心的循环pow(10, 2)=100次
                    count += bit[i] * dp[i-1] + pow(10, i-1);
      
                }
                else { //当该位为1时,我们只能循环一部分,比方134,只能循环35次
                    int tmp = 0;
                    int j = i-1;
                    while (j > 0) {
                        tmp = tmp * 10 + bit[j--];
                    }
                    tmp += 1; //计算35
                    count += bit[i] * dp[i-1] + tmp;
                }
            }
            //计算当前位的基数
            dp.push_back(dp[i-1]*10 + pow(10, i-1));
        }
        return count;
    }
};

到此就结束了,不知道有没有讲清楚,也没有严谨的推导,这笨办法就是找规律,所以我感觉不像是个hard的题

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值