《程序员面试金典(第6版)》面试题 02.05. 链表求和
创始人
2024-05-29 02:23:08
0

题目内容

给定两个用链表表示的整数,每个节点包含一个数位。这些数位是反向存放的,也就是个位排在链表首部。编写函数对这两个整数求和,并用链表形式返回结果。

示例:

  • 输入:(7 -> 1 -> 6) + (5 -> 9 -> 2),即617 + 295
    输出:2 -> 1 -> 9,即912

进阶:思考一下,假设这些数位是正向存放的,又该如何解决呢?

示例:

  • 输入:(6 -> 1 -> 7) + (2 -> 9 -> 5),即617 + 295
    输出:9 -> 1 -> 2,即912

解题思路与代码

这种题它没有给你说链表的节点范围,就不要贸然的想要去用遍历节点然后存储在一个int里。因为很可能存不下。就算是换size_t类型也不行。

方法一:对位相加法

由于由于输入的两个链表都是反向存放数字的位数的,因此两个链表中同一位置的数字可以直接相加。首先我们可能会察觉到一个问题,就是相加超过10会产生进位问题,所以我们就先设置一个进位变量nextBit将它置为0.之后我们逐位去遍历链表,将当前的 进位值 与 两个链表当前位的和相加起来。具体而言,如果当前两个链表处相应位置的数字为v1,v2 则这个的和sum = v1 + v2 + nextBit。我们创建一个新链表,每次将(sum%10)作为一个节点的值存进链表。然后再新的进位值设置为(sum /10)。

还有一个问题便是我们链表会出现长短不一的情况那怎么办呢?很好办,将短的链表的值设为0即可。这个设计很巧妙,具体可以看代码:

代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode *head = nullptr, *pos = nullptr;int nextBit = 0; while(l1 || l2){int v1 = l1 ? l1->val : 0;int v2 = l2 ? l2->val : 0;int sum = v1 + v2 +nextBit;if(!head){head = pos = new ListNode(sum % 10);}else{pos->next = new ListNode(sum % 10);pos = pos->next;}nextBit = sum / 10;if(l1) l1 = l1->next;if(l2) l2 = l2->next;}if(nextBit) pos->next = new ListNode(nextBit);return head;}
};

给出这个代码的复杂度分析:
时间复杂度:O(max(m,n)),其中m,n分别是链表l1,l2的节点个数,我们需要遍历两个链表的全部位置,而处理每个位置只需要 O(1) 的时间。
空间复杂度:O(1),没有用到额外的数据结构。

进阶:思考一下,假设这些数位是正向存放的,又该如何解决呢?

先开个玩笑,其实可以先翻转链表,然后再进行同为相加操作,hh。这种写法我就不写了,没什么必要。

那换一种思路想想,有没有什么数据结构,可以让我们实现先加链表的最后面的节点呢?
答案是:栈(stack) 。我们可以分别把链表l1,l2的节点分别压入栈中。此时取出来的元素必定是相同位数。如果有的栈先取完了,和刚刚一样,当做0就行。

注意,虽然说,这里的进阶是让你去思考,如果你拿我的代码去leetcode上去提交,题解肯定是不通过的,这是因为,leetcode里面的案例都是个位数是排在前面的,而我们这个进阶思考是让你将最高位排在最前面。

而将最高位排在最前面其实就运用到了一个技巧,就是用循环来插入头节点。也就是反转链表

class Solution {
public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {stack s1, s2;while (l1) {s1.push(l1 -> val);l1 = l1 -> next;}while (l2) {s2.push(l2 -> val);l2 = l2 -> next;}int carry = 0;ListNode* head = nullptr;while (!s1.empty() or !s2.empty() or carry != 0) {int a = s1.empty() ? 0 : s1.top();int b = s2.empty() ? 0 : s2.top();if (!s1.empty()) s1.pop();if (!s2.empty()) s2.pop();int cur = a + b + carry;carry = cur / 10;cur %= 10;auto pos = new ListNode(cur);pos -> next = head;head = pos;}return head;}
};

给出这个代码的复杂度分析:
时间复杂度:O(max(m,n)),其中m,n分别是链表l1,l2的节点个数,我们需要遍历两个链表的全部位置,而处理每个位置只需要 O(1) 的时间。
空间复杂度:空间复杂度主要取决于我们把链表内容放入栈中所用的空间。

