目录
- 大数加法
- 题目解析
- 解法
- 代码
- 链表相加(二)
- 题目解析
- 解法
- 逆序链表函数
- 代码
- 大数乘法
- 题目解析
- 解法
- 代码
感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐣🐣 python
🐓🐓🐓 数据结构C语言
🐔🐔🐔 C++
🐿️🐿️🐿️ 文章链接目录
🏀🏀🏀 笔试练习题
大数加法
链接大数加法
题目解析
这道题就是模拟计算的过程
比如123+789,我们先让各位的相加,因为涉及到进位,所以需要有一个中间变量t保存进位的数
比如3+9=12.需要进1,就用中间变量t=1
计算十位的时候2+8+t=11,再让t=1
…
解法
因为是以字符串形式去返回的,所以我们需要定义一个string ret
并且计算的过程中需要知道字符串有多少个字符,所以我们用sizes和sizet分别表示字符串s和字符串t有多少个字符
因为从个位开始计算,然后一直进位,所以我们要进行while循环,循环条件即是sizes和sizet的大小大于等于0,且在最后的时候我们还需要保证中间变量tmp为0,因为如果tmp不为0的话就说明还要进位,我们还需要进行一次循环,否则就会丢失数据
循环内部我们要分别对sizes和sizet进行判断,如果sizes已经为负数了,那就不将s[sizes]进行相加
因为是分别判断所以每次判断如果符合条件就和tmp进行相加
在两个判断都结束后,要将tmp的个位通过+=的形式追加到ret的尾部,然后让tmp保留十位的数
最后再用reverse进行逆序
具体过程如下图,s为12,t为89,tmp初始化为0
将tmp的个位追加到ret尾部
让tmp等于他的十位上的数字
之后重复上面操作
最后将ret进行逆序,因为是尾插
代码
class Solution {
public:
string solve(string s, string t) {
string ret;
int sizes=s.size()-1,sizet=t.size()-1;
int tmp=0;
while(sizes>=0||sizet>=0||tmp)
{
if(sizes>=0)
tmp+=s[sizes--]-'0';
if(sizet>=0)
tmp+=t[sizet--]-'0';
ret+=tmp%10+'0';
tmp/=10;
}
reverse(ret.begin(),ret.end());
return ret;
}
};
链表相加(二)
链接链表相加(二)
题目解析
这道题和上一道题很相似,只不过这个是链表
链表有个难点就是我们要实现加法的话应该是从后往前加,但是由于是链表,如果我们从后往前加的话会找不到前一个节点
所以我们要先对链表进行逆序
解法
这里的解法会用到一个常用的操作就是创建一个虚拟头节点,有了这个虚拟头结点,我们就不需要考虑链表为空的情况
逆序链表函数
ListNode* reverse(ListNode* head) {
ListNode* newHead = new ListNode(0);
ListNode* cur = head;
while (cur) {
ListNode* next = cur->next;
cur->next = newHead->next;
newHead->next = cur;
cur = next;
}
cur = newHead->next;
delete newHead;
return cur;
}
逆序链表函数传递一个头结点的指针,然后创建一个虚拟头结点
注意这个虚拟的头结点ListNode(0)表示的是val=0,next为空
将原链表的头结点给到cur去遍历链表,然后头插,在头插的时候要保留cur的下一个节点,否则头插完一次后就找不到下一个节点的地址了
具体过程如下
cur->next=newHead->next,此时的cur不再指向next
newHead->next指向cur
整理一下就变成下面这样了
重复上面的操作,cur->next指向newHead->next,此时的newHead->next指向的是节点1,所以cur->next指向节点1
再让newHead->next指向cur
整理后变成了这样
让cur指向newHead->next,也就是节点2
让newHead->next指向cur
最后整理后变成这样,因为这次的next为空,让cur=next后,cur也就为空,while循环判断的cur是否为空,所以这次会直接跳出循环
循环跳出后将cur指向newHead->next,再销毁newHead
代码
ListNode* addInList(ListNode* head1, ListNode* head2) {
head1 = reverse(head1);
head2 = reverse(head2);
int t = 0;
ListNode* cur1 = head1, *cur2 = head2;
ListNode* ret = new ListNode(0);
ListNode* prev = ret;
while (cur1 || cur2 || t) {
if (cur1) {
t += cur1->val;
cur1 = cur1->next;
}
if (cur2) {
t += cur2->val;
cur2 = cur2->next;
}
prev = prev->next = new ListNode(t % 10);
t /= 10;
}
cur1 = ret->next;
ret->next = nullptr;
delete ret;
return reverse(cur1);
}
};
将两个链表分别逆序,这样做的目的是可以实现个位和个位相加…
用一个变量t保存进位,并且用两个指针cur1和cur2指向两个逆序链表的头节点
创造出一个链表ret保存两个逆序链表相加的结果,并用一个指针prev指向ret头结点
因为要两个逆序链表一起遍历相加,所以用while循环,while循环的判断是cur1||cur2||t不为0
因为可能会出现已经有一个逆序链表遍历完了,而另一个没有遍历完,所以还需要进行遍历,而t不为0是考虑的进位的问题
在循环内部用if语句去判断cur1和cur2是否为空,如果不为空就让cur的val与t相加,同时让cur走到下一个节点
每进行一次循环后都需要保存他们相加的值到prev->next里面去,但是要注意的是t可能大于10,所以我们保存的值应该为t%10
prev = prev->next = new ListNode(t % 10)可以拆分成
prev->next = new ListNode(t % 10)
prev = prev->next
之后让t=t/10,使t保存进位
大数乘法
链接大数乘法
题目解析
这里的方法和第一题是一样的,并且顺便说一下为什么要用字符串的形式读入和输出,这是因为有些数字太大了已经超出最大的范围,所以用字符串的形式
解法
这里的解法是无进位相乘然后相加,但是要注意的是这和我们平时计算的方式有一点不同
我们平时计算是进位与计算同时进行的,而这里我们是直接进行计算不进位,在计算完后将进位的数字进行相加
过程如下
代码
string solve(string s, string t) {
reverse(s.begin(), s.end());
reverse(t.begin(), t.end());
int m = s.size(), n = t.size();
vector<int>tmp(m + n);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
tmp[i + j] += (s[i] - '0') * (t[j] - '0');
}
}
int c = 0;
string ret;
for (auto x : tmp) {
c += x;
ret += c % 10 + '0';
c /= 10;
}
while (c) {
ret += c % 10 + '0';
c /= 10;
}
while (ret.size() > 1 && ret.back() == '0')
ret.pop_back();
reverse(ret.begin(), ret.end());
return ret;
}
};