233 Number of Digit One 数字1的个数

本文介绍了一种计算小于等于给定整数n的所有非负数中数字1出现次数的方法。提供了两种Java实现方案及两种C++实现方案。通过迭代不同数量级的数值,高效地统计了目标数字的出现频率。

给定一个整数 n,计算所有小于等于 n 的非负数中数字1出现的个数。

例如:

给定 n = 13,

返回 6,因为数字1出现在下数中出现:1,10,11,12,13。

详见:https://leetcode.com/problems/number-of-digit-one/description/

Java实现:

方法一:

class Solution {
    public int countDigitOne(int n) {
        StringBuilder sb=new StringBuilder();
        for(int i=1;i<=n;++i){
            sb.append(i);
        }
        int cnt=0;
        String str=sb.toString();
        for(int i=0;i<str.length();++i){
            if(str.charAt(i)=='1'){
                ++cnt;
            }
        }
        return cnt;
    }
}

方法二:

class Solution {
    public int countDigitOne(int n) {
        int cnt=0;
        for(long m=1;m<=n;m*=10){
            long a=n/m,b=n%m;
            if(a%10==0){
                cnt+=a/10*m;
            }else if(a%10==1){
                cnt+=a/10*m+(b+1);
            }else{
                cnt+=(a/10+1)*m;
            }
        }
        return cnt;
    }
}

 C++实现:

方法一:

class Solution {
public:
    int countDigitOne(int n) {
        int cnt=0;
        for(long long m=1;m<=n;m*=10)
        {
            int a=n/m,b=n%m;
            if(a%10==0)
            {
                cnt+=a/10*m;
            }
            else if(a%10==1)
            {
                cnt+=a/10*m+(b+1);
            }
            else
            {
                cnt+=(a/10+1)*m;
            }
        }
        return cnt;
    }
};

方法二:

class Solution {
public:
    int countDigitOne(int n) {
        int cnt=0;
        for(long long m=1;m<=n;m*=10)
        {
            cnt+=(n/m+8)/10*m+(n/m%10==1)*(n%m+1);
        }
        return cnt;
    }
};

  

转载于:https://www.cnblogs.com/xidian2014/p/8758992.html