总结

这道题说难不算很难,但也不算简单。处处考验了大家对于操作链表的细节。大家可能都知道要同位相加,但同位相加的操作却怎么也写不对,这就是经验啦,做的题越多,对于细节的处理就越到位,代码也就越容易通过。

相关内容

热门资讯

苹果系统安卓爱思助手,系统兼容... 你有没有发现,手机的世界里,苹果系统和安卓系统就像是一对欢喜冤家,总是各有各的粉丝,各有各的拥趸。而...
安卓系统占用很大内存,揭秘内存... 手机里的安卓系统是不是让你感觉内存不够用,就像你的房间堆满了杂物,总是找不到地方放新东西?别急,今天...
安卓系统p30,安卓系统下的摄... 你有没有发现,最近安卓系统P30在手机圈里可是火得一塌糊涂呢!这不,我就来给你好好扒一扒这款手机的那...
siri被安卓系统进入了,智能... 你知道吗?最近科技圈可是炸开了锅,因为一个大家伙——Siri,竟然悄悄地溜进了安卓系统!这可不是什么...
最强挂机系统和安卓区别,揭秘安... 亲爱的读者,你是否曾在游戏中遇到过这样的困扰:一边想要享受游戏带来的乐趣,一边又不想放弃手中的零食或...
安卓系统为什么设系统盘,保障稳... 你有没有想过,为什么安卓系统里会有一个叫做“系统盘”的东西呢?这可不是随便设置的,背后可是有大学问的...
王者怎么加安卓系统的,轻松提升... 你有没有想过,你的手机里那款超酷的王者荣耀,怎么才能让它更好地在你的安卓系统上运行呢?别急,今天就来...
安卓手机系统怎么开热点,共享网... 你有没有想过,当你身处一个没有Wi-Fi信号的地方,而你的安卓手机里却存满了精彩视频和游戏时,是不是...
安卓系统11的平板电脑,性能升... 你有没有发现,最近平板电脑市场又热闹起来了?没错,安卓系统11的新一代平板电脑正在悄悄地走进我们的生...
安卓手机系统创始人,安卓手机系... 你有没有想过,那些陪伴我们每天生活的安卓手机,它们的灵魂是谁赋予的呢?没错,就是那位神秘而又传奇的安...
安卓11系统速度提升,体验再升... 你知道吗?最近安卓系统又升级啦!这次可是直接跳到了安卓11,听说速度提升了不少呢!是不是很心动?那就...
安卓5.1原生系统设置apk,... 你有没有想过,你的安卓手机里那些看似普通的设置,其实隐藏着不少小秘密呢?今天,就让我带你一探究竟,揭...
手机安卓系统玩音游,畅享指尖音... 你有没有发现,现在手机上的游戏种类越来越丰富,尤其是音游,简直让人爱不释手!今天,就让我来给你详细介...
安卓系统与win10,系统融合... 你有没有想过,为什么你的手机里装的是安卓系统,而电脑上却是Windows 10呢?这两种操作系统,就...
苹果系统王者安卓系统可以登吗,... 你有没有想过,为什么苹果系统的手机那么受欢迎,而安卓系统的手机却也能在市场上占有一席之地呢?今天,咱...
安卓系统怎么重制系统还原,安卓... 手机用久了是不是感觉卡得要命,想给它来个大变身?别急,今天就来教你怎么给安卓手机重置系统,让它焕然一...
安卓9系统怎样应用分身,轻松实... 你有没有发现,手机里的APP越来越多,有时候一个APP里还要处理好多任务,分身功能简直就是救星啊!今...
获取安卓系统的ip地址,轻松获... 你有没有想过,你的安卓手机里隐藏着一个神秘的IP地址?没错,就是那个能让你在网络世界里找到自己的小秘...
LG彩电安卓系统升级,畅享智能... 你家的LG彩电是不是最近有点儿“闹别扭”,屏幕上时不时地跳出个升级提示?别急,今天就来给你详细说说这...
阴阳师安卓苹果系统,安卓与苹果... 亲爱的玩家们,你是否曾在深夜里,手握手机,沉浸在阴阳师的神秘世界?今天,就让我带你一起探索这款风靡全...