计算1到N中各个数字出现的次数 --数位DP
题意:给定一个数n,问从1到n中,0~9这10个数字分别出现了多少次。比如366这个数,3出现了1次,6出现了2次。
题解:《剑指offer》P174;《编程之美》P132 都给出了统计数字1的O(log(n))的解法。把他们进行改进就得到了这个问题的答案。
下面这个代码是我改的剑指offer的,也有类似编程之美的:传送门。
//《剑指offer》P174 #include <bits/stdc++.h> using namespace std; int pow1(int n,int len)//注意算的时候不要用math里的pow 会产生误差 { int ans=1; while(len--) ans*=n; return ans; } int cal(char *c,int i) { int len=strlen(c); int f=*c-'0',g=*(c+1)-'0'; if(len==1&&(f<i||i==0)) return 0; if(len==1&&f>=i) return 1; int a1=0,a2=0,a3=0; if(i==0||f<i) a1=0; else if(f>i) a1=pow1(10,len-1); else if(f==i) a1=atoi(c+1)+1; a2=f*(len-1)*pow1(10,len-2); if(g==0&&i==0) a2=a2-pow1(10,len-2)+atoi(c+2)+1; a3=cal(c+1,i); return a1+a2+a3; } int solve(int n,int i) { char c[55]; sprintf(c,"%d",n); return cal(c,i); } int main() { int n; while(scanf("%d",&n)!=EOF){ for(int i=0;i<10;i++) printf("%d%c",solve(n,i),i==9?'\n':' '); } return 0; }
官方标程:
#include <bits/stdc++.h> using namespace std; vector<int> solve(int n) { vector<int> res(10, 0); if(!n) return res; if(n % 10 < 9) { res = solve(n - 1); while(n) { res[n % 10]++; n /= 10; } return res; } res = solve(n / 10); for(int i = 0; i < 10; i++) res[i] = res[i] * 10 + n / 10 + (i > 0); return res; } int main() { int n; cin >> n; vector<int> ans = solve(n); for(int i = 0; i < ans.size(); i++) { i == 0 ? cout << ans[i] : cout << " " << ans[i]; } return 0; }