LeetCode add two numbers
问题描述:
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
就是让你加两个数,最左边是个位,最右边是最高位,计算后返回开始节点。
最开始自己写了个程序,但是感觉不是不好。通过时间52ms,最快是35ms。
package leetCode;
class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
public class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if(l1==null) return l2 ;
else if(l2==null) return l1;
else
{
int length=getLength(l1);
if(getLength(l2)>length)
{
length=getLength(l2);
}
int temp=0;ListNode begin=new ListNode(0);ListNode flag=new ListNode(0);
for(int i=1;i<=length;i++)
{
if(i==1)
{
begin=new ListNode((l1.val+temp+l2.val)%10);
flag=begin;
temp=(l1.val+temp+l2.val)/10;
if((getLength(l1)==1)&(getLength(l2)==1)&(temp!=0))
{
flag.next=new ListNode(temp);
}
}
else if(i==length)
{
flag.next=new ListNode((l1.val+temp+l2.val)%10);
flag=flag.next;
temp=(l1.val+temp+l2.val)/10;
if(temp!=0)
{
flag.next=new ListNode(temp);
}
}
else
{
flag.next=new ListNode((l1.val+temp+l2.val)%10);
flag=flag.next;
temp=(l1.val+temp+l2.val)/10;
}
if(l1.next!=null) l1=l1.next;
else l1=new ListNode(0);
if(l2.next!=null) l2=l2.next;
else l2=new ListNode(0);
}
return begin;
}
}
public static int getLength(ListNode a)
{
ListNode node=a;
int s=1;
while(node.next!=null)
{
s++;
node=node.next;
}
return s;
}}
虽然程序写得很low,但是姑且写写我自己的思路,看看自己到底是哪种low:
1.获得两个数的长度 2.如果有任何一个数为空,那么就返回另一个数(实际不需要判断这种情况) 3.将两个数的较长长度作为循环的次数 4.在循环前设置好进位数int,开始节点,和移动节点 5.循环分为三种情况:第一次循环,最后一次循环,和中间情况 6.第一次循环,需要设置开始节点和移动 7.最后一次,需要额外判断进位是否为1,是就要一位 8.中间情况,就是新建节点,后移节点,更新进位 9.循环更新条件
分析了下,我这算法主要思想:获得两个数的最大长度,然后如果两个数的长度不一样长,那么就相当于把短的那个数缺的数全部变成0了,因为if(l1.next!=null) l1=l1.next; else l1=new ListNode(0);。这样循环的次数就能知道了。但是由于还需要去计算数的长度,所以时间花费多了。
而31ms的算法如下:
public ListNode addTwoNumbers2(ListNode l1, ListNode l2) {
ListNode list1 = l1;//l1,l2传进来就赋值给引用,然后只用引用
ListNode list2 = l2;
ListNode curr = null;
ListNode start = null;//当且仅当两个数都是空,那么start将会返回空
int carry = 0;//进位的值,初始值为0
while(list1 != null && list2!=null)//最普通的情况是两个数都不为空
{
int sum = list1.val+list2.val+carry;//用完carry后归零
carry = 0;//用完要归零,因为如果不归零,程序又没有执行下面的if,那么接下来的循环就会多加进位1
if(sum>=10)
{
carry = 1;//进位设为1,为下次循环使用
sum = sum-10;//加和之后的个位
}
if(curr == null)//如果当前指针为空,那么说明是循环的第一次
{
curr = new ListNode(sum);//产生当前节点,其后继设为空
curr.next =null;
start = curr;//把当前引用赋值给开始引用,之后开始引用不能变
}
else
{
ListNode lastLink = new ListNode(sum);
curr.next = lastLink;
lastLink.next= null;
curr= lastLink;
}
list1 = list1.next;
list2 = list2.next;
}//这个循环结束后,之后就是list1或者list2的引用为空,如果都为空,也就是两个数长度相同时,
//就不会进入下面两个white循环了
//因为题目已经说了是two non-empty linked lists了,所以下面两个循环不用判断
//当传进来的两个数,其中一个为空时,就直接返回另一个的情况,要加这种判断也很简单
//在上面循环加个计数器,如果计数器等于初值,那么就是特殊情况
while(list1!=null)
{
int sum = carry+list1.val;//此时因为list2已经到尾,所以就不加list2的值了
carry=0;
if(sum>=10)
{
carry = 1;
sum = sum-10;
}
ListNode lastLink = new ListNode(sum);
curr.next = lastLink;
lastLink.next= null;
curr= lastLink;
list1 = list1.next;
}
while(list2!=null)
{
int sum = carry+list2.val;
carry=0;
if(sum>=10)
{
carry = 1;
sum = sum-10;
}
ListNode lastLink = new ListNode(sum);
curr.next = lastLink;
lastLink.next= null;
curr= lastLink;
list2= list2.next;
}
if(carry==1)//最后当节点都遍历到尾部时,判断最后一位要不要多一位
{
ListNode lastLink = new ListNode(carry);
curr.next = lastLink;
lastLink.next= null;
curr= lastLink;
}
return start;
}
该算法的优点在于:
首先不需要知道循环的次数。
然后就是思路很清晰,对于算法的运行情况的分类分得很好。主要理解我都在注释里写了。还有就是,对于情况的分类,每种分类里的代码(3个while循环),复用率很高,基本操作都相同,就是稍微有点变化,这样的话特别好理解。
很严谨,新建节点后,必让新建节点的后继为空,而我的代码没有这个。