剑指offer 面试题32 从1到n整数中1出现的次数

  题目链接: 剑指offer啊

  题目描述: 输入N, 求从1到n整数中1出现的次数

  解题思路: 一开始的想法只能是暴力, 但是自己太蠢了啊, 看了看剑指offer上的做法就是巧妙的利用了递归......一个数字可以拆成两部分: 拿21345举例来说, 可以拆成两部分:

        1 ~ 1345,   01346 ~ 21345, 我们为什么要拆成这两个串呢, 因为第二部分我们可以准确的知道1 出现的次数, (拿第一位的值进行分类讨论), 第一部分我们可以递归, 这样我们就将问题划分成更小的子问题了, 所以问题可以求解, 注意边界情况子串长度为1 的时候, 和到字符串结尾 '\0' 的时候

  代码: 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;

const int maxn = 1e2;

int PowerBase10(int a, int n) {
    int res = 1;
    for( int i = 0; i < n; i++ ) {
        res *= 10;
    }
    return res;
}

int NumberOf1(const char *strN) {
    if( !strN || *strN < '0' || *strN > '9' || *strN == '\0' ) return 0;
    int first = *strN-'0';
    int len = (int)strlen(strN);
    if( len == 1 && first == 0 ) return 0;
    else if( len == 1 && first == 1 ) return 1;
    int NumberFirstDigit = 0;
    if( first >= 2 ) {
        NumberFirstDigit += PowerBase10(10, len-1);
    }
    else {
        NumberFirstDigit += atoi(strN+1) + 1;
    }
    int NumberOtherDigit = first*(len-1)*PowerBase10(10, len-2);
    int NumberRecursive = NumberOf1(strN+1);
    return NumberFirstDigit + NumberOtherDigit + NumberRecursive;
}

int NumberOf1Between1AndN( int n ) {
    char str[maxn];
    if( n <= 0 ) return 0;
    sprintf( str, "%d", n );
    return NumberOf1(str);
}

int main() {
    int n;
    scanf( "%d", &n );
    printf( "%d\n", NumberOf1Between1AndN(n) );
    return 0;
}
View Code

  思考: 通过这道题更加深刻地理解了递归, 我认为递归的用途是, 至少在本道题来讲, 如果说一个问题, 可以化成子问题 + ..... + 子问题 + 常数, 那么这道题就可以用递归的思想去解决

明天要去问面试结果了, 感觉自己的希望很小很小, 但是还是要问问, 哎, 今天晚上又该闹心了, 玻璃心, stupid

posted on 2017-09-12 20:33  FriskyPuppy  阅读(122)  评论(0编辑  收藏  举报

导航