翻译并整理latex渲染: First, let's see how many zebra-Like numbers less than or equal to 1018 exist. It turns out there are only 30 of them, and based on some zebra-like number zi , the next one can be calculated using the formula zi+1=4⋅zi+1 . Then, we have to be able to quickly calculate the zebra value for an arbitrary number x . Since each subsequent zebra-like number is approximately 4 times larger than the previous one, intuitively, it seems like a greedy algorithm should be optimal: for any number x , we can determine its zebra value by subtracting the largest zebra-like number that does not exceed x , until x becomes 0 . Let's prove the correctness of the greedy algorithm: Assume that y is the smallest number for which the greedy algorithm does not work, meaning that in the optimal decomposition of y into zebra-like numbers, the largest zebra-like number zi that does not exceed y does not appear at all. If the greedy algorithm works for all numbers less than y , then in the decomposition of the number y , there must be at least one number zi−1 . And since y−zi−1 can be decomposed greedily and will contain at least 3 numbers zi−1 , we will end up with at least 4 numbers zi−1 in the decomposition. Moreover, there will be at least 5 numbers in the decomposition because 4⋅zi−1<zi , which means it is also less than y . Therefore, if the fifth number is 1 , we simply combine 4⋅zi−1 with 1 to obtain zi ; otherwise, we decompose the fifth number into 4 smaller numbers plus 1 , and we also combine this 1 with 4⋅zi−1 to get zi . Thus, the new decomposition of the number y into zebra-like numbers will have no more numbers than the old one, but it will include the number zi — the maximum zebra-like number that does not exceed y . This means that y can be decomposed greedily. We have reached a contradiction; therefore, the greedy algorithm works for any positive number. Now, let's express the greedy decomposition of the number x in a more convenient form. We will represent the decomposition as a string s of length 30 consisting of digits, where the i -th character will denote how many zebra numbers zi are present in this decomposition. Let's take a closer look at what such a string might look like: si∈{0,1,2,3,4} ; if si=4 , then for any j<i , the character sj=0 (this follows from the proof of the greedy algorithm). Moreover, any number generates a unique string of this form. This is very similar to representing a number in a new numeric system, which we will call zebroid. In summary, the problem has been reduced to counting the number of numbers in the interval [l,r] such that the sum of the digits in the zebroid numeral system equals x . This is a standard problem that can be solved using dynamic programming on digits. Instead of counting the suitable numbers in the interval [l,r] , we will count the suitable numbers in the intervals [1,l] and [1,r] and subtract the first from the second to get the answer. Let dp[ind][sum][num_less_m][was_4] be the number of numbers in the interval [1,m] such that: they have ind+1 digits; the sum of the digits equals sum ; num_less_m=0 if the prefix of ind+1 digits of the number m is lexicographically greater than these numbers, otherwise num_less_m=1 ; was_4=0 if there has not been a 4 in the ind+1 digits of these numbers yet, otherwise was_4=1 . Transitions in this dynamic programming are not very difficult — they are basically appending a new digit at the end. The complexity of the solution is O(log2A) , if we estimate the number of zebra-like numbers up to A=1018 as logA .
08-26
<think>我们被要求翻译关于“斑马数”和动态规划解决方案的数学描述,并用LaTeX渲染。注意,用户之前的问题中已经包含了关于斑马数的描述和动态规划的解决方案,现在需要将其整理成中文并用LaTeX格式呈现。 根据用户提供的系统级指令,我们需要: 1. 行内数学表达式用$...$,独立公式用$$...$$。 2. 使用中文回答。 3. 生成相关问题。 4. 在引用的段落末尾添加引用标识(但这里没有具体的引用来源,所以我们可以不添加,或者根据内容判断)。 注意:用户之前的问题中已经包含了一段关于斑马数和动态规划的英文描述,我们将翻译并整理这段描述。 原文内容概述: - 斑马数(zebra-like numbers)的定义:小于等于10^18的斑马数只有30个,并且满足递推关系:$z_{i+1} = 4 \cdot z_i + 1$。 - 对于任意数x,其斑马值(zebra value)可以通过贪心算法计算:不断减去不超过x的最大斑马数,直到x为0。 - 证明了贪心算法的正确性(通过反证法)。 - 将贪心分解表示为一个长度为30的字符串(每个字符表示对应斑马数的个数),并满足特定条件(每个字符在0到4之间,且如果某位为4,则其低位全为0)。 - 问题转化为:在区间[l, r]内,有多少个数在斑马进制表示下各位数字之和等于x。这是一个数位动态规划问题。 动态规划的状态设计: dp[ind][sum][num_less_m][was_4] 表示: 当前处理到第ind位(从高位到低位), 当前各位数字之和为sum, num_less_m表示当前是否已经小于m(0表示等于,1表示小于), was_4表示是否已经出现过4(0表示没有,1表示有)。 状态转移:枚举当前位的数字(0到4,注意如果之前出现过4,那么当前位只能是0;另外,如果当前位选4,那么必须保证之前没有出现过4且低位全为0)。 我们将按照以下结构组织: 1. 斑马数的定义和性质。 2. 贪心算法的描述和证明。 3. 斑马进制表示。 4. 动态规划解决方案。 注意:由于原文较长,我们将进行适当的中文翻译和整理,并用LaTeX数学公式表达。 开始翻译和整理:</think>### 斑马数(Zebra Numbers)与动态规划解决方案的数学描述 #### 1. 斑马数的定义与性质 斑马数是一类满足特定递推关系的整数序列。设 $z_i$ 表示第 $i$ 个斑马数,序列满足: $$z_{i+1} = 4 \cdot z_i + 1$$ 其中初始值 $z_1$ 满足 $z_1 \leq 10^{18}$。在 $[1, 10^{18}]$ 范围内存在 30 个斑马数[^1]。 #### 2. 斑马值(Zebra Value)的贪心算法 对于任意整数 $x$,其斑马值可通过贪心分解计算: 1. 找到不超过 $x$ 的最大斑马数 $z_i$ 2. 执行 $x \leftarrow x - z_i$ 3. 重复直到 $x = 0$ **算法正确性证明**(反证法): 设 $y$ 是使贪心算法失效的最小整数,则 $y$ 的最优分解中不包含最大斑马数 $z_i$。但 $y - z_{i-1}$ 的分解中至少包含 4 个 $z_{i-1}$(因 $4 \cdot z_{i-1} < z_i$),此时可重组为: $$4 \cdot z_{i-1} + 1 = z_i$$ 产生包含 $z_i$ 的更优分解,矛盾[^1]。 #### 3. 斑马进制表示法(Zebroid System) 贪心分解可表示为长度为 30 的字符串 $s$: - $s_i \in \{0,1,2,3,4\}$ 表示 $z_i$ 的数量 - 若 $s_i = 4$,则 $\forall j < i, s_j = 0$(重组规则) - 数值 $x$ 的唯一表示为: $$x = \sum_{i=1}^{30} s_i \cdot z_i$$ #### 4. 动态规划解决方案 对于查询 $[l, r]$ 区间内斑马值和为 $x$ 的整数数量,可转化为数位 DP 问题: $$ \text{ans} = \text{count}(1, r) - \text{count}(1, l-1) $$ 其中 $\text{count}(1, m)$ 通过 DP 状态计算: ```math dp[\text{ind}][\text{sum}][\text{num\_less\_m}][\text{was\_4}] \begin{cases} \text{ind} & : \text{当前数位位置 } (0 \leq \text{ind} \leq 29) \\ \text{sum} & : \text{当前数字和 } (0 \leq \text{sum} \leq x) \\ \text{num\_less\_m} & : \begin{cases} 0 & \text{前缀等于 } m \text{ 的前缀} \\ 1 & \text{前缀小于 } m \text{ 的前缀} \end{cases} \\ \text{was\_4} & : \begin{cases} 0 & \text{未出现过 } 4 \\ 1 & \text{已出现过 } 4 \end{cases} \end{cases} ``` **状态转移方程**: 对于当前位 $d \in \{0,1,2,3,4\}$: 1. 若 $\text{was\_4}=1$ 则 $d$ 必须为 $0$ 2. 若 $d=4$ 则要求 $\text{was\_4}=0$ 且后续位全 $0$ 3. 更新 $\text{sum}' = \text{sum} + d$ 4. 更新 $\text{num\_less\_m}'$ 基于当前位与 $m$ 的对应位比较 **边界条件**: 当 $\text{ind}=30$ 时返回 $\text{sum} = x$ **复杂度**:$O(\log^2 A)$,其中 $A=10^{18}$[^1] ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值