当所处理的对象数值很大时,如(int)32634573563452724846734573
,使用整型长整型,都会溢出,这种情况就要使用字符串代替数字。此方法处理大数问题。
两个知识点:
字符型的数字与其对应的ASCII值:
char |
‘0’ |
‘1’ |
‘2’ |
‘3’ |
… |
‘9’ |
int |
48 |
49 |
50 |
51 |
… |
57 |
char与对应int转换
char->int: '3'-'0' = 3
int->char: 3 +'0' = '3'
问题描述
给一个n位数,打印从1到最大的n位数。比如n=3,则打印1,2,3,...,998,999
.
思路
当n为20,其对应的数值已经远远超过了计算机可以表示的范围,所以用字符串表示一个大数,并且实现中不能出现for
循环,因为循环变量i
随循环次数也会超出表示范围的。所以用while循环避免使用循环变量。
实现
下面的实现是有冗余的,只用addOne()
或subtractOne()
其一即可。当使用addOne()
时,只要加一后的string不等于最大的n位数,就打印,后循环;当使用subtractOne()
,初始string设为最大的n位数,while循环减一,只要这个string不是空,就打印,后循环。
当然两个函数可以配合使用,不过就多余了,但就当练习大数操作了。
一个string表示的大数加一操作如下。先在string首位插入一个’0‘占位,可能加一后要进位:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| string addOne(string num) { if (num.size() == 0) return " "; num.insert(0, 1, '0');
int carry = 1; int i = num.size() - 1; while (carry != 0) { int sum = (num[i] - '0') + carry; carry = sum / 10; int remainder = sum % 10; num[i] = remainder + '0'; i--; } return num[0]=='0' ? num.substr(1) : num; }
|
一个string表示的大数减一的实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| string subtractOne(string Nine) { bool borrow = false; int length = Nine.size(); int iter = length - 2; int val; if (Nine[length - 1] == '0') { borrow = true; val = 10 + (Nine[length - 1] - '0') - 1; Nine[length - 1] = val + '0'; } else Nine[length - 1] = Nine[length - 1] - '0' - 1 + '0';
while ( borrow && iter >= 0) { if (Nine[iter] == '0') val = 10 + (Nine[iter] - '0') - 1; else { borrow = false; val = (Nine[iter] - '0') - 1; } Nine[iter] = val + '0'; iter--; } return Nine[0]=='0' ? Nine.substr(1) : Nine; }
|
主函数,仔细分析,上述两个操作,使用一个就可以达到目的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void solution(int n) { if (n <= 0) return;
string str; for (int i = 0; i < n; i++) str += '9'; cout << str << endl;
string preNum = addOne("0"); string isZero = subtractOne(str);
while (isZero != "") { cout << preNum << " "; preNum = addOne(preNum); isZero = subtractOne(isZero); } cout <<str<< endl; return; }
|
敲黑板
- 体会
subtractOne
中的bool borrow = false;
,表示向前借位否,
- 实现中总会用到知识点2.
415大数相加
依然使用到上述知识点2,思路直接,实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| string addStrings(string num1, string num2) { int length1 = num1.size(); int length2 = num2.size();
if(length1 != length2){ int diff = abs(length1-length2); length2 > length1 ? num1.insert(0, diff, '0') : num2.insert(0, diff, '0'); } int length = num1.size() + 1; string res(length,'0');
int carry=0; for(int i=length-2; i>=0; i--){ int sum = (num1[i]-'0') + (num2[i]-'0') + carry; carry = sum/10; int remainder = sum%10;
res[i+1] = remainder + '0'; } if (carry) res[0] = carry + '0';
return res[0]=='0' ? res.substr(1) : res; }
|