题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
简单的方法:对10取模求得每一位的数,时间复杂度O(nlogn)
class Solution { public: int NumberOf1Between1AndN_Solution(int n) { if(n <= 0) return 0; int sum = 0; while(n){ sum += weishu(n); n--; } return sum; } int weishu(int n){ int sum = 0; while(n){ if(n % 10 == 1) sum++; n /= 10; } return sum; } };
或者将数字转为字符串,对每一位进行判断
剑指offer的思路:利用数学规律
这里要注意的是类似100这种情况还有首位为1的情况
public class Solution { public int NumberOf1Between1AndN_Solution(int n) { if(n <= 0) return 0; String number = n+""; return NumberOf1("1",number,number.length()); } public int NumberOf1(String startNum,String endNum,int endNumWei){ if(endNumWei == 1) return 1; if(startNum == "1"){ String subNum = endNum.substring(1); while(subNum.length()>0&&subNum.charAt(0) == '0'){ subNum = subNum.substring(1); } if(subNum.length()==0) { int sumOne = 0; for(int i=0;i<endNum.length();i++){ if(endNum.charAt(i)=='1') sumOne++; } endNum = (strToint(endNum)-1)+""; return sumOne + NumberOf1("1",endNum,endNum.length()); } else return NumberOf1(subNum,endNum,endNumWei) + NumberOf1("1",subNum,subNum.length()); }else{ if(endNum.charAt(0) != '1') return (int)(Math.pow(10.0,endNumWei-1) + ((int)endNum.charAt(0)-(int)('0')) * (endNumWei-1) * Math.pow(10.0,endNumWei-2)); else{ return strToint(endNum.substring(1))+1 + (endNumWei-1) * (int)Math.pow(10.0,endNumWei-2); } } } public int strToint(String str){ int sum = 0; for(int i=0;i<str.length();i++) sum = sum * 10 + (int)(str.charAt(i)-'0'); return sum; } }
还是没有书上的算法简洁:
class Solution { public: int NumberOf1Between1AndN_Solution(int n) { if(n<=0) return 0; char strN[50]; sprintf(strN, "%d", n); return NumberOf1(strN); } int NumberOf1(char* strN){ if(*strN <'0'||*strN>'9') return 0; unsigned int len = static_cast<unsigned int>(strlen(strN)); int first = *strN - '0'; if(len == 1 && first == 0) return 0; if(len == 1 && first > 0) return 1; //计算首位为1的个数 int numFirstDigit = 0; if(first == 1) numFirstDigit = atoi(strN+1)+1; else if(first > 1) numFirstDigit = (int)pow(10.0, len-1); int otherDigits = first *(len-1)*(int)pow(10.0, len-2); int recurisiveDigits = NumberOf1(strN+1); return numFirstDigit + otherDigits + recurisiveDigits; } };