难度中等28
输入一个整数 n
,求1~n这n个整数的十进制表示中1出现的次数。
例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
示例 1:
输入:n = 12 输出:5
示例 2:
输入:n = 13 输出:6
解题思路:刚开始自己用的普通方法,结果时间超限了。
class Solution {
public static int countOne(int n){
int count = 0;
StringBuilder sb = new StringBuilder();
if(n>9){
int temp = n%10;
n = n/10;
sb.append(temp);
}
sb.append(n);
String s = String.valueOf(sb);
for(int i = 0;i<s.length();i++){
if(s.charAt(i) == '1')
count++;
}
return count;
}
public int countDigitOne(int n) {
int sum = 0;
for(int i = 1;i<=n;i++){
sum+=countOne(i);
}
return sum;
}
}
思路是对的,就是方法太low,遇到比较大的数字就会时间超限。
解法二:
dfs(n)表示数字n有多少个1;
我们可以利用这样的例子进行思考,
假设数字为1234,则high = 1 pow = 1000 low = 234;
其中当高位为1的时候的1的个数 234+1(low+1);
然后就是pow中1的个数为 dfs(pow)
low中1的个数为 dfs(low)
最后结果就是low+1+dfs(pow)+dfs(low)
假设数字是2234 则high = 2,pow = 1000 low = 234
则可以将数字分成 0 - 999,1000-1999,2000-2234,
在0-999范围内,dfs(pow-1)
在1000-1999范围内分为两部分
当高位确定是1的时候:就是1的个数就是pow
抛开高位为1的情况:就是dfs(pow-1)
2000-2234
就是dfs(low)
最后的结果就是
pow+high*dfs(pow-1)+dfs(low)
class Solution {
public int dfs(int n){
if(n<=0)
return 0;
String s = String.valueOf(n);
int high = s.charAt(0) - '0';
int pow = (int)Math.pow(10,s.length()-1);
int low = n-high*pow;
if(high == 1){
return dfs(pow-1)+low+1+dfs(low);
}else{
return pow+high*dfs(pow-1)+dfs(low);
}
}
public int countDigitOne(int n) {
return dfs(n);
}
}