【剑指offer】面试题17 - 打印从 1 到 最大的 n 位数

面试题17:打印从 1 到最大的 n 位数

题目描述

输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。

解法一:大数加法

思路:

  • 当 n 过于大时,无论是 int 还是 long long 都会出现溢出,考虑至此,我们选择使用数组来处理大数问题
  • 由于每一位上面数字范围是 [0, 9] 共 10 个数字,故我们考虑使用 char 型数组,而 int 型数组过于浪费空间
  • 最大的 n 位数字,即需要打印直到 n 个 9 的时候即可
  • 如何判断是否到最大呢?
    • 策略 1:使用 strcmp 函数比较字符串与"999…999",可是 strcmp 时间复杂度为O(N),不太好
    • 策略 2:判断第 n+1 位是否发生进位,时间复杂度为 O(1),可行!
  • 如何打印呢?
    • 策略 1::使用 print 函数,但是会把字符串前面没有数字的 0 都给打印出来,这样不太好
    • 策略 2:遍历字符串,把前面的 0 全部略过,出现数字再打印
bool Increment(char *s)
{
	bool flag = false;
	int nextDig = 0;
	for (int i = strlen(s) - 1; i >= 0; i--)
	{
		int curNum = s[i] - '0' + nextDig;
		if (i == strlen(s) - 1)
			curNum++;
		if (curNum > 9)
		{
			if (i == 0)
			{
				flag = true;
			}
			else
			{
				nextDig = 1;
				curNum -= 10;
				s[i] = curNum + '0';
			}
		}
		else
		{
			s[i] = curNum + '0';
			break;
		}
	}
	return flag;
}
void PrintS(char* s)
{
	int i;
	for (i = 0; i < strlen(s); i++)
	{
		if (s[i] != '0') break;
	}
	for (; i < strlen(s); i++)
	{
		printf("%c", s[i]);
	}
}
void PrintToMaxOfNDigits(int n)
{
	if (n <= 0) return;
	char* s = new char[n + 1];
	memset(s, '0', n);
	s[n] = '\0';
	while (!Increment(s))
	{
		PrintS(s);
		putchar('\n');
	}
	delete[] s;
}

解法二:全排列

思路:

  • n 位数字从 0 到 9 的全排列
  • 打印时,前面的 0 不打印出来
void PrintS(char* s)
{
	int i;
	for (i = 0; i < strlen(s); i++)
	{
		if (s[i] != '0') break;
	}
	for (; i < strlen(s); i++)
	{
		printf("%c", s[i]);
	}
}
void func(char* s, int n, int index)
{
    if(index == n-1)
    {
        PrintS(s);
        return ;
    }
    for(int i = 0; i < n ;i++)
    {
        s[i] = '0' + i;
        func(s, n, i);
    }
}
void PrintToMaxOfNDigits(int n)
{
    if(n <= 0)	return ;
    char* s = new char[n+1];
    s[n] = '\0';
	func(s, n, 0);
    delete[] s;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值