剑指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; }
思考: 通过这道题更加深刻地理解了递归, 我认为递归的用途是, 至少在本道题来讲, 如果说一个问题, 可以化成子问题 + ..... + 子问题 + 常数, 那么这道题就可以用递归的思想去解决
明天要去问面试结果了, 感觉自己的希望很小很小, 但是还是要问问, 哎, 今天晚上又该闹心了, 玻璃心, stupid
posted on 2017-09-12 20:33 FriskyPuppy 阅读(122) 评论(0) 编辑 收藏 举报