题解 | #两个链表生成相加链表#

两个链表生成相加链表

http://www.nowcoder.com/practice/c56f6c70fb3f4849bc56e33ff2a50b6b

题目思路:
假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。
我们知道题目已经限定了每个节点的值都不为负数了,所以我们就可以不考虑符号的问题了,那么就很简单了。
我们先看一下题目给的例子:

例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。
从这个例子我们可以得到:
1、两个链表的长度可能不等,需要对齐
2、相加后可能需要进位
对齐进位
因为我们无法保证两个链表长度一致,所以我们干脆从后往前对齐,跟我们整数再做加法一样

图片说明

方法一:反转链表
所以我们的入手则是对链表进行对齐,我们可以看到上面的图片,我们都是从后面开始对齐与计算的,所以很容易想到反转链表后进行相加。

public ListNode addInList (ListNode head1, ListNode head2) {
        // 进行判空处理
        if(head1 == null)
            return head2;
        if(head2 == null){
            return head1;
        }
        // 反转h1链表
        head1 = reverse(head1);
        // 反转h2链表
        head2 = reverse(head2);
        // 创建新的链表头节点
        ListNode head = new ListNode(-1);
        ListNode nHead = head;
        // 记录进位的数值
        int tmp = 0;
        while(head1 != null || head2 != null){
            // val用来累加此时的数值(加数+加数+上一位的进位=当前总的数值)
            int val = tmp;
            // 当节点不为空的时候,则需要加上当前节点的值
            if (head1 != null) {
                val += head1.val;
                head1 = head1.next;
            }
            // 当节点不为空的时候,则需要加上当前节点的值
            if (head2 != null) {
                val += head2.val;
                head2 = head2.next;
            }
            // 求出进位
            tmp = val/10;
            // 进位后剩下的数值即为当前节点的数值
            nHead.next = new ListNode(val%10);
            // 下一个节点
            nHead = nHead.next;

        }
        // 最后当两条链表都加完的时候,进位不为0的时候,则需要再加上这个进位
        if(tmp > 0){
            nHead.next = new ListNode(tmp);
        }
        // 重新反转回来返回
        return reverse(head.next);
    }

    // 反转链表
    ListNode reverse(ListNode head){
        if(head == null)
            return head;
        ListNode cur = head;
        ListNode node = null;
        while(cur != null){
            ListNode tail = cur.next;
            cur.next = node;
            node = cur;
            cur = tail;
        }
        return node;
    }

复杂度分析:
时间复杂度:方法一和二都为O(n)。取决于链表的长度。
空间复杂度:方法一没有用到额外的空间,所以为O(1)。

方法二:使用辅助栈
上一个方式是直接对原来的两个链表进行了反转,这个方法则是借助了栈的先进后出的特性来充当链表的反转,因为我们其实是想从两个链表的尾部进行开始操作,所以我们干脆直接将两条链表的结点放进栈中,然后依次出栈操作即可,然后相加完后采用头插法即可得到最终的链表。

public class Solution {
    /**
     * 
     * @param head1 ListNode类 
     * @param head2 ListNode类 
     * @return ListNode类
     */
    public ListNode addInList (ListNode head1, ListNode head2) {
        // write code here
        if(head1 == null)
            return head2;
        if(head2 == null){
            return head1;
        }
        // 使用两个辅助栈,利用栈先进后出,相当于反转了链表
        Stack<ListNode> stack1 = new Stack<>();
        Stack<ListNode> stack2 = new Stack<>();
        ListNode p1=head1;
        ListNode p2=head2;
        // 将两个链表的结点入栈
        while(p1!=null){
            stack1.push(p1);
            p1=p1.next;
        }
        while(p2!=null){
            stack2.push(p2);
            p2=p2.next;
        }
        // 进位
        int tmp = 0;
        // 创建新的链表头节点
        ListNode head = new ListNode(-1);
        ListNode nHead = head.next;
        while(!stack1.isEmpty()||!stack2.isEmpty()){
            // val用来累加此时的数值(加数+加数+上一位的进位=当前总的数值)
            int val = tmp;
            // 栈1不为空的时候,弹出结点并累加值
            if (!stack1.isEmpty()) {
                val += stack1.pop().val;
            }
            // 栈2不为空的时候,弹出结点并累加值
            if (!stack2.isEmpty()) {
                val += stack2.pop().val;
            }
            // 求出进位
            tmp = val/10;
            // 进位后剩下的数值即为当前节点的数值
            ListNode node = new ListNode(val%10);
            // 将结点插在头部
            node.next = nHead;
            nHead = node;
        }
        if(tmp > 0){
            // 头插
            ListNode node = new ListNode(tmp);
            node.next = nHead;
            nHead = node;
        }
        return nHead;
    }
}

复杂度分析:
时间复杂度:方法一和二都为O(n)。取决于链表的长度。
空间复杂度:方法一没有用到额外的空间,所以为O(1),方法二用了栈则为O(n)。

CS-Review 文章被收录于专栏

本专栏记录本人维护的仓库( cs-review.cn )分类刷题解法~

全部评论
解法一,每次循环都新创建一个节点,空间复杂度为O(1)?
7
送花
回复
分享
发布于 2022-04-08 20:13
复制,粘贴,不愧是我
2
送花
回复
分享
发布于 2023-01-05 16:26 香港
秋招专场
校招火热招聘中
官网直投
java代码是不是写错了?
1
送花
回复
分享
发布于 2022-07-26 00:30
思路清晰,注释到位,真好
点赞
送花
回复
分享
发布于 2022-03-26 15:19
你这搞复杂了,链表1换算成数字937,链表2是63
点赞
送花
回复
分享
发布于 2022-08-31 10:29 广东
反转列表存在问题,或者必须加前提,两个链表不存在公共节点,否则结果不对,例如链表1为1->2-> 3,链表2为4->2->3。其中2、3为公共节点。使用反转的话,结果不是123+423,而是124+324;另外,修改传入的原始数据,是很不好的编程习惯。
点赞
送花
回复
分享
发布于 2022-11-28 18:54 上海
第一种方法new创建节点,空间复杂度还是O(n),利用较长链表存储可能好一些,最多再创建一个最高位节点
点赞
送花
回复
分享
发布于 2023-03-02 14:11 上海
值不限定在0-9的整数可就麻烦好多
点赞
送花
回复
分享
发布于 2023-08-01 15:39 北京
或者可以先相加再反转链表
点赞
送花
回复
分享
发布于 2023-08-09 15:02 广东
方法2后面那个iftemp>0那一步是为啥呀,前面不是已经把它头***去了吗
点赞
送花
回复
分享
发布于 2023-08-15 12:28 北京
方法一用较长链表存储才是 O(1),现在这个很明显 O(n)呀
点赞
送花
回复
分享
发布于 2023-09-14 10:54 湖北
方法一里面直接使用头插法创建新的链表就,结尾就不需要反转链表了。
点赞
送花
回复
分享
发布于 01-02 02:05 广东

相关推荐

62 8 评论
分享
牛客网
牛客企业服务