leetcode 233. Number of Digit One

233. Number of Digit One

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,然后统计剩下位数的数字中满足条件的可能情况数。时间复杂度为O(log n).

考虑把某一个位的数字设成1后,分析他位置有多少种选择。然后把每个数字位取1而有的选择都加起来就可以了。


然后来分析其他位置有多少种选择: 假设为1350


(1) 如果将n的个位数置为1,xxx1

该位的数字置1之前为0, 所以从个位数往左边找需要减一的位,是十位数。找到减1的位之后,反过来把后面所有低位变为9,当前由于已经到个位了,所以没有体现出来。变为   0001 - 1341

card({000, 001...134}),满足条件的数共有135个


(2) 如果将n的十位数置为1,xx1x

该位的数字置1之前5>1,由于当前位1小于本来的5.所以 前面不需要减一,后面全部变为 9 。 0010 - 1319

card({000, 001...139}),共140个


(3) 如果将n的百位数置为1,x1xx

该位的数字置1之前3>1,由于当前位1小于本来的3.所以 前面不需要减一,后面全部变为 9.  0100 - 1199

2*card({00, 01...99}),共200个


(4) 如果将n的千位数置为1,1xxx

该位的数字置1之前=1,相等直接求    1000 - 1350

card({000,001...350}),共351个


于是所求的值count=135+140+200+351=826 个 1


class Solution {
public:
    int countDigitOne(int n) 
    {
        if (n <= 0) return 0;
        else if (n < 10) return 1;
        string s = to_string(n);
        int ret = 0;
        for (int i = 0; i < s.size(); i++)
        {
            if (s[i] == '1')
            {
                ret += to_int(s.substr(0, i) + s.substr(i + 1)) + 1;
                continue;
            }   
            
            string ss = s;
            int j = i;
            if (s[i] == '0')
            {
                for (j = i - 1; j >= 0; j--) //往前面找需要减一的位
                {
                    if (s[j] != '0')
                    {
                        ss[j] = ss[j] - 1;
                        break;
                    }
                }
            }
            for (int h = j + 1; h < s.size(); h++) //在减一的位之后所有位都设为最大 ‘9’
                ss[h] = '9';
            
            ret += to_int(ss.substr(0, i) + ss.substr(i + 1)) + 1;  
        }
        return ret;
    }
    
    int to_int(string s)  
    {  
        stringstream ss;    
        ss<<s;    
        int i;    
        ss>>i;    
        return i;  
    } 
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值