目录
编辑
<->本篇简介:
<二>题目解析解答:
2·1大数乘法问题:
①题目:
②思路汇总:
③解答代码:
2·2 大数加法问题:
①题目:
②思路汇总:
③解答代码:
2·3链表相加(二):
①题目:
②思路汇总:
③解答代码:
<三>做题总结:
<->本篇简介:
本篇文章分为三个部分也就是三道题来对一系列大数求和积问题做一下解答已经总结,这里正如题目所说的链表,字符串等,这些也不过是一个形式,其实可以归为一类,因此这里我们要知道真正的侧重点是在于如何去求和以及乘积? 这里也就是我们不能盲目的直接相加啊,相乘啊去求,因此可以把加以及乘的具体步骤模拟一下,最后得到最后答案,说白了也就是我们要一位一位来,而不是‘’一口气‘’!
因此下面我们就根据三道题来分析一下具体思路以及解法,一下是这三道题的链接,方便寻找,我们在这一起拿出(之后每个题目解答还会存在)。
大数乘法_牛客题霸_牛客网
大数加法_牛客题霸_牛客网
链表相加(二)_牛客题霸_牛客网
<二>题目解析解答:
2·1大数乘法问题:
①题目:
nowcoder链接:大数乘法_牛客题霸_牛客网
②思路汇总:
思路:
首先根据num1和num2的位数确定要返回的字符串位数,开辟初始化好,然后把它拆分成num2的每一位从后往前与num1的数一位一位乘,故
这里用了num2嵌套num1的for循环。总结的规律:对应num1与num2里元素相乘得到的结果%放在ret数组的i+j+1位置,而/数放在i+j
位置,因此循环里可以套这个逻辑(而当算num2的十位与num1相乘的时候就要考虑加上对于ret数组位置上原先的数累加并进位了)
注:与正常相乘算法不同:这个是比如123*456:算出错位的738 就加上 后面算出的错位的 615.等到492算出再加上,是算一次就加上,而不是
最后一起加。
③解答代码:
#include <iostream>
#include<string>
using namespace std;
string multiply(string num1, string num2) {
if(num1=="0"||num2=="0")//一个零都为零
{
return "0";
}
int n1=num1.size();
int n2=num2.size();
string ret(n1+n2,'0');
for(int i=n2-1;i>=0;i--){
for(int j=n1-1;j>=0;j--){
//由于如果是第一次可以不用,而后面的次数都要加上原先ret数组含有的值
int re=(num2[i]-'0')*(num1[j]-'0')+(ret[i+j+1]-'0');//保存值,然后% /再放入对应数组
ret[i+j+1]=re%10+'0';
ret[i+j]= re/10+ret[i+j];//加减'0'抵消了
}
}
//找是否存在开头有‘0’的情况
string tmp;
int count=-1;
for(auto o:ret){
if(o=='0'){
count++;
}
else{
break;
}
}
if(count==-1){
count=0;
return ret;
}
tmp =ret.substr(count+1,n1+n2-count);
return tmp;
}
int main() {
string s1;
string s2;
cin>>s1;
cin>>s2;
string ret= multiply(s1,s2);
cout<<ret<<endl;
return 0;
}
// 64 位输出请用 printf("%lld")
2·2 大数加法问题:
①题目:
nowcoder题目链接:大数加法_牛客题霸_牛客网
②思路汇总:
思路:栈+分步加法,这里由于可能一开始思路是直接转成整型或者longlong然后再相加,然而试过就知道了这种方法直接否掉了,因此我们可以借助一个栈的方法得到它的尾位然后依次保留商,依次与余数叠加放入新的栈,最后来个调整即可得到正确字符串,这里特别细的细节也没用,按着这样的思路就好。
下面介绍一下步骤汇总:
1.s与t分别遍历后放入两个栈里。
2·分别取完栈顶元素后再pop然后完成一系列叠加操作,取余放入新栈。
3·把新栈中的元素遍历出string中返回即可。
③解答代码:
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 计算两个数之和
* @param s string字符串 表示第一个整数
* @param t string字符串 表示第二个整数
* @return string字符串
*/
string solve(string s, string t) {
stack<char> s1, s2,ret;
char top1='0',top2='0';
int discuss = 0;
for (int i = 0; i < s.size(); i++) s1.push(s[i]);
for (int i = 0; i < t.size(); i++) s2.push(t[i]);
while (!s1.empty() || !s2.empty() || discuss) {
if (!s1.empty()) top1 = s1.top(); //这里不能pop,赋完值后pop
if (!s2.empty())top2 = s2.top(); //这里不能pop,赋完值后pop
int val1 = s1.empty() ? 0 : top1-'0';
int val2 = s2.empty() ? 0 : top2-'0';
if (!s1.empty()) s1.pop();
if (!s2.empty()) s2.pop();
int sum = val1 + val2 + discuss;
discuss = sum / 10;
ret.push(sum%10+'0');
}
string ans;
while(!ret.empty()){
ans+=ret.top();
ret.pop();
}
return ans;
}
};
2·3链表相加(二):
①题目:
②思路汇总:
思路:这里由于是从链表后面开始加故要么逆置链表要么借助栈容器先把它们各自入进去然后每次top加pop完成相加,余数入ret栈,保存商,方便下一次得到的余数相加,最后把分个的节点通过一次出栈的顺序连接起来。
细节问题:
1· 可以接着叠加assert不能为0,如这种情况,即使两个栈都为空也要进行叠加:[5] [6];(叠加成立的是三个条件)
2·不能保存top1或者top2就立马给它出栈,因为下面会根据判空来对val1和val2赋值操作,故要等赋完值后再pop。
③解答代码:
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head1 ListNode类
* @param head2 ListNode类
* @return ListNode类
*/
ListNode* addInList(ListNode* head1, ListNode* head2) {
// write code here
stack<ListNode*>s1,s2,ret;
ListNode* cur=nullptr;
ListNode* top1=nullptr;
ListNode* top2=nullptr;
ListNode*cur1=head1;
ListNode*cur2=head2;
int discuss=0;
//入栈:
while(cur1){
s1.push(cur1);
cur1=cur1->next;
}
while(cur2){
s2.push(cur2);
cur2=cur2->next;
}
//对应节点的val相加操作:
while(!s1.empty()||!s2.empty()||discuss){
if(!s1.empty()) top1=s1.top();//这里不能pop,赋完值后pop
if(!s2.empty())top2=s2.top();//这里不能pop,赋完值后pop
int val1=s1.empty()?0:top1->val;
int val2=s2.empty()?0:top2->val;
if(!s1.empty()) s1.pop();
if(!s2.empty()) s2.pop();
int sum=val1+val2+discuss;
discuss=sum/10;
cur=new ListNode(sum%10);
ret.push(cur);
}
//最后结果链表的组合:
cur=ret.top();
ListNode*fans=cur;
ret.pop();
while(!ret.empty()){
ListNode*top3=ret.top();
ret.pop();
cur->next=top3;
cur=top3;
}
return fans;
}
};
<三>做题总结:
仅个人理解:这里比如说像上面的字符串,链表节点等求和,积,其实这不是重点,重点是对加法和乘法要怎么操作?——>这里我认为大致分为两类:
1·就是求加法(当然这里不能直接求):这里一般就是给你一组数(先不要管是啥类型),肯定是从末尾到前,这么对应加,因此这里引用了栈,完成一系列操作。所以只要是加法我们可以优先考虑一下栈。
2·就是乘法:乘法我们要知道它可以理解为“加法的升级”,怎么解释呢? 它就相当于加法然后还要错位相加一次,因此我们这里可以转化成每次一位数(i处)乘完另一个数各个位,然后与下面i+1处的再次重复,接下来不就是个加法操作(只不过错位了),因此这里可以借助一个数组(初始化0),大小就是这两位数size之和,如(999*999不就最长也就是六位数嘛)。因此再来两个for循环嵌套,相乘后模放到i+j+1位置也就是对应那个开辟数组的相应位置(当然也要加上原来此位置上的值),此时我们得到的就是总和,然后取余放到它的前一位也就是i+j(当然一开始对应的是0,但是错位相乘的时候就不是零了,因此我们还要加上原来这里的值,这也算一个细节吧),最后遍历完,然后消除前置零即可了,故概括为开辟数组根据下标判断位置映射过去,最后去无关0即可。
如有错误或不详细地方欢迎各位大佬留言指导.