31整数中1出现的次数(从1到n整数中1出现的次数)
1 整数中1出现的次数(从1到n整数中1出现的次数) 2 // 3 //求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,
但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。 4 //---常规思想--- 5 //累加1到n的每个整数1出现的次数,每次通过对10求余数判断整数的个位数字是不是1.如果这个数字大于10,除以10之后在判断个位数字是不是1. 6 7 int NumberOf1BetweenAndN_Solution(int n) 8 { 9 int number = 0; 10 for (int i = 1; i <= n; ++i) 11 { 12 number += NumberOf1(i); 13 } 14 return number; 15 } 16 int NumberOf1(int n) 17 { 18 int number = 0; 19 while(n)//如果输入数字n,n有O(logn)位,需要判断每一位是不是1,那么它的时间复杂度是O(n*logn) 20 { 21 if (n % 10 == 1) 22 { 23 number ++; 24 } 25 n = n/10; 26 } 27 return number; 28 } 29 30 //从数字规律着手明显提高时间效率的解法---- 31 //将21345举例 32 //将1-21345分成两段,一段是从1-1345,另一段是1346-21345 33 //先解决1346-21345,查看1出现的次数---分两种情况 34 // --首先分析1出现在最高位的情况,10000-19999,一共出现10000个(并不是所有的5位数,在万位出现的次数是10000个,即出去最高数字之后剩下的数字再加上1) 35 // --再分析1出现在除最高位之外的其他四位数中的情况。例如1346-21345这20000个数字中后4位中1出现的次数是2000次。由于最高位是2,故分成两种情况: 36 // --首先1346-11345和11346-21345. 37 // --每一段剩下的4位数字中,选择一位其中1位是1,其他三位可以再0-9这10个数字中任意选择,根据排列组合原则,出现的次数是2*10*10*10 38 class Solution 39 { 40 public: 41 int NumberOf1BetweenAndN_Solution(int n) 42 { 43 if(n <= 0) 44 { 45 return 0; 46 } 47 //为了编程将数字转化为字符串 48 char strN[50]; 49 sprintf(strN, "%d", n);//将数字n转化成字符串保存再StrN中 50 return NumberOf1(strN); 51 } 52 public: 53 int NumberOf1(const char* strN) 54 { 55 if (strN == NULL || *strN < '0' && *strN > '9' && *strN== '\0') 56 { 57 return 0; 58 } 59 int first = *strN - '0'; 60 unsigned int length = static_cast<unsigned int>(strlen(strN)); 61 if(length == 1 && first == 0) 62 { 63 return 0; 64 } 65 if (length == 1&& first > 0) 66 { 67 return 1; 68 } 69 //其他length 不等于1;且假设strN = "21345" 70 //numFirstDigit 是10000-19999的第一位中的数目 71 int numFirstDigit = 0; 72 if (first > 1)//10000-19999 73 { 74 numFirstDigit = PowerBase10(length-1); 75 } 76 else if(first == 1)//10000-11345 77 { 78 numFirstDigit = atoi(strN+1)+1; 79 } 80 //numOtherDigit是1346-21345除了第一位之外的数位中的数目 81 //1346-11345 和 11346-21345 82 //first表示有两段length-1的 83 //每个length-1的,固定一位为1,然后组合10*10*10 84 int numOtherDigit = first * (length-1) *PowerBase10(length-2); 85 //1-1345中的数目 86 int numRecursive = NumberOf1(int strN+1); 87 return numFirstDigit+numOtherDigit+numRecursive; 88 } 89 int PowerBase10(unsigned int n) 90 { 91 int result = 1; 92 for(int i = 0; i<n; i++) 93 { 94 result *= 10; 95 } 96 return result; 97 } 98 };
在代码的世界尽情的翱翔吧!