问:
给定两个非空链表来存储两个非负整数,位数按照逆序方式存储,每个节点存储单个数字。将两数相加后返回一个新链表。
example:
input:2 -> 4 -> 3 + 5 -> 6 -> 4
output:7 -> 0 -> 8
reason:342+465=807
思路:
当然,我们要写一个链表类,有点像LinkedList,这样子,我们才能把一个个节点串联起来。
按照题目中数字连接的样式(2 -> 4 -> 3 ),我们可以决定写一个单向的非循环链表。
在这个链表类中,我们需要一个内部类,以此来存储数据,因为题中说,每个节点单独存储一个数字。
向链表中添加数字的方法我们可以叫它add方法,原理就是尾部追加元素。
然后要考虑最后的加法问题,也就是说,根据题目的规则,先加入的数先参与运算。题目示例的两个链表,2和5首先加入,它们也是首先参与加法运算的。为此,我们也要封装一个方法,来取出头部元素。
操作:
我们的类,叫做MyList:
一个链表,要有头有尾,为了方便观察,我还加入了size。
private Node head;
private Node last;
private int size;
Node就是我们要写的内部类,就是用来存单个数据的。
private class Node {
E data;
Node next;
Node prev;
Node(E e) {
data = e;
}
}
data是当前Node的数据,一个Node里面,当然还保存着上一个Node(prev)的信息以及下一个Node(next)的信息。如此这般,一个个Node才能串联起来。
现在来写尾部追加元素的方法:
public boolean add(E e) {
Node l = last;
Node newNode = new Node(e);
last = newNode;
if (l == null) {
head = newNode;
last = newNode;
} else {
l.next = newNode;
newNode.prev = l;
}
size++;
return true;
}
往尾部追加元素,一定会是成功的,所以我一直返回true。
我们考虑最后一个节点(last)。如果原来就没有最后的节点(原来的链表为空),那么新加入的节点就既是头,又是尾。
如果原来最后一个节点就有值,那么就一直链下去。
说好要写单向的链表,又写成双向的了,不过这个问题都不大。
然后就是取出头部元素了。
public E getHead() {
Node h = head;
if(h == null) {
throw new NoSuchElementException();
}else {
E item = h.data;
head = h.next;
h = null;
size--;
return item;
}
}
我们把取出的当前头部data返回,并且让当前头部指向null,然后size减一。
完整的链表类:
(为了好显示,我还加入了toString方法)
package add_two_numbers;
import java.util.NoSuchElementException;
public class MyList<E> {
private Node head;
private Node last;
private int size;
private class Node {
E data;
Node next;
Node prev;
Node(E e) {
data = e;
}
}
public int size() {
return size;
}
public boolean add(E e) {
Node l = last;
Node newNode = new Node(e);
last = newNode;
if (l == null) {
head = newNode;
last = newNode;
} else {
l.next = newNode;
newNode.prev = l;
}
size++;
return true;
}
public E getHead() {
Node h = head;
if(h == null) {
throw new NoSuchElementException();
}else {
E item = h.data;
head = h.next;
h = null;
size--;
return item;
}
}
public String toString() {
if (head == null) {
return "[]";
}
StringBuilder builder = new StringBuilder("[");
builder.append(head.data);
Node node = head.next;
while (node != null) {
builder.append("-> ").append(node.data);
node = node.next;
}
builder.append("]");
return builder.toString();
}
}
现在我们来写两数相加方法:
public static MyList<Integer> add_two_numbers(MyList<Integer> list1, MyList<Integer> list2) {
MyList<Integer> ans = new MyList<Integer>();
int carry = 0;
while(list1.size() > 0 || list2.size() > 0) {
int sum = list1.getHead() + list2.getHead() + carry;
carry = sum / 10;
ans.add(sum % 10);
}
if(carry > 0) {
ans.add(carry);
}
return ans;
}
首先,依据题目要求,我们还是要返回一个链表。
我们分别取出两个链表的当前头元素然后相加。
这里有个问题,就是加法可能出现满十进一的情况。
我们用变量carry来携带这个进位。
跳出while循环后,实际上已经完成了每个位置的数的相加,但是还可能出现进位的情况,比如说,两个三位数相加,很可能是一个四位数,最后的进位需要加入到链表中,保证加法的准确。
测试:
public static void main(String[] args) {
MyList<Integer> list1 = new MyList<Integer>();
list1.add(2);
list1.add(4);
list1.add(3);
MyList<Integer> list2 = new MyList<Integer>();
list2.add(5);
list2.add(6);
list2.add(4);
MyList<Integer> ans = add_two_numbers(list1, list2);
System.out.println(ans);
}
我们的结果和示例中一样。
检查一下大数相加的情况:
public static void main(String[] args) {
MyList<Integer> list1 = new MyList<Integer>();
list1.add(8);
list1.add(4);
list1.add(8);
MyList<Integer> list2 = new MyList<Integer>();
list2.add(5);
list2.add(6);
list2.add(4);
MyList<Integer> ans = add_two_numbers(list1, list2);
System.out.println(ans);
}
也没有问题。