剑指offer 1~n中整数1出现的次数

题目简介

给一个整数n,求1-n的十进制整数中1出现的次数;
例如 输入 12,输出 5 ,因为 1,10,11,12中,1一共出现了5次;

越是简洁,越是不简单,这题leetcode困难难度的确实让我头疼了蛮久

解题思路

分别计算一个数的个位百位…对应的组合数,最后相加,分别对应的位元素 是大于1,等于1,等于0;
01
10
11
12
比如 12, 先计算 个位数,1出现2次;再计算 百位数,1出现3次,最后相加,2 + 3 = 5;

形象的举例理解: 类比一下密码箱上的密码锁,cur 指向某一位密码,表示把这位密码固定不动;
cur指向的那位密码左边的数表示高位high,右边表示low;
cur指向的密码也就是位元素分为等于0,等于1,大于1三种情况举例;

 *举个例子:把百位固定  (大于1)
 *3101 5 92  我们把百位设为1 5前面可以取0-3101,5后面可以取0-99
 *一共有(3101+1)*100(百位)种组合使百位为1
 *
 *再举个例子:把千位固定  (等于1)
 *310 1 592  我们把千位设为1,这里可以分两种情况:
 *  1前面可以取0-309 1后面可以取0-99
 *  1前面取310,1后面可以取0-592
 *一共有(301+1)*1000(千位)+(592+1)种组合使千位为1

 *再举最后一个例子:把万位固定 (等于0)
 *31 0 1592,把万位设为1,0前面可以取0-30,0后面可以取0-99
 *一共有(31)*10000(万位)种组合使万位为1

在把一个数分为high、cur、low的情况下,用base表示cur所在位数是百位、千位、万位…发现如下规律:
cur 等于 0 :high * base
cur 等于 1 : high * base + low + 1
cur 大于 1 : (high + 1) * base

循环计算要求的数的所有位元素的和,最后就是1出现的次数,注意的是,base要是long,否则会超出范围;

代码

class Solution {
public:
    int countDigitOne(int n) {
        long base = 1;// 固定位数,这里要用long 否则会超
        int ans = 0;//1的次数
        while (base <= n) {
            int low = n % base;//低位
            int high = n / base;
            int cur = high % 10;//当前位
            high /= 10;//高位
            if (cur == 0) ans += high * base;
            else if (cur == 1) ans += high * base + 1 + low; 
            else ans += (high + 1) * base;                 
            base *= 10;
        }
        return ans;
    }
};

你可能感兴趣的:(数据结构与算法,算法,leetcode,数据结构)