zoukankan      html  css  js  c++  java
  • 《剑指offer》第四十三题(从1到n整数中1出现的次数)

    // 面试题43:从1到n整数中1出现的次数
    // 题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。例如
    // 输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。
    
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    
    // ====================方法一====================
    //逐个判断,时间复杂度为O(nlogn),不好
    int NumberOf1(unsigned int n);
    
    int NumberOf1Between1AndN_Solution1(unsigned int n)
    {
        int number = 0;
    
        for (unsigned int i = 1; i <= n; ++i)
            number += NumberOf1(i);
    
        return number;
    }
    
    int NumberOf1(unsigned int n)
    {
        int number = 0;
        while (n)
        {
            if (n % 10 == 1)
                number++;
    
            n = n / 10;
        }
    
        return number;
    }
    
    // ====================方法二====================
    int NumberOf1(const char* strN);
    int PowerBase10(unsigned int n);
    
    int NumberOf1Between1AndN_Solution2(int n)//把数字换成字符串,方便处理
    {
        if (n <= 0)
            return 0;
    
        char strN[50];
        sprintf(strN, "%d", n);//格式化输出成字符串
    
        return NumberOf1(strN);
    }
    
    int NumberOf1(const char* strN)
    {
        if (!strN || *strN < '0' || *strN > '9' || *strN == '')
            return 0;
    
        int first = *strN - '0';//第一位的最大值
        unsigned int length = static_cast<unsigned int>(strlen(strN));//强制转换符
    
        if (length == 1 && first == 0)//边界特殊情况
            return 0;
    
        if (length == 1 && first > 0)
            return 1;
    
        // 假设strN是"21345"
        //先计算第一种情况,第一位为1的个数
        // numFirstDigit是数字10000-19999的第一个位中1的数目
        int numFirstDigit = 0;
        if (first > 1)
            numFirstDigit = PowerBase10(length - 1);
        else if (first == 1)
            numFirstDigit = atoi(strN + 1) + 1;//若在1xx的情况,个数不到PowerBase10(length - 1),atoi是字符串转整数
    
        //第二种情况,非第一位为1的个数
        // numOtherDigits是01346-21345除了第一位之外的数位中1的数目
        int numOtherDigits = first * (length - 1) * PowerBase10(length - 2);//第一位可能性有first个,第二项表示选取除了第一位的任一位为1,剩下的有10种可能
        // numRecursive是1-1345中1的数目,使用迭代处理
        int numRecursive = NumberOf1(strN + 1);
    
        return numFirstDigit + numOtherDigits + numRecursive;
    }
    
    int PowerBase10(unsigned int n)//10的n次方
    {
        int result = 1;
        for (unsigned int i = 0; i < n; ++i)
            result *= 10;
    
        return result;
    }
    
    // ====================测试代码====================
    void Test(const char* testName, int n, int expected)
    {
        if (testName != nullptr)
            printf("%s begins: 
    ", testName);
    
        if (NumberOf1Between1AndN_Solution1(n) == expected)
            printf("Solution1 passed.
    ");
        else
            printf("Solution1 failed.
    ");
    
        if (NumberOf1Between1AndN_Solution2(n) == expected)
            printf("Solution2 passed.
    ");
        else
            printf("Solution2 failed.
    ");
    
        printf("
    ");
    }
    
    void Test()
    {
        Test("Test1", 1, 1);
        Test("Test2", 5, 1);
        Test("Test3", 10, 2);
        Test("Test4", 55, 16);
        Test("Test5", 99, 20);
        Test("Test6", 10000, 4001);
        Test("Test7", 21345, 18821);
        Test("Test8", 0, 0);
    }
    
    int main(int argc, char* argv[])
    {
        Test();
        system("pause");
        return 0;
    }
  • 相关阅读:
    题解 CF171G 【Mysterious numbers
    题解 P1157 【组合的输出】
    题解 P3955 【图书管理员】
    题解 P2036 【Perket】
    题解 CF837A 【Text Volume】
    题解 CF791A 【Bear and Big Brother】
    题解 CF747A 【Display Size】
    题解 P1332 【血色先锋队】
    题解 P2660 【zzc 种田】
    题解 P4470 【[BJWC2018]售票】
  • 原文地址:https://www.cnblogs.com/CJT-blog/p/10522116.html
Copyright © 2011-2022 走看看