zoukankan      html  css  js  c++  java
  • [LeetCode 233] Number of Digit One

    Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.

    Example:

    Input: 13
    Output: 6 
    Explanation: Digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.

    If n is not big, then we can just count each number's digit 1 and add them up. However, if n can be as big as 10^9, this approach takes too long. We need to solve it by first dividing the original problem into the following smaller problems.

    Let's say the given input integer n has K digits. Then all the digit 1 comes from : (a) all numbers that have < K digits; (b) all numbers that have K digits and <= n.

    To compute a, we use this formula: Cnt_P_Digits = P * 10^(P - 1) - Cnt_P - 1_Digits, Cnt_0_Digits = 0. It is easy to see that for a given digit count P, we can try to fix a 1 on one digit position, then count the different numbers with this position fixed. This will be P * 10^(P - 1) in total before we deduct the invalid leading 0 numbers' contributions. If we set the leading digit to 0, the contribution becomes a smaller subproblem with one fewer digit, which is Cnt_P - 1_Digits.

    To compute b, we use the same fix then count strategy with a. Denote all digits of n as d[i] and there are K digits in total. We have the following 3 cases:

    1. current digit d[i] is 0, setting this digit to 1 makes n bigger, we must make the leading part smaller to compensate for this increase. This means the left part can be any number from 10^(i - 1) to d[0, i - 1] - 1. Since the leading part is < d[0, i - 1], the right part can be anything from 000... to 10^(K - 1 - i).

    2. d[i] == 1, first do the same with 1 to count all the contributions with a smaller left part; Then we need to count the remaining contributions from numbers with the same leading left part. In this case, the right part can only go up to d[i, ...... K - 1] from 00, otherwise the numbers will be > n.

    3. d[i] > 1, since fixing this digit to 1 makes n smaller, the left part can be from 10^(i - 1) to d[0, i - 1]. The right part can be anything from 000... to 10^(K - 1 - i).

    The following code implements the above algorithm. The runtime is O(log N * log N). It takes O(log N) time to loop through all digits. For each iteration it takes O(log N) time to compute left and right. A better way shown in the 2nd implementation is to use a sliding window that gives O(1) time to compute left and right. This makes the overall runtime to be O(log N).

    class Solution {
        public int countDigitOne(int n) {
            if(n <= 0) {
                return 0;
            }
            List<Integer> digits = new ArrayList<>();
            while(n > 0) {
                digits.add(n % 10);
                n /= 10;
            }
            Collections.reverse(digits);
            int cnt = 0, prevCnt = 0;
            int[] base = new int[10];
            base[0] = 1;
            for(int i = 1; i < 10; i++) {
                base[i] = base[i - 1] * 10;
            }
            for(int i = 1; i < digits.size(); i++) {
                cnt += (i * base[i - 1] - prevCnt);
                prevCnt = cnt;
            }
            for(int i = 0; i < digits.size(); i++) {
                int left = 0, right = 0;
                for(int j = 0; j < i; j++) {
                    left = left * 10 + digits.get(j);
                }   
                for(int j = i + 1; j < digits.size(); j++) {
                    right = right * 10 + digits.get(j);
                }   
                if(digits.get(i) <= 1) {
                    cnt += Math.max(left - 1 - (i > 0 ? base[i - 1] : 0) + 1, 0) * base[digits.size() - 1 - i];
                    if(digits.get(i) == 1) {
                        cnt += (right + 1);
                    }
                }
                else {
                    cnt += (left - (i > 0 ? base[i - 1] : 0) + 1) * base[digits.size() - 1 - i];
                }
            }
            return cnt;
        }
    }


    class Solution {
        public int countDigitOne(int n) {
            if(n <= 0) {
                return 0;
            }
            List<Integer> digits = new ArrayList<>();
            while(n > 0) {
                digits.add(n % 10);
                n /= 10;
            }
            Collections.reverse(digits);
            int cnt = 0, prevCnt = 0;
            int[] base = new int[10];
            base[0] = 1;
            for(int i = 1; i < 10; i++) {
                base[i] = base[i - 1] * 10;
            }
            for(int i = 1; i < digits.size(); i++) {
                cnt += (i * base[i - 1] - prevCnt);
                prevCnt = cnt;
            }
            int left = 0, right = 0;
            for(int i = 1; i < digits.size(); i++) {
                right = right * 10 + digits.get(i);
            }
            for(int i = 0; i < digits.size(); i++) {  
                left = (i > 0 ? left * 10 + digits.get(i - 1) : 0);
                right = right % base[digits.size() - 1 - i];
                if(digits.get(i) <= 1) {
                    cnt += Math.max(left - 1 - (i > 0 ? base[i - 1] : 0) + 1, 0) * base[digits.size() - 1 - i];
                    if(digits.get(i) == 1) {
                        cnt += (right + 1);
                    }
                }
                else {
                    cnt += (left - (i > 0 ? base[i - 1] : 0) + 1) * base[digits.size() - 1 - i];
                }
            }
            return cnt;
        }
    }
    
    
    









  • 相关阅读:
    【多线程】-实现多线程的三种方法
    在java项目启动时就执行某操作
    PHP上传多个Excel表格里的数据到数据库然后在页面显示
    PHP如何生成word并下载
    PHP把网页表单导出到word
    把PHP网页表单导出到word文档中
    HTTP Keep-Alive的作用
    利用paramiko获取上传下载远程服务器的资源信息
    3.django连接mysql数据库及安装mysqldb驱动报错解决办法
    3.Pycharm和navicate的使用
  • 原文地址:https://www.cnblogs.com/lz87/p/13467960.html
Copyright © 2011-2022 走看看