链表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:反转之三—生成相加链表的主要内容,如果未能解决你的问题,请参考以下文章