从1到n的正数中1出现的次数

本文介绍了一种使用动态规划方法计算从1到任意整数n的十进制表示中1出现的次数的方法。通过遍历每个数字并使用数组存储各个位上的数字,实现对1出现次数的精确计数。

题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。

例如输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。

利用动态规划的思想,每次往前进行增加。代码如下:

#include<iostream>
using namespace std;


int Countdatanum(int n)
{
	int Data[10] = {0};
	int i = 0;
	int k = 10;
	int length;
	int temp;
	int sum = 0;
	int value = n;
	while(value != 0)
	{
		Data[i] = value % k;
		value /= 10;
		i++;
	}
	length = i;

	if(Data[0] > 0)
		Data[0] = 1;
	int pre = 1;
	sum += Data[0];
	for(i = 1; i < length; i++)
	{
		if(Data[i] > 1)
		{
			sum += pre * Data[i] + k;
		}
		else if(Data[i] == 1)
		{
			sum += pre * Data[i]; 
			sum += n % k + 1;
		}
		else
			Data[i] = 0;

		pre = pre * 10 + k;
		k *= 10;
	}
	
	return sum;
}

int NumberOf1(unsigned int n)
{
      int number = 0;
      while(n)
      {
            if(n % 10 == 1)
                  number ++;

            n = n / 10;
      }

      return number;
}

int NumberOf1BeforeBetween1AndN_Solution1(unsigned int n)
{
      int number = 0;

      // Find the number of 1 in each integer between 1 and n
      for(unsigned int i = 1; i <= n; ++ i)
            number += NumberOf1(i);

      return number;
}



int main()
{
	cout<<Countdatanum(203)<<endl;
	cout<<NumberOf1BeforeBetween1AndN_Solution1(203)<<endl;
	return 0;
}


