每日一题(58) - 从1到n整数中1出现的次数

题目来自剑指Offer

题目:


思路一:暴力法

方法:对1到n中的每一个数,分别判断其中1的个数。

复杂度:O(n*logn)

代码:

#include <iostream>
#include <assert.h>
using namespace std;

int OneNum(int n)
{
	assert(n >= 0);
	int nSum = 0;
	int nCurNum = 1;
	for (int i = 1;i <= n;i++)
	{
		nCurNum = i;
		while (nCurNum)
		{
			if (nCurNum % 10 == 1)
			{
				nSum++;
			}
			nCurNum /= 10;
		}
	}
	return nSum;
}

int main()
{
	cout<<OneNum(1)<<endl;	//1
	cout<<OneNum(11)<<endl;	//4
	cout<<OneNum(111)<<endl;//36
	cout<<OneNum(123)<<endl;//57
	cout<<OneNum(93)<<endl;	//20
	system("pause");
	return 1;
}

思路二:找规律,可以直接根据数n中每一个数字来判断包含1的个数

复杂度为O(len),len表示数n包含的数字个数。

方法:

假设数字为abcde,对于abcde中的每一个数字,可以根据该数字与1的关系,求在该数字对应位置上1出现的次数。

具体来说:

假设我们要求百位出现1的次数,此时我们可以根据c与1的关系,求出百位1出现的次数。

(1)如果c = 0,则1出现的次数等于ab * 100,即 c前面的数 * c对应的基数

在该情况下,百位出现1的次数只与c前面的数有关

(2)如果c = 1,则1出现的次数等于(ab * 100) + (de + 1),即(c前面的数 * c对应的基数) +( c后面的数 + 1)

在该情况下,百位出现1的次数与c前面和c后面的数有关。

(3)如果c = 2,则1出现的次数等于(ab + 1)*100,即c前面的数 +1)* c对应的基数

在该情况下,百位出现1的次数只与c前面的数有关。

举例:

对于12013,在百位处出现1的次数= 12 * 100 = 1200次

其分别是,00100 -00199,01100 -01199,02100 - 02199,...,11100 - 11199。

(1)由于因为百位 = 0,则以12为开头的数不会含有1。

(2)百位前面的数值能有00 - 11,即出现12次。由于百位后的数字有两位,因此其基数为100。

以00 - 11为开头的数,后面都可以由00 变化到99,即包含了所有1的情况。

--------------------------------------

对于12113,在百位处出现1的次数= (12 * 100 ) + (13+1)= 1214次

(1)包含足够1的情况:00100 - 00199,01100 - 01199,02100 - 02199,...,11100 - 11199

(2)包含部分1的情况:12100 - 12113

即,由于百位 = 1,则以00 - 12为开头的数在百位都含有1。

(1)当百位前面的数字为00-11时,此情况包含了所有1的情况。(00-99)

(2)当百位前面为数字为12时,此情况仅仅包含了部分1的情况(00-13)

---------------------------------------

对于12213,在百位处出现1的次数= (12+1) * 100 = 1300次

其分别是,00100 - 00199,01100 - 01199,02100 - 02199,...,11100 - 11199,12100 - 12199。

此时,百位前面的数无论怎么变化,后面都可以由00 变化到99,即包含了所有1的情况。

代码:

#include <iostream>
#include <assert.h>
using namespace std;

int OneNum(int n) 
{
	assert(n >= 0);
	int nCurBit = n % 10; //待处理的每一位
	int nForward = n / 10; //nCurBit前面的数
	int nBackward = 0; //nCurBit后面的数
	int nBase = 1;
	int nSum = 0;
	while (n / nBase) 
	{
		if (nCurBit == 0)
		{
			nSum += nForward * nBase;
		}
		else if (nCurBit == 1)
		{
			nSum += nForward * nBase;
			nSum = nSum + nBackward + 1;
		}
		else
		{
			nSum += (nForward + 1) * nBase;
		}
		nCurBit = nForward % 10;
		nBase *= 10;
		nForward = n / (nBase * 10);	
		nBackward = n % nBase; 
	}
	return nSum;
}

