题目:两数之和
给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]
ListNode类需要自己实现
public class ListNode {
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
//print方法便于最后查看结果
public void print() {
System.out.print(this.val);
if (this.next != null) {
System.out.print("-->");
this.next.print();
}
}
}
方法一:官方给的方法
学习算法时知道链表,也知道Java有链表实现类。但从没有用过自己写结点组成链表类这种。
最开始我不明白他说的逆序存储是什么意思,后来发现就是存储的链表头节点是个位。按243存储的顺序,他其实是数字342。
也就意味着,这俩个链表相同位置结点(相加满10就要往新链表对应位置的下一个结点进1)。
a表示进位的值(由于每个结点存放一位数,所以a只能是0或者1,1就表示上一个结点以满10需要进位)。俩结点(n1,n2)相加新链表相同位置为(n1+n2+a)%10,进位为(n1+n2+a)/10。
俩链表结点不同,少的用0补齐。
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode head = null;
ListNode tail = null;
int a = 0;
//循环结束条件l1和l2都为空
while (l1 == null && l2 == null) {
//结点少的用0补齐
int n1 = l1 != null ? l1.val : 0;
int n2 = l2 != null ? l2.val : 0;
//新结点相同位置的值
int sum = n1 + n2 + a;
if (head == null) {
//确认第一个结点,head结点
//head结点主要是确认第一个节点的位置,tail结点不断指向下一个增加新节点
head = tail = new ListNode(sum % 10);
} else {
//增加一个新的结点,tail指向新结点
tail.next = new ListNode(sum % 10);
tail = tail.next;
}
//保留进位数
a = sum / 10;
//这样写也可以
//a = sum >= 10 ? 1 : 0; sum大于1等于10进位
//l1指向下一个节点,没有下一个结点则为空,在下一次循环下个节点赋值0。
//若为null就表示l1是短的那条链表需要用0补齐
if (l1 != null) {
l1 = l1.next;
}
//l2指向下一个节点
if (l2 != null) {
l2 = l2.next;
}
}
//防止l1和l2最后一个结点相加,仍需要进位。这时增加一个新节点保存进位数
if (a > 0) {
tail.next = new ListNode(a);
}
return head;
}
}
这题感觉挺简单的,只需要注意进位。
方法二:递归
当时评论区看到的一位大神写的自己从写了一遍,同样情况下好像递归比循环消耗性能。
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
return test(l1,l2,0);
}
//i表示进位数,每次调用生成一个相同位置的结点
public ListNode test(ListNode l1, ListNode l2, int i) {
//递归停止条件l1和l2为空,l1和l2最后一位相加没有进位
if (l1 == null && l2 == null & i ==0){
return null;
}
//新链表相同位置的值
int sum = (l1 ==null ? 0 : l1.val)+(l2 ==null ? 0 : l2.val)+ i;
ListNode node = new ListNode(sum%10);
//下一个结点进入下一次循环确认
node.next = test(l1 != null ? l1.next: null, l2 != null ? l2.next: null, sum/10);
return node;
}
}
感觉递归和官方给的循环基本一样。退出循环的条件也相同,我个人感觉递归相反没有循环容易理解,我第一反应很少是会用递归解决问题。
俩种方法我都提交了运行时间都是2ms,递归内存消耗多了一点点。
新学习到的东西(总结):
会编写ListNode类,实线链表。
有时间去看下LinkedList和List的源码
如果有什么错误或者不合理的地方请告诉我,我会即使修改