目录
一、题目
两链表相加问题, 满10向next进1
例如: (4->2->1) +(6->3->7),
得到结果为: 0->6->8
得到结果860
二、思路一
将链表二中的数据加到链表一上,然后返回链表一,如果链表一的除了末位的满10那么进1。
我们可以给每一个链表中的所有节点放入到一个 Node [] table里, 然后通过fo循环遍历两个table。
此方式利用牺牲空间的方式初始化2个数组,只用一个for循环就能实现两个链表相加。
private static SumOfTwoLinkedList addLinkedList(SumOfTwoLinkedList one, SumOfTwoLinkedList two) {
for (int i = 0; i < one.table.length; i++) {
if (one.table[i] != null) {
// 两条链表中对应位置值相加
Integer sum = (Integer) one.table[i].data + (Integer) two.table[i].data;
boolean overflow = false;
if (sum >= 10 && i + 1 <= one.table.length) {
// 是否进位
overflow = true;
// 最后一位不支持进位
if (i + 1 == one.table.length) {
throw new RuntimeException("illegal params! check lists");
}
//下一位+1
one.table[i + 1].data = (Integer) one.table[i + 1].data + 1;
}
if (overflow) {
// 当前位归0
one.table[i].data = 0;
continue;
}
one.table[i].data = sum;
}
}
return one;
}
完整代码
package leetcode100;
/**
* @decription:
* @author: zhengbing.zhang
* @date: 2021/7/12 17:40
* 两链表相加问题, 满10进1
* 例如: (4->2->1) +(6->3->7),
* 得到结果为: 0->6->8
* 得到结果860
* 假设链表的长度是相等的, 不考虑表尾溢出的情况
*/
public class SumOfTwoLinkedList {
private static SumOfTwoLinkedList addLinkedList(SumOfTwoLinkedList one, SumOfTwoLinkedList two) {
for (int i = 0; i < one.table.length; i++) {
if (one.table[i] != null) {
// 两条链表中对应位置值相加
Integer sum = (Integer) one.table[i].data + (Integer) two.table[i].data;
boolean overflow = false;
if (sum >= 10 && i + 1 <= one.table.length) {
// 是否进位
overflow = true;
// 最后一位不支持进位
if (i + 1 == one.table.length) {
throw new RuntimeException("illegal params! check lists");
}
//下一位+1
one.table[i + 1].data = (Integer) one.table[i + 1].data + 1;
}
if (overflow) {
// 当前位归0
one.table[i].data = 0;
continue;
}
one.table[i].data = sum;
}
}
return one;
}
public static void main(String[] args) {
SumOfTwoLinkedList l1 = new SumOfTwoLinkedList();
SumOfTwoLinkedList l2 = new SumOfTwoLinkedList();
Node oneHead = new Node(3);
oneHead.addNode(new Node(7)).addNode(new Node(1));
Node twoHead = new Node(6);
twoHead.addNode(new Node(3)).addNode(new Node(6));
// Node one = new Node(3, new Node(7, new Node(1, null)));
// Node two = new Node(6, new Node(3, new Node(8, null)));
l1.initLinkList(oneHead);
l2.initLinkList(twoHead);
SumOfTwoLinkedList result = addLinkedList(l1, l2);
System.out.println(result.traverseLinkList());
}
Node[] table;
/**
* 初始化链表
*
* @param head
*/
public void initLinkList(SumOfTwoLinkedList.Node head) {
int index = 0;
this.table = new Node[head.length()];
while (head.next != null) {
this.table[index] = head;
head = head.next;
index++;
}
this.table[index] = head;
}
public String traverseLinkList() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < table.length; i++) {
Object obj = this.table[i];
if (obj != null) {
sb.append(((Node) obj).getData());
sb.append("->");
}
}
sb.append("NULL");
return sb.toString();
}
static class Node {
private Object data;
private Node next;
public Node(Object data) {
this.data = data;
}
public Node addNode(Node node) {
this.next = node;
return node;
}
public Object getData() {
return this.data;
}
/**
* 返回链表长度
*/
public Integer length() {
Node current = this;
int count = 1;
while (current.next != null) {
count++;
current = current.next;
}
return count;
}
public String traverse() {
return this.data + "->" + (this.next == null ? "Null" : this.next.traverse());
}
}
}
输入:
3——>7——>1——>NULL
6——>3——>6——>NULL
执行结果:
此方式的时间复杂度是o(n), 但是空间复杂度o(m+n),需要利用额外的空间创建LinkedList。
三、思路二
大思路:
不创建额外的链表,我们只需要一个单链表去接收2个链表节点叠加后的结果, 然后返回新的单链表即可。
实现原理:
1) 两个链表相同位置的节点数据相加可能会产生进位,如果尾节点也进位了,那么需要创建新的节点去接收进位。
2) 如何计算当前位(节点)的值?
可以用 (x+y) %10 的结果作为当前位的值,但是这样的话要考虑到进位的情况,那么就是(carry+x+y)%10。
3) 如何判断进位?
可以根据 两个节点的和除以10是否等于0来判断,如果两数之和除以10等于0,那么表示没有进位,如果等于1,那么表示产生进位。
比如: 链表1 中的节点x = 5, 链表2中的节点y=3, x+y/10=0。 这样是不会产生进位的。
由于之前的进位carry会影响到当前位两个节点的累加和,因此需要用(carry+x+y)/10 来判断进位。
package leetcode100;
import java.util.List;
/**
* @decription:
* @author: zhengbing.zhang
* @date: 2021/7/20 15:49
* l1: 4->2->1
* l2: 6->3->7
*/
public class SumOfTwoLinkedList01 {
static class ListNode {
ListNode next;
Object value;
public ListNode(ListNode next, Object value) {
this.next = next;
this.value = value;
}
public ListNode(Object value) {
this.value = value;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(value);
while (next != null) {
sb.append("->");
sb.append(next.value);
next = next.next;
}
return sb.toString();
}
}
public static ListNode addTwoListNodes(ListNode l1, ListNode l2) {
ListNode dumpHead = new ListNode(0);
ListNode p = l1, q = l2, curr = dumpHead;
// 进位
int carry = 0;
while (p != null || q != null) {
int x = p.value == null ? 0 : (int) p.value;
int y = q.value == null ? 0 : (int) q.value;
int sum = carry + x + y;
carry = sum / 10;
curr.next = new ListNode(sum % 10);
// 不断叠加curr
curr = curr.next;
if (p != null) {
p = p.next;
}
if (q != null) {
q = q.next;
}
}
if (carry > 0) {
curr.next = new ListNode(carry);
}
// head节点没有存值
return dumpHead.next;
}
public static void main(String[] args) {
ListNode tail01 = new ListNode(null, 1);
ListNode node01 = new ListNode(tail01, 2);
ListNode l1 = new ListNode(node01, 4);
ListNode tail02 = new ListNode(null, 8);
ListNode node02 = new ListNode(tail02, 7);
ListNode l2 = new ListNode(node02, 6);
ListNode result = addTwoListNodes(l1, l2);
System.out.println(result);
}
}
输入:
l1: 4->2->1
l2: 6->7->8
打印结果: 0->0->0->1
此方法的时间复杂度为: o(max(m,n)) 其中m,n为链表的长度。空间复杂度为o(max(m+n))+1, 因为头节点没有存值,占了一个位,由于存next后面的值。
如果两链表长度不相等,那么也可以合并成为一个新的节点,因为可以给空节点初始化一个为0的值。
int x = (p.value == null) ? 0 : (int) p.value;