剑指offer面试题12:打印1到最大的n位数
因为没有说明n的大小,所以有可能long long型也无法存下这个n位数,所以考虑大数问题,将其存储为字符数组或字符串。主要包括如何在字符串上模拟加法和如何把字符串打印出来。
void Print1ToMaxOfNDigits_1(int n)
{
if (n <= 0)
return;
char* number = new char[n + 1];
memset(number, '0', n);
number[n] = '\0';
while (!Increment(number))
{
PrintNumber(number);
}
delete[]number;
}
模拟字符加法要注意怎么判断已经达到最大的n位数,因为当达到最大的n位数后,再加一的话,第一个‘9’(第0位)会产生进位,而其他时候第一位均不会产生进位,所以以此来判断。
bool Increment(char* number)
{
bool isOverflow = false;
int nTakeOver = 0;
int nLength = strlen(number);
for (int i = nLength - 1; i >= 0; --i)
{
int nSum = number[i] - '0' + nTakeOver;
if (i == nLength - 1)
nSum++;
if (nSum >= 10)
{
if (i == 0)
isOverflow = true;
else
{
nSum -= 10;
nTakeOver = 1;
number[i] = nSum + '0';
}
}
else
{
number[i] = nSum + '0';
break;
}
}
return isOverflow;
}
打印字符串要注意当开头为‘0’的时候,根据习惯是不打印出来的,如‘098’,打印为98。
void PrintNumber(char* number)
{
bool isBegining0 = true;
int nLength = strlen(number);
for (int i = 0; i < nLength; ++i)
{
if (isBegining0&&number[i] != '0')
isBegining0 = false;
if (!isBegining0)
printf("%c", number[i]);
}
printf("\t");
}
第二种思路是把问题转换成数字排列,n位所有十进制数其实是n个0到9的全排列。所以只要把每一位从0到9排列一遍就可以得到所有的数了。
void Print1ToMaxOfNDigits_2(int n)
{
if (n <= 0)
return;
char* number =new char[n + 1];
number[n] = '\0';
for (int i = 0; i < 10; ++i)
{
number[0] = i + '0';
Print1ToMaxDigitsRecursively(number, n, 0);
}
delete[]number;
}
void Print1ToMaxDigitsRecursively(char* number, int length, int index)
{
if (index == length - 1)
{
PrintNumber(number);
return;
}
for (int i = 0; i < 10; ++i)
{
number[index + 1] = i + '0';
Print1ToMaxDigitsRecursively(number, length, index + 1);
}
}
杭电ACM 1002题目
解法:先在较短的数前填充‘0’,使得两个整数长度一样,然后从最后一位开始,逐位相加,并加上从上一次得到的进位,相加结束后,要单独判断进位是否为1,若为1,则在结果前面加上‘1’,否则不处理。
#include
#include
#include
using namespace std;
string addtwonumbers(string num1,string num2)
{
int length;
if (num1.length() > num2.length())
{
length = num1.length();
string temp(num1.length() - num2.length(), '0');
num2 = temp + num2;
}
else
{
length = num2.length();
string temp(num2.length() - num1.length(), '0');
num1 = temp + num1;
}
string sum(length, '0');
int carry = 0;//进位
for (int i = length - 1; i >= 0; --i)
{
int nSum = num1[i] - '0' + num2[i] - '0' + carry;
sum[i] = nSum % 10 + '0';
carry = (nSum > 9);
}
if (carry == 1)
sum = '1' + sum;
return sum;
}
int main()
{
int t; //the number of test cases;
cin >> t;
string *a = new string[t]; //use the dynamic array when not knowing the dimension before compiling;
string *b = new string[t];
string *sum = new string[t];
for (int i = 0; i != t; ++i)
{
cin >> a[i] >> b[i];
sum[i] = addtwonumbers(a[i], b[i]);
}
for (int i = 0; i != t; ++i){
cout << "Case " << i + 1 << ":\n"
<< a[i] << " + " << b[i] << " = " << sum[i] << endl;
if (i
进一步问题,该代码只实现的两个正数相加,没有考虑输入中有负数的情况。
下面考虑加数中有负数的情况,若两个加数都是负数,则直接相加再在前面加个负号就可以了。若只有其中一个为负数,又分为两种情况,若正数绝对值大于负数,则用正数加上负数,最高位不会出现借位的情况,此时结果是正数;若正数小于负数,此时最高位还需进一步借位,我们在此假设Sub1长度不足Sub2长度的部分填充0,以“123”-‘456789’为例,如下见图所示,最终结果应该是“456666”,还要加上负号。
上图可以理解为:
Sub1-Sub2=-(-(Sub1-Sub2))=-(-(基数+Sub1-Sub2-基数))=-(基数-(基数+Sub1-Sub2))
string BigMiunsSmall(string big, string small)//大数减小数(正数)
{
int length = big.length();
string temp(big.length() - small.length(), '0');
small = temp + small;
string minus(length, '0');
int borrow = 0;//借位
for (int i = length - 1; i >= 0; --i)
{
int nMinus = big[i] - small[i] - borrow;
cout << nMinus << endl;
if (nMinus < 0)
{
nMinus += 10;
borrow = 1;
minus[i] = nMinus + '0';
}
else
{
borrow = 0;
minus[i] = nMinus + '0';
}
}
return minus;
}
string addtwonumbers(string num1, string num2)
{
int length;
int flagNum1 = 1;
int flagNum2 = 1;
if (num1[0] == '-'&&num1[0] == '-')
{
flagNum1 = -1;
flagNum2 = -1;
}
else if (num1[0] == '-')
{
num2 = '+' + num2;
flagNum1 = -1;
}
else if (num2[0] == '-')
{
num1 = '+' + num1;
flagNum2 = -1;
}
else
{
num1 = '+' + num1;
num2 = '+' + num2;
}
if (num1.length() > num2.length())
{
length = num1.length();
string temp(num1.length() - num2.length(), '0');
num2 = num2[0] + temp+num2.substr(1, num2.length() - 1);
}
else
{
length = num2.length();
string temp(num2.length() - num1.length(), '0');
num1 = num1[0] + temp+ num1.substr(1, num1.length() - 1);
}
string sum(length - 1, '0');
int carry = 0;//进位
if (flagNum1*flagNum2 == 1)
{
for (int i = length - 1; i >= 1; --i)
{
int nSum = num1[i] - '0' + num2[i] - '0' + carry;
if (nSum >= 10)
{
nSum -= 10;
carry = 1;
sum[i - 1] = nSum + '0';
}
else
{
carry = 0;
sum[i - 1] = nSum + '0';
}
}
if (carry == 1)
sum = '1' + sum;
if (flagNum1 == -1 && flagNum2 == -1)
sum = '-' + sum;
}
else
{
for (int i = length - 1; i >= 1; --i)
{
int nSum = flagNum1*(num1[i] - '0') + flagNum2*(num2[i] - '0') + carry;
if (nSum < 0)
{
nSum += 10;
carry = -1;
sum[i-1] = nSum + '0';
}
else
{
carry = 0;
sum[i-1] = nSum + '0';
}
}
if (carry == -1)
{
string borrow(length, '0');
borrow[0] = '1';
sum = BigMiunsSmall(borrow, sum);
sum[0] = '-';
}
}
return sum;
}
参考文献:
http://www.cnblogs.com/ziqiao/archive/2010/10/09/1846955.html
http://www.cnblogs.com/ballwql/archive/2013/04/20/3032090.html