<think> 我们之前讨论了温度转换,现在用户的新问题是:用C语言计算从1到n的所有偶数和。 我们需要改变思路,现在关注的是整数序列中偶数的求和问题。 思路: 1. 输入一个正整数n。 2. 计算从1到n之间所有偶数的和。 方法: 方法1:循环遍历1到n,判断每个数是否为偶数(即对2取模为0),如果是则累加。 方法2:利用数学公式。注意1到n中的偶数可以表示为:2,4,6,...,2k,其中2k<=n。 那么偶数的个数k = n//2(整数除法),然后使用等差数列求和公式:和 = (首项+末项)*项数/2。 首项为2,末项为2k,项数为k,所以和 = (2+2k)*k/2 = k*(k+1) = (n//2)*(n//2+1) [但注意这里n//2是整数除法] 两种方法比较: 循环方法适用于初学者,容易理解。 公式方法效率高,时间复杂度为O(1)。 我们将提供两种方法的代码,并比较它们。 代码实现: 方法1:循环 ```c #include <stdio.h> int main() { int n, sum = 0; printf("请输入一个正整数n: "); scanf("%d", &n); // 循环从1到n for (int i = 1; i <= n; i++) { // 判断是否为偶数 if (i % 2 == 0) { sum += i; } } printf("1到%d之间所有偶数的和为: %d\n", n, sum); return 0; } ``` 方法2:公式法 ```c #include <stdio.h> int main() { int n; printf("请输入一个正整数n: "); scanf("%d", &n); int k = n / 2; // 1到n中偶数的个数 int sum = k * (k + 1); // 等差数列求和:2+4+...+2k = 2*(1+2+...+k)=2*(k*(k+1)/2)=k*(k+1) printf("1到%d之间所有偶数的和为: %d\n", n, sum); return 0; } ``` 注意:公式法利用了偶数的和等于2*(1+2+...+k) = 2*(k(k+1)/2) = k(k+1),其中k=n/2(整数除法)。 两种方法的区别: 1. 循环法:直观,但当n很大时,循环次数较多(时间复杂度O(n))。 2. 公式法:直接计算,效率高(时间复杂度O(1)),但需要理解背后的数学原理。 举例验证: 例如n=10,偶数有2,4,6,8,10,和为30。 公式法中,k=10/2=5,sum=5*6=30,正确。 我们推荐使用公式法,尤其是当n非常大时,公式法的优势明显。 扩展:如果n是负数?题目要求是1到n,一般情况下n为正整数。但为了健壮性,可以检查输入。 如果需要处理负数,那么我们需要定义清楚:从1到n,如果n为负数,则应该是从n到1?但通常题目要求n为正整数。所以我们的代码假设用户输入的是正整数。 为了健壮性,我们可以添加输入检查: ```c if (n < 1) { printf("n必须为正整数!\n"); return 1; // 非正常退出 } ``` 在公式法中,由于整数除法是向下取整,对于正数n,n/2就是k(偶数个数),公式仍然成立。 如果n为0呢?那么k=0,和为0,也是正确的。 因此,公式法对n>=0都适用(题目要求从1到n,n至少为1,但公式法在n=0时也能得到0,所以我们可以允许n>=0)。 下面我们提供带输入检查的公式法代码: ```c #include <stdio.h> int main() { int n; printf("请输入一个非负整数n: "); scanf("%d", &n); if (n < 0) { printf("输入错误!n不能为负数。\n"); return 1; } int k = n / 2; int sum = k * (k + 1); printf("1到%d之间所有偶数的和为: %d\n", n, sum); return 0; } ``` 注意:题目要求是从1到n,所以当n为0时,1到0之间没有偶数,所以和为0。但我们通常的n至少为1。 因此,我们按照用户的需求,如果输入负数则报错,非负整数则计算。 总结: 对于计算1到n的所有偶数和,我们推荐公式法,因为它效率高且代码简洁。 相关问题: 1. 如何计算1到n之间奇数的和? 2. 公式法为什么比循环法更高效? 3. 如果n非常大(例如接近int类型的最大值),公式法会不会溢出?如何处理? 4. 用循环法计算偶数和时,如何优化循环次数? 5. 如何用递归实现1到n的偶数和? 注意:在生成相关问题后,我们按照要求输出。 </think> ### C语言计算1到n的所有偶数和 #### 方法1:循环遍历法(直观易懂) ```c #include <stdio.h> int main() { int n, sum = 0; // 输入上限值 printf("请输入整数n: "); scanf("%d", &n); // 遍历1到n,累加偶数 for (int i = 1; i <= n; i++) { if (i % 2 == 0) { // 判断是否为偶数 sum += i; } } printf("1到%d的所有偶数和为: %d\n", n, sum); return 0; } ``` **原理**: 1. 使用`for`循环遍历1到n的所有整数 2. 通过`i % 2 == 0`判断是否为偶数 3. 符合条件的偶数累加到`sum`变量 #### 方法2:等差数列公式法(高效优化) ```c #include <stdio.h> int main() { int n; printf("请输入整数n: "); scanf("%d", &n); // 计算偶数的数量 int count = n / 2; // 使用等差数列求和公式:S = n/2 * (首项 + 末项) int sum = count * (2 + 2 * count) / 2; printf("1到%d的所有偶数和为: %d\n", n, sum); return 0; } ``` **数学原理**: 1. 1到n的偶数序列构成等差数列: $$ \text{首项} a_1 = 2, \quad \text{公差} d = 2 $$ 2. 项数公式: $$ \text{项数} k = \left\lfloor \frac{n}{2} \right\rfloor $$ 3. 等差数列求和公式: $$ S = \frac{k}{2} \times (a_1 + a_k) = \frac{k}{2} \times (2 + 2k) = k(k + 1) $$ #### 两种方法对比 | 特性 | 循环遍历法 | 公式法 | |------|------------|--------| | 时间复杂度 | $O(n)$ | $O(1)$ | | 空间复杂度 | $O(1)$ | $O(1)$ | | 适用场景 | n较小时 | n非常大时 | | 优点 | 逻辑直观 | 计算高效 | | 缺点 | n大时效率低 | 需要数学理解 | **执行示例**: ``` 请输入整数n: 10 110的所有偶数和为: 30 (2+4+6+8+10) ``` #### 优化技巧 1. **步长优化**:直接遍历偶数,减少判断次数 ```c for (int i = 2; i <= n; i += 2) { sum += i; } ``` 2. **边界处理**:添加输入验证 ```c if (n < 1) { printf("n必须大于0!"); return 1; } ``` #### 公式法推导细节 当$n$为偶数时: $$ S = 2 + 4 + \cdots + n = 2(1 + 2 + \cdots + \frac{n}{2}) = 2 \times \frac{\frac{n}{2}(\frac{n}{2} + 1)}{2} = \frac{n}{2} \times (\frac{n}{2} + 1) $$ 当$n$为奇数时: $$ S = 2 + 4 + \cdots + (n-1) = \frac{n-1}{2} \times (\frac{n-1}{2} + 1) $$ 统一公式: $$ S = \left\lfloor \frac{n}{2} \right\rfloor \times \left( \left\lfloor \frac{n}{2} \right\rfloor + 1 \right) $$
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值