剑指offer 32. 整数中 1 出现的个数 & leetcode 233. 数字 1 的个数

 32. 整数中 1 出现的个数 & 233. 数字 1 的个数

题目描述

求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

思路一:

思路参考:https://leetcode-cn.com/problems/number-of-digit-one/solution/shu-zi-1-de-ge-shu-by-leetcode/

在方法一中,我们手动计算了每个数中 ’1’ 的个数,但这种计算是非常慢。因此,我们需要找到’1’ 在这些数中出现的规律。然后我们就能利用这个规律来形成数学公式解决问题了。

考虑 ’1’ 在 个位,十位,百位,... 出现的情况,我们可以做出以下的分析

 

 

 1 class Solution {
 2     public int countDigitOne(int n) {
 3         int count = 0;
 4         for(long i = 1; i <= n; i *= 10){
 5             long divider = i * 10;
 6             count += (n / divider) * i + Math.min(Math.max(n % divider - i + 1, 0L), i);
 7         }
 8         return count;
 9     }
10 }
leetcode 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
  内存消耗:35.1 MB, 在所有 Java 提交中击败了89.87%的用户

复杂度分析:

时间复杂度:迭代次数是 log10n, 所以时间复杂度为 O(log10n)。
空间复杂度:O(1)。

思路二:

从 1 -  n, 分别统计每个数中1的个数

 1 public class Solution {
 2     public int NumberOf1Between1AndN_Solution(int n) {
 3         // dp[i]表示 从 1 - i中所有数 中 1 的个数
 4         // dp[i] + cnt;    // cnt 表示当前数中1的个数
 5         // 统计每个数中1的个数,右移一位,连续31次右移
 6         
 7         int count = 0;
 8         for(int i = 1; i <= n; i++){
 9             // 统计每个数中1的个数,右移一位,连续31次右移
10             int tmp = i;
11            while(tmp != 0){
12                count += (tmp % 10 == 1) ? 1 : 0;
13                tmp /= 10;
14             }
15         }
16         return count;
17     }
18 }

 

posted @ 2020-03-28 21:59  Lucky小黄人^_^  阅读(158)  评论(0编辑  收藏  举报