“从1到n整数中1出现的次数”的非递归解法


//by L&L
//《剑指offer》面试题32,P174
//问题:从1到n整数中1出现的次数
//
//非递归方法描述:
//先取一个具体的例子,假设n = 9999;
//令个位为1,则有(999+1)*1个数;
//令十位为1,则有(99 +1)*10个数;
//令百位为1,则有(9  +1)*100个数;
//令千位为1,则有(0  +1)*1000个数;
//以上相加,得...共4000
//上面这个例子太特殊,再看一个更具普遍性的例子:
//假设n = 2014:
//令个位为1,则有(201+1)*1个数;
//令十位为1,则有(20   )*10+1*(4+1)个数;
//令百位为1,则有(2    )*100个数;
//令千位为1,则有(0  +1)*1000个数;
//以上相加,得202+205+200+1000=1607
///可以看出,有三种情况需要考虑:该位上数字小于1,等于1,大于1
#include <iostream>
#include <time.h>

int NumberOf1Between1AndN(unsigned n);//原始方法,效率不行
int NumberOf1(unsigned n);

int NumberOf1Between1AndN2(unsigned n);//高效方法,非递归
bool GetNumber(const unsigned& n, unsigned ui, 
			   unsigned* pHi, unsigned* pBe, unsigned* pLo, unsigned* pBase);

int main()
{
	clock_t  clockBegin, clockEnd;
	unsigned ui = 88801666u;
	std::cout << "计算从1到" << ui << "整数中1出现的次数" <<std::endl;
	std::cout << "begin:" << std::endl;
	clockBegin = clock(); 
	std::cout << NumberOf1Between1AndN(ui);
	clockEnd = clock();
	std::cout << ", used " << clockEnd - clockBegin << "ms" << std::endl;
	std::cout << NumberOf1Between1AndN2(ui);
	std::cout << ", used " << clock() - clockEnd << "ms" << std::endl;

	system("pause");
	return 0;
}

//原始方法,效率不行
int NumberOf1Between1AndN(unsigned n)
{
	int number = 0;
	for (unsigned i = 1; i <= n; ++i)
	{
		number += NumberOf1(i);
	}
	return number;
}

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

//高效方法,非递归
int NumberOf1Between1AndN2(unsigned n)
{
	int number = 0;
	unsigned hi = 0, be = 0, lo = 0;
	unsigned uiBase = 1;
	for (unsigned i = 1, ii = 1; ii < n * 10; ++i, ii *= 10)
	{
		if (GetNumber(n, i, &hi, &be, &lo, &uiBase))
		{
			if (be > 1)
				number += (hi + 1) * uiBase;
			else if (be < 1)
				number += hi * uiBase;
			else
				number += hi * uiBase + (lo + 1);
		}
	}
	return number;
}

bool GetNumber(const unsigned& n, unsigned ui, 
			   unsigned* pHi, unsigned* pBe, unsigned* pLo, unsigned* pBase)
{
	if (0 == ui)
		return false;
	unsigned uiBase = 1;
	while (--ui)
		uiBase *= 10;
	*pHi = n / (uiBase * 10);
	*pBe = n % (uiBase * 10);
	*pLo = *pBe % uiBase;
	*pBe = *pBe / uiBase;
	*pBase = uiBase;
	return true;
}

/*输出:
计算从1到88886666整数中1出现的次数
begin:
72345037, used 9024ms
72345037, used 1ms
请按任意键继续. . .
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值