2. 两数相加(Java实现)
题目:给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
看了大佬们的思路后重新整理的代码
思路:
- 将两个链表看成是相同长度的进行遍历,如果一个链表较短则在前面补0,eg: 987 + 23 = 987 + 023 = 1010
- 每一位计算的同时需要考虑上一位的进位问题,而当前位计算结束后同样需要更新进位值
- 如果两个链表全部遍历完毕后,进位值为 1,则在新链表最前方添加节点 1。这里解释一下,因为最终你的结果是按链表一位一位返回的,所以不管中间你有多少进位,这些进位你都在计算时加进去了,直到最后一位如果有进位的话,就要新插入一个结点(val=1)。
- 最后构造返回结果的链表。说白了就是在Java中的链表操作,这一步一定要深刻理解一个问题:Java中的对象与对象的引用。如果觉得不太清楚,请看浅谈Java中的对象和引用。简单来说,我们先创建一个头对象,两个引用head,temp都指向这个头。接下来,head不动,temp作为工具人去链接新对象(结点)(temp.next=newNode;),然后指向链表尾部的结点*(temp = temp.next;)*。head一直指向链表头,用来返回结果。(注:因为头结点不是结果的一部分,所以返回的是head.next)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
//创建一个头结点对象
ListNode head = new ListNode(0);
//两个引用head和temp都指向这个对象,head用来指向链表头,temp是工具人(有点像C语言中移动的指针)
ListNode temp = head;
//进位标志carry
int carry = 0;
//每一位的求和sum
int sum =0;
while(l1!=null||l2!=null){
int x = null==l1?0:l1.val;
int y = null==l2?0:l2.val;
sum = x+y+carry;
//计算本位是否有进位
carry = sum/10;
//插入本位的计算结果
ListNode newNode = new ListNode(sum%10);
//将新结点插入到链表中
temp.next=newNode;
//指针移动,temp一直指向链表的尾部
temp = temp.next;
if(l1 != null)
l1 = l1.next;
if(l2 != null)
l2 = l2.next;
}
//最高位如果有进位,则插入一个新结点(val=1)
if(carry>0){
temp.next = new ListNode(carry);
}
//head指向的头结点不是结果的一部分,真正的返回结果从head.next开始
return head.next;
}
}
- 结果:
- 相信很多人和我一样看着head.next觉得很不爽,为什么要搞一个没用的头结点,我希望我的链表就是结果,而不是再去掉一个头结点。于是我将上面的代码稍微修改了一点,解决了上面的问题,其实很简单,加个判断就行了。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode head = null;
ListNode temp = null;
//进位标志carry
int carry = 0;
//每一位的求和sum
int sum =0;
while(l1!=null||l2!=null){
int x = null==l1?0:l1.val;
int y = null==l2?0:l2.val;
sum = x+y+carry;
//计算本位是否有进位
carry = sum/10;
//插入本位的计算结果
ListNode newNode = new ListNode(sum%10);
//将新结点插入到链表中
//如果头结点为null,就将head指向新创建的结点
if(head==null){
head = newNode;
temp = head;
}else{
temp.next=newNode;
temp = temp.next;
}
if(l1 != null)
l1 = l1.next;
if(l2 != null)
l2 = l2.next;
}
//最高位如果有进位,则插入一个新结点(val=1)
if(carry>0){
temp.next = new ListNode(carry);
}
//head指向的头结点不是结果的一部分,真正的返回结果从head.next开始
return head.next;
}
}
- 结果:
记录下我自己的不成熟的想法
看到这个题目,我最先想到的就是,把给的输入的两个链表l1和l2转化为整型数,相加得到结果,再将结果转为链表返回。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
StringBuilder str1 = new StringBuilder();
StringBuilder str2 = new StringBuilder();
//遍历l1链表,存储到str1中
while(l1!=null){
str1.append(l1.val);
l1=l1.next;
}
//遍历l2链表,存储到str2中
while(l2!=null){
str2.append(l2.val);
l2=l2.next;
}
try{
//将l1、l2中字符串逆序后准成int类型
int r1 = Integer.parseInt(str1.reverse().toString());
int r2 = Integer.parseInt(str2.reverse().toString());
//求和得到结果
int r = r1+r2;
// System.out.println(r1+" + "+r2+"="+" "+r);
//将结果r从低位到高位插入到结果链表中
ListNode head = null;
if(r==0){
return new ListNode(0);
}
while(r!=0){
ListNode newNode = new ListNode(r%10);
if(head ==null) {
head = newNode;
}else {
ListNode tmp = head;
while(tmp.next!=null) {
tmp = tmp.next;
}
tmp.next = newNode;
}
r = r/10;
}
return head;
}catch(Exception e){
}
return null;
}
}
- 结果:
这里面的问题是:用int型来存储计算结果,但测试用例的值远大于int型所能表示的范围。我看了一些帖子,据说long也不行,用 BigDecimal 可以通过。