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循环),复用率很高,基本操作都相同,就是稍微有点变化,这样的话特别好理解。

很严谨,新建节点后,必让新建节点的后继为空,而我的代码没有这个。

 

 

 

posted @ 2017-09-26 13:25  allMayMight  阅读(64)  评论(0编辑  收藏  举报