两数逆向相加

问:

给定两个非空链表来存储两个非负整数,位数按照逆序方式存储,每个节点存储单个数字。将两数相加后返回一个新链表。

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);
	}


也没有问题。

发布了25 篇原创文章 · 获赞 26 · 访问量 1143

猜你喜欢

转载自blog.csdn.net/weixin_43810802/article/details/103403706