int main()
{
	cout<<OneNum(1)<<endl;//1
	cout<<OneNum(11)<<endl;//4
	cout<<OneNum(111)<<endl;//36
	cout<<OneNum(123)<<endl;//57
	cout<<OneNum(93)<<endl;//20
	cout<<OneNum(0)<<endl;//0
	cout<<OneNum(9999)<<endl;//0
	system("pause");
	return 1;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 这道题需要统计一批整数出现最多的个位数字。我们可以先将这批整数的个位数字都提取出来,然后再统计每个数字出现次数,最后找出出现次数最多的数字即可。 具体做法如下: 1. 将这批整数的个位数字都提取出来,可以用取模运算(%10)实现。 2. 统计每个数字出现次数,可以用一个长度为10的数组来存储,数组下标表示数字,数组元素表示出现次数。 3. 找出出现次数最多的数字,可以遍历数组,找到出现次数最多的元素的下标,即为最多出现的数字。 下面是示例代码: ```python # 输入一批整数 nums = list(map(int, input().split())) # 统计每个数字出现次数 count = [] * 10 for num in nums: count[num % 10] += 1 # 找出出现次数最多的数字 max_count = max_digit = for i in range(10): if count[i] > max_count: max_count = count[i] max_digit = i # 输出结果 print(max_digit) ``` 注意,这里假设输入的整数都是非负整数。如果输入的整数可能是负数,需要先将其转换为正数再进行取模运算。 ### 回答2: 此题需要对输入的一批整数进行统计,并统计出其个位数字出现最多的数字。下面给出一种简单的思路。 1. 接收输入的整数集合。 首先,需要定义一个列表或数组,用来存放输入的多个整数。可以使用 input 函数来获取用户输入,也可以将固定数量的整数写死在程序。这里假设使用 input 函数获取用户输入。 2. 统计个位数字。 对于每个输入的整数,需要将其个位数字找出来,并统计出现次数。可以使用取模运算(%)来获得个位数字,使用一个字典来存储各个数字出现次数,例如: digit_count = {} # 定义一个空字典,用来存放数字出现次数 for num in num_list: digit = num % 10 # 取出个位数字 if digit not in digit_count: # 如果该数字尚未在字典出现过 digit_count[digit] = 1 # 则将其添加到字典,计数为 1 else: digit_count[digit] += 1 # 如果已经在字典出现过,则计数加 1 3. 找出出现次数最多的数字。 最后,需要遍历字典,找出出现次数最多的数字。可以使用一个变量来记录目前为止看到的出现次数最多的数字及其出现次数,例如: max_count = 0 max_digit = -1 # 如果找不到任何数字,就返回 -1 for digit, count in digit_count.items(): # 遍历字典的所有数字和其计数 if count > max_count: # 如果当前数字出现次数更多 max_digit = digit # 则更新出现次数最多的数字 max_count = count # 同时更新最大出现次数 上述代码逻辑应该比较容易理解。需要注意的是,为了防止找不到任何数字而返回空值,设置了 max_digit 的初始值为 -1。如果需要输出多个出现次数相同的数字,可以将它们存储在一个列表。 ### 回答3: 题目描述: 输入一批整数出这些整数个位数字出现最多的数字以及出现次数。 解题思路: 首先,我们需要将输入的整数分离出各个位上的数字,可以用%10来获取个位数。然后,我们需要一个计数器数组来记录个位数出现次数,每遍历到一个个位数,就让对应的计数器加1。最后,再遍历一遍计数器数组,找出出现次数最多的数字。如果有多个数字出现次数相同,我们可以将它们都记录下来,最后输出即可。 算法流程: 1. 首先输入整数数量n,以及n个整数a1,a2,a3,...,an。 2. 初始化计数器数组count,将其全部赋值为0。 3. 对于每一个输入的整数,遍历其整数各位上的数字。 4. 对于每个数字,将其个位数作为下标,在计数器数组对应的位置上加1。 5. 遍历计数器数组,找出出现次数最多的数字以及出现次数。 6. 如果有多个数字出现次数相同,将它们都记录下来。 7. 输出出现次数最多的数字以及出现次数。 算法实现: 下面给出该算法的Python实现代码:
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值