何海涛博客中的一个思路,比较清晰。
package static_;
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(get(14));
}
// 将一个数字abcde分成bcde和abcde
public static int get(int n) {
String s = String.valueOf(n);
String sub = s.substring(1, s.length());
int res = 0;
// bcde+1到abcde的首位
int first = Integer.parseInt(s.charAt(0) + "");
if (first == 1) {
if (!sub.equals("")) {
res += Integer.parseInt(sub) + 1;
}
} else {
res += power10(s.length() - 1);
}
if (!sub.equals("")) {
// bcde+1到abcde除去首位之后,剩余的位置
res += first * (s.length() - 1) * power10(s.length() - 2);
// 1到bcde的
res += get(Integer.parseInt(sub));
}
return res;
}
public static int power10(int n) {
int r = 1;
for (int i = 0; i < n; i++) {
r *= 10;
}
return r;
}
}
思路是将到n的数字分成两部分,比如说数字是abcde,那么把数字分成1~bcde和bcde+1~abcde,这样问题就变成了分别计算1~bcde和bcde+1~abcde两部分,这两个数字中1出现的次数了。
针对1~bcde,算是一个子问题,可以递归求解。
对于bcde+1~abcde,考察:
1、第一位如果不是1,那么,第一位可能出现1 的次数是后面各个位置的全排列。供是Power(s.length()-1)
2、第一位如果是1,那么就是后面bcde+1个
3、第一位考察完毕之后,考察第一位之后的位置。之后的位置,每一位都可能是从0到9的。所以,后面的情况是c(s.length()-1,1)*Power(s.length()-2)【从几个位置中选出1个位置置1,然后其他位置全排列】。
这样,把上面几步加起来就是最终结果!