链表9:反转之三—生成相加链表

Posted 纵横千里,捭阖四方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链表9:反转之三—生成相加链表相关的知识,希望对你有一定的参考价值。

相加相链表是基于链表构造的一种特殊题,反转只是其中的一部分。这个题还存在进位等的问题,因此看似简单,但是手写成功并不容易,这个题目在LeetCode中我没找到原题,但是在很多材料里有,而且笔者也确实曾经遇到过,所以我们就来研究一下。

题目要求是这样的:

假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。

给定两个这种链表,请生成代表两个整数相加值的结果链表。

例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。

示例:

输入:[9,3,7],[6,3]返回值:{1,0,0,0}

 分析,这个题目的难点在于存放是从最高位向最低位开始的,但是因为低位会产生进位的问题,计算的时候必须从最低位开始。所以我们必须想办法将链表节点的元素反转过来,如下图所示:

怎么反转呢?首先想到可以先用栈来将两个链表分别反转,然后再计算。当你将思路说出来之后,面试官通过会说:“栈要开辟O(n)的空间,你有只需要O(1)空间的方法吗?”。其实言外之意是栈太简单了,那这时候只能用链表反转来做了。

不过呢,为了充分思考,两种方式我们都看一下。

方法1:使用栈实现

思路是先将两个链表的元素分别压栈,然后再一起出栈,将两个结果分别计算。之后对计算结果取模,模数保存到新的链表中,进位保存到下一轮。

完成之后再进行一次反转就行了。

我们知道在链表插入有头插法和尾插法两种。头插法就是每次都将新的结点插入到head之前。而尾插法就是将新结点都插入到链表的表尾。两者的区别是尾插法的顺序与原始链表是一致的,而头插法与原始链表是逆序的,所以上面最后一步如果不想进行反转,可以将新结点以头插法。

import java.util.*;/* * public class ListNode { *   int val; *   ListNode next = null; * } */public class Solution {    public ListNode addInList (ListNode head1, ListNode head2) {          Stack<ListNode> st1 = new Stack<ListNode>();          Stack<ListNode> st2 = new Stack<ListNode>();        while(head1!=null){            st1.push(head1);            head1=head1.next;        }        while(head2!=null){            st2.push(head2);            head2=head2.next;        }        ListNode newHead=new ListNode(-1);        int carry=0; //这里设置carry!=0,是因为当st1,st2都遍历完时,如果carry=0,就不需要进入循环了while(!st1.empty()||!st2.empty()||carry!=0){    ListNode a=new ListNode(0);     ListNode b=new ListNode(0);    if(!st1.empty())    {        a=st1.pop();    }    if(!st2.empty())    {        b=st2.pop();    }    //每次的和应该是对应位相加再加上进位    int get_sum=a.val+b.val+carry;    //对累加的结果取余    int ans=get_sum%10;    //如果大于0,就进位    carry=get_sum/10;    ListNode cur=new ListNode(ans);     cur.next=newHead.next;    //每次把最新得到的节点更新到neHead.next中    newHead.next=cur;}return newHead.next;   }}

方法2:使用链表反转实现

如果不用栈,那只能用链表反转了,先将两个链表分别反转,最后计算完之后再将结果反转,一共需要三次。进位等的处理与上面差不多。

public class Solution {    /**     *      * @param head1 ListNode类      * @param head2 ListNode类      * @return ListNode类     */    public ListNode addInList (ListNode head1, ListNode head2) {        head1 = reverse(head1);        head2 = reverse(head2);        ListNode head = new ListNode(-1);        ListNode cur = head;        int carry = 0;        while(head1 != null || head2 != null) {            int val = carry;            if (head1 != null) {                val += head1.val;                head1 = head1.next;            }            if (head2 != null) {                val += head2.val;                head2 = head2.next;            }            cur.next = new ListNode(val % 10);            carry = val / 10;            cur = cur.next;        }        if (carry > 0) {            cur.next = new ListNode(carry);        }        return reverse(head.next);    }    private ListNode reverse(ListNode head) {        ListNode cur = head;        ListNode pre = null;        while(cur != null) {            ListNode temp = cur.next;            cur.next = pre;            pre = cur;            cur = temp;        }        return pre;    }}

上面我们直接调用了反转函数,这样代码写起来就容易很多,如果你没手写过反转,所有功能都是在一个方法里,那复杂度要高好几个数量级,甚至自己都搞不清楚了。

可见将基础算法掌握好是多么重要。

以上是关于链表9:反转之三—生成相加链表的主要内容,如果未能解决你的问题,请参考以下文章

leetcode-两个链表生成相加链表-76

算法总结之 两个链表生成相加链表

链表相加(NC40/考察次数Top24/难度中等)

两数相加(链表)

牛客Top200---链表相加(java详解)

LeetCode之两数相加反转链表少箭射球二叉树