【编程马拉松】【004-包含一】

来源:互联网 发布:asp.net vb 教程 编辑:程序博客网 时间:2024/05/16 07:52

【编程马拉松算法目录>>>】


【004-包含一】【工程下载>>>】


1 题目描述


  NowCoder总是力争上游,凡事都要拿第一,所以他对“1”这个数情有独钟。爱屋及乌,他也很喜欢包含1的数,例如10、11、12……。你能帮他统计一下有多少个包含1的正整数吗?

1.1 输入描述:


  输入有多组数据,每组数据包含一个正整数n,(1≤n≤2147483647)。

1.2 输出描述:


  对应每组输入,输出从1到n(包含1和n)之间包含数字1的正整数的个数。

1.3 输入例子:


191020

1.4 输出例子:


11211

2 解题思路


  假设有数字X(n)=xnxn1x2x1x0xi上的权重是10i
  先考虑09n9n1929190,中出现1的数字个数,假设它是P(n),它由三部分组成:
  - 09n1929190,含有1的数字数目是P(n1)
  - 1n0n19291901n9n1929190,含有1的数字数目是10n1
  - 1<ji<xiji0i1020100 ji9i1929190中含有1的数字数目是P(n1)ji可以取8个数字。
  所以P(n1)=P(n1)+10n1+8P(n1)=9P(n1)+10n1,又n=0时,P(n)=1,综上有:

P(n)={19P(n1)+10n1n=0n>0

  再考虑X(n),从右到左处理X(n)上的每一位,假设当前处理第i位。则要分三种情况:
  第一种:xi=0,则xixi1x2x1x0xi1x2x1x0含有1的数字个数相同,则F(i)=F(i1)
  第二种:xi=1,则xixi1x2x1x0包含1的由两部分组成:
    - 09i1929190中含有1的数字数,为P(i1)
    - xi0i1020100xixi1x2x1x0中含有1的数字,为X(i1)+1
  则有F(i)=P(i1)+X(i1)+1
  第三种:xi>1,则xixi1x2x1x0包含1的由四部分组成:
    - 0xi1x2x1x0中含有1的数字数,为P(i1)
    - 1i0i10201001i9i1929190中含有1的数字数,为10i1
    - 1<ji<xiji0i1020100ji9i1929190中含有1的数字数,为P(i1)。j_i可以取xi2
    - xi0i1020100 xixi1x2x1x0中含有1的数字,为F(i1)
  则有F(i1)=P(i1)+10i1+(xi2)P(i1)+F(i1)=(xi1)P(i1)+10i1+F(i1)
  综合有:
  当n=0时,X(n)=x0

F(n)=1

  当n>0时,X(n)=xnxn1x2x1x0

F(n)=F(n1)P(n1)+X(n1)+1(xn1)P(n1)+10n1+F(n1)xn=0xn=1xn>1

3 算法实现


import java.util.Scanner;/** * Author: 王俊超 * Time: 2016-05-06 17:52 * CSDN: http://blog.csdn.net/derrantcm * Github: https://github.com/Wang-Jun-Chao * Declaration: All Rights Reserved !!! */public class Main {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);//        Scanner scanner = new Scanner(Main.class.getClassLoader().getResourceAsStream("data.txt"));        while (scanner.hasNext()) {            int n = scanner.nextInt();            System.out.println(countOne(n));        }        scanner.close();    }    /**     * 【方法一】     * 计算[1-n]中包含数字1的数字个数     *     * @param n 最在范围     * @return 包含数字1的数字个数     */    private static int countOne(int n) {        int countedN = 0;        int result = 0;        // 从右向左分析n的每一位;for循环中:i 表示分析到了哪一位,i=1表示个位,i=10表示十位,以此类推;        // onesPerI 表示从0到i-1含有1的数的个数,0,1,19 ...;        // cur 是目前分析的那一位的数值;        // 举个例子: f(m,n) 表示从m到n,含有1的数字的个数。        // f(1,500) = f(1, 99)+f(100, 199)+f(200, 299)+(300, 399)+f(400, 499)        // f(1, 99) = f(200, 299) = f(300, 399) = f(400, 499)        // f(100, 199) = 100        for (int i = 1, onesPerI = 0, cur; n != 0; onesPerI = onesPerI * 9 + i, i *= 10, n /= 10) {            // 当前数位的数值            cur = n % 10;            if (cur == 0) {                continue;            } else if (cur == 1) {                // onesPerI表示[1, i-1]含有1的个数,countedN表示比                result = onesPerI + countedN + 1;            } else {                result += (cur - 1) * onesPerI + i;            }            // 表示比第i位以及比第i位低的各位的数值,比如abcdef,现在处理万位,那么countN就是bcdef            countedN += cur * i;        }        return result;    }}

4 测试结果


这里写图片描述

5 其它信息


因为markddow不好编辑,因此将文档的图片上传以供阅读。Pdf和Word文档可以在Github上进行【下载>>>】。

这里写图片描述
这里写图片描述

2 0
原创粉丝点击