leetcode系列(1)-- Add Two Numbers解法分析

1.Description

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.

Example

 
 
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.
翻译: 给出两个表示两个非负数整数的 非空 链接列表。数字以 逆序 形式存储, 每个节点都包含一个数字。添加两个数字并将其作为链接列表返回。您可能假定两个数字不包含任何前导零, 但数字0本身除外。
难度:中等

2.以下这种方法是在讨论中见到的最简洁的一种方法
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode preheader(-1), *curr=&preheader;
        int carry=0;
        while(l1||l2||carry) {
            curr->next = new ListNode(((l1?l1->val:0)+(l2?l2->val:0)+carry)%10);
            curr = curr->next;
            carry = ((l1?l1->val:0)+(l2?l2->val:0)+carry)/10;
            l1?l1=l1->next:0;
            l2?l2=l2->next:0;
        }
        return preheader.next;

        
    }
};
另外一种比较清晰的解法:
class Solution {
public:
    ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
        ListNode *res = new ListNode(-1);
        ListNode *cur = res;
        int carry = 0;
        while (l1 || l2) {
            int n1 = l1 ? l1->val : 0;
            int n2 = l2 ? l2->val : 0;
            int sum = n1 + n2 + carry;
            carry = sum / 10;
            cur->next = new ListNode(sum % 10);
            cur = cur->next;
            if (l1) l1 = l1->next;
            if (l2) l2 = l2->next;
        }
        if (carry) cur->next = new ListNode(1);
        return res->next;
    }
};
说明: 这道并不是什么难题,算法很简单,链表的数据类型也不难。就是建立一个新链表,然后把输入的两个链表从头往后撸,每两个相加,添加一个新节点到新链表后面,就是要处理下进位问题。还有就是最高位的进位问题要最后特殊处理一下。

要考虑以下几种情况
1.某一个加数为空,此时需要做一个判断,故采用 l1?l1->val:0l2?l2->val:0来分别表示两个加数,若为空则置为0;
2.请注意该题定义的结点结构体,可以进行初始化运算,所以可以在为新的结点申请存储空间时.就把值写入;
3.求和和进位是在leetcode中比较常见的运算形式,进位的值就是A/10(一般就是0或者1,为了统一运算,就用A/10表示),进位之后剩余的值就是A%10;
4.最后一点就是本题考查的关键了,对链表知识的考察,需要理解清楚,方能灵活运用。

3.链表知识复习

链表分类

链表分为单向链表(Singly linked lis)、双向链表(Doubly linked list)、循环链表(Circular Linked list)。

单向链表(Singly linked lis)

单向链表是最简单的链表形式。我们将链表中最基本的数据称为节点(node),每一个节点包含了数据块和指向下一个节点的指针。


typedef struct node
{
    int val;
    struct node *next;
}Node;

头结点

单向链表有时候也分为有头结点和无头结点。有头结点的链表实现比较方便(每次插入新元素的时候,不需要每次判断第一个节点是否为空),并且可以直接在头结点的数据块部分存储链表的长度,而不用每次都遍历整个链表。

不带头结点的单链表

带头结点的单链表
1.单链表的初始化,即建立一个空链表。
  1. //不带头结点的单链表的初始化  
  2. void LinkedListInit1(LinkedList L)  
  3. {  
  4.   L=NULL;  
  5. }  
  6. //带头结点的单链表的初始化  
  7. void LinkedListInit2(LinkedList L)  
  8. {  
  9.   L=(LNode *)malloc(sizeof(LNode));  
  10.   if(L==NULL)  
  11.   {  
  12.     printf("申请空间失败!");  
  13.     exit(0);  
  14.   }  
  15.   L->next=NULL;  
  16. }  
  //不带头结点的单链表的初始化
  void LinkedListInit1(LinkedList L)
  {
    L=NULL;
  }
  //带头结点的单链表的初始化
  void LinkedListInit2(LinkedList L)
  {
    L=(LNode *)malloc(sizeof(LNode));
    if(L==NULL)
    {
      printf("申请空间失败!");
      exit(0);
    }
    L->next=NULL;
  }

    2.单链表的求表长操作

      单链表的求表长操作需要设定当前指针p和一个计数器j,初始时p指向链表中的第一个结点,p每向下移动一个结点时,j就加1,直到到达p链表的尾部。带头结点的链表,链表长度不包括头结点。
  1. //带头结点的单链表求表长  
  2. int LinkedListLength(LinkedList L)  
  3. {  
  4.   LNode *p;            //p需要声明为LNode类型  
  5.   p=L->next;  
  6.   int j=0;  
  7.   while(p!=NULL)  
  8.   {  
  9.     j++;  
  10.     p=p->next;         //将p向下移动一个结点  
  11.   }  
  12.   return j;  
  13. }  
  //带头结点的单链表求表长
  int LinkedListLength(LinkedList L)
  {
    LNode *p;            //p需要声明为LNode类型
    p=L->next;
    int j=0;
    while(p!=NULL)
    {
      j++;
      p=p->next;         //将p向下移动一个结点
    }
    return j;
  }

    3.单链表获取第i个结点元素的操作

     设定p为当前结点,初始时p指向链表的第一个结点,然后向下移动i,此时p所指向的元素就是需要查找的第i个结点元素。

  1. //带头结点的单链表取元素操作  
  2. LinkedList LinkedListGetINode(LinkedList L, int i)  
  3. {  
  4.   LNode *p;  
  5.   p=L->next;  
  6.   int j=1;  
  7.   while((p!=NULL)&&(j<i))  
  8.   {  
  9.     p=p->next;  
  10.     j++;  
  11.   }  
  12.   return p;  
  13. }  
  //带头结点的单链表取元素操作
  LinkedList LinkedListGetINode(LinkedList L, int i)
  {
    LNode *p;
    p=L->next;
    int j=1;
    while((p!=NULL)&&(j<i))
    {
      p=p->next;
      j++;
    }
    return p;
  }

    4.单链表的定位操作

    查找元素e第一次出现的位置。从链表的第一个结点开始,判断当前结点的值是否等于e,等于则返回该结点的指针,否则继续向后查找,直至到达链表的最后。
  1. //带头结点的单链表定位操作  
  2. LNode LinkedListLocateE(LinkedList L, ElemType e)  
  3. {  
  4.   LNode *p;  
  5.   p=L->next;  
  6.   while((p!=NULL)&&(p->data!=e))  
  7.   {  
  8.     p=p->next;  
  9.   }  
  10.   return p;  
  11. }  
  //带头结点的单链表定位操作
  LNode LinkedListLocateE(LinkedList L, ElemType e)
  {
    LNode *p;
    p=L->next;
    while((p!=NULL)&&(p->data!=e))
    {
      p=p->next;
    }
    return p;
  }

    5.单链表的插入操作

    在结点p之前插入一个新的结点q:对于不带头结点的单链表,结点p的位置有所不同,插入操作有以下两种情况:
    1)在链表的表头插入:
       (1)创建一个新的结点q。
       (2)将此结点的数据域赋值为e,并将它的next指针指向第一个结点,即L。
       (3)将L修改为指向新的结点q。
       操作示意图如下:

                                    
    2)在链表的中间插入
       (1)创建一个新的结点q。
       (2)将此结点的数据域赋值为e,并将它的next指针指向p。
       (3)查找到p的前驱结点pre。
       (4)将pre的next指针指向新创建的结点q。
      操作示意图如下:
                                             

  1. //不带头结点的单链表的插入操作  
  2. void LinkedListInertQE1(LinkedList L, LinkedList p, ElemType e)  
  3. {  
  4.   q=(LNode *)malloc(sizeof(LNode));        //创建一个新的结点q  
  5.   if(q==NULL)  
  6.   {  
  7.     printf("申请空间失败!");  
  8.     exit(0);  
  9.   }  
  10.   q->data=e;  
  11.   
  12.   if(p==L)   //在表头插入  
  13.   {  
  14.     q->next=L;  
  15.     L=q;  
  16.   }  
  17.   else      //在表的中间进行插入  
  18.   {  
  19.     pre=L;  
  20.     while((pre!=NULL)&&(pre->next!=p))           //寻找p的前驱  
  21.        pre=pre->next;  
  22.   
  23.     q->next=pre->next;  
  24.     pre->next=q;  
  25.   }  
  26. }  
  27.   
  28. //带头结点的单链表的插入操作  
  29. void LinkedListInertQE2(LinkedList L, LinkedList p, ElemType e)  
  30. {  
  31.   q=(LNode *)malloc(sizeof(LNode));        //创建一个新的结点q  
  32.   if(q==NULL)  
  33.   {  
  34.     printf("申请空间失败!");  
  35.     exit(0);  
  36.   }  
  37.   q->data=e;  
  38.   
  39.   //插入新的结点  
  40.   pre=L;  
  41.   while((pre!=NULL)&&(pre->next!=p))           //寻找p的前驱  
  42.     pre=pre->next;  
  43.   
  44.   q->next=pre->next;  
  45.   pre->next=q;  
  46. }  
    //不带头结点的单链表的插入操作
    void LinkedListInertQE1(LinkedList L, LinkedList p, ElemType e)
    {
      q=(LNode *)malloc(sizeof(LNode));        //创建一个新的结点q
      if(q==NULL)
      {
        printf("申请空间失败!");
        exit(0);
      }
      q->data=e;

      if(p==L)   //在表头插入
      {
        q->next=L;
        L=q;
      }
      else      //在表的中间进行插入
      {
        pre=L;
        while((pre!=NULL)&&(pre->next!=p))           //寻找p的前驱
           pre=pre->next;

        q->next=pre->next;
        pre->next=q;
      }
    }

    //带头结点的单链表的插入操作
    void LinkedListInertQE2(LinkedList L, LinkedList p, ElemType e)
    {
      q=(LNode *)malloc(sizeof(LNode));        //创建一个新的结点q
      if(q==NULL)
      {
        printf("申请空间失败!");
        exit(0);
      }
      q->data=e;

      //插入新的结点
      pre=L;
      while((pre!=NULL)&&(pre->next!=p))           //寻找p的前驱
        pre=pre->next;

      q->next=pre->next;
      pre->next=q;
    }

      6.单链表的删除操作

       删除链表中的某个元素e,如果e在链表中出现不止一次,将删除第一次出现的e,否则什么也不做。
       用p找到元素e所在的结点:
        1)p是链表中的第一个结点
            (1)将L指向p->next。
            (2)释放p。
         示意图如下:

                                       

         2)p是链表中的其他结点
            (1)找到p的前驱结点pre。
            (2)将pre->next指向p->next。
            (3)释放p。
         示意图如下:

                                                                 

  1. //不带头结点的单链表的删除操作  
  2. void LinkedListDeleteQE1(LinkedList L, LinkedList p, ElemType e)  
  3. {  
  4.    pre=L;  
  5.    while((pre!=NULL)&&(pre->next->data!=e))      //查找元素e的前驱  
  6.        pre=pre->next;  
  7.    p=pre->next;  
  8.   
  9.    if(p!=NULL)                //找到需要删除的结点  
  10.    {  
  11.      if(p==L)                 //删除的是第一个结点  
  12.        L=p->next;  
  13.      else                     //删除的是其他结点  
  14.        pre->next=p->next;  
  15.      free(p);  
  16.    }  
  17. }  
  18. //带头结点的单链表的删除操作  
  19. void LinkedListDeleteQE2(LinkedList L, LinkedList p, ElemType e)  
  20. {  
  21.    pre=L;  
  22.    while((pre!=NULL)&&(pre->next->data!=e))      //查找元素e的前驱  
  23.        pre=pre->next;  
  24.    p=pre->next;  
  25.   
  26.    if(p!=NULL)                //找到需要删除的结点  
  27.    {  
  28.      pre->next=p->next;  
  29.      free(p);  
  30.    }  
  31. }  
     //不带头结点的单链表的删除操作
     void LinkedListDeleteQE1(LinkedList L, LinkedList p, ElemType e)
     {
        pre=L;
        while((pre!=NULL)&&(pre->next->data!=e))      //查找元素e的前驱
            pre=pre->next;
        p=pre->next;

        if(p!=NULL)                //找到需要删除的结点
        {
          if(p==L)                 //删除的是第一个结点
            L=p->next;
          else                     //删除的是其他结点
            pre->next=p->next;
          free(p);
        }
     }
     //带头结点的单链表的删除操作
     void LinkedListDeleteQE2(LinkedList L, LinkedList p, ElemType e)
     {
        pre=L;
        while((pre!=NULL)&&(pre->next->data!=e))      //查找元素e的前驱
            pre=pre->next;
        p=pre->next;

        if(p!=NULL)                //找到需要删除的结点
        {
          pre->next=p->next;
          free(p);
        }
     }

        7.单链表的创建操作

        单链表的创建方法有两种:头插法和尾插法。
        头插法是将新增结点插入第一个结点之前,示意图如下:

                                          
        尾插法是将新增结点插入最后一个结点之后,示意图如下:

                                                       

  1. //用头插法创建带头结点的单链表  
  2. void LinkedListCreateHeadL(LinkedList L, ElemType a[n])  
  3. {  
  4.   L=(LNode *)malloc(sizeof(LNode));  
  5.   if(L==NULL)  
  6.   {  
  7.     printf("申请空间失败!");  
  8.     exit(0);  
  9.   }  
  10.   L->next=NULL;  
  11.   
  12.   for(i=0; i<n; i++)  
  13.   {  
  14.     p=(LNode *)malloc(sizeof(LNode));  
  15.     if(p==NULL)  
  16.     {  
  17.       printf("申请空间失败!");  
  18.       exit(0);  
  19.     }  
  20.   
  21.     p->data=a[i];  
  22.     p->next=L->next;  
  23.     L->next=p;  
  24.   }  
  25. }  
  26. //用尾插法创建带头结点的单链表  
  27. void LinkedListCreateTailL(LinkedList L, ElemType a[n])  
  28. {  
  29.   L=(LNode *)malloc(sizeof(LNode));  
  30.   if(L==NULL)  
  31.   {  
  32.     printf("申请空间失败!");  
  33.     exit(0);  
  34.   }  
  35.   L->next=NULL;  
  36.   tail=L;         //设置尾指针,方便插入  
  37.   
  38.   for(j=0; j<n; j++)  
  39.   {  
  40.     p=(LNode *)malloc(sizeof(LNode));  
  41.     if(p==NULL)  
  42.     {  
  43.       printf("申请空间失败!");  
  44.       exit(0);  
  45.     }  
  46.   
  47.     p->data=a[j];  
  48.     p->next=NULL;  
  49.     tail->next=p;  
  50.     tail=p;  
  51.   }  
  52. }  
    //用头插法创建带头结点的单链表
    void LinkedListCreateHeadL(LinkedList L, ElemType a[n])
    {
      L=(LNode *)malloc(sizeof(LNode));
      if(L==NULL)
      {
        printf("申请空间失败!");
        exit(0);
      }
      L->next=NULL;

      for(i=0; i<n; i++)
      {
        p=(LNode *)malloc(sizeof(LNode));
        if(p==NULL)
        {
          printf("申请空间失败!");
          exit(0);
        }

        p->data=a[i];
        p->next=L->next;
        L->next=p;
      }
    }
    //用尾插法创建带头结点的单链表
    void LinkedListCreateTailL(LinkedList L, ElemType a[n])
    {
      L=(LNode *)malloc(sizeof(LNode));
      if(L==NULL)
      {
        printf("申请空间失败!");
        exit(0);
      }
      L->next=NULL;
      tail=L;         //设置尾指针,方便插入

      for(j=0; j<n; j++)
      {
        p=(LNode *)malloc(sizeof(LNode));
        if(p==NULL)
        {
          printf("申请空间失败!");
          exit(0);
        }

        p->data=a[j];
        p->next=NULL;
        tail->next=p;
        tail=p;
      }
    }

      8.单链表的合并操作

      首先设置3个指针pa、pb、pc, pa和pb分别指向链表La与Lb的当前待比较插入结点,pc指向链表Lc的最后一个结点。当pa->data≤pb->data时,将pa所指的结点插入到pc后面,否则就将pb所指的结点插入到pc后面。最后,当有一个表合并完,将另一个表剩余的结点全插入到pc。

  1. //带头结点的单链表合并操作  
  2. void LinkedListMergeLaLb(LinkedList La, LinkedList Lb, LinkedList Lc)  
  3. {  
  4.   pa=La->next;  
  5.   pb=Lb->next;  
  6.   Lc=La;          //借用表La的头结点作为表Lc的头结点  
  7.   pc=Lc;  
  8.   
  9.   while((pa!=NULL)&&(pb!=NULL))  
  10.   {  
  11.     if(pa->data<=pb->data)  
  12.     {  
  13.       pc->next=pa;  
  14.       pc=pa;  
  15.       pa=pa->next;  
  16.     }  
  17.     else  
  18.     {  
  19.       pc->next=pb;  
  20.       pc=pb;  
  21.       pb=pb->next;  
  22.     }  
  23.   }  
  24.   if(pa!=NULL)  
  25.     pc=pa->next;  
  26.   else  
  27.     pc=pb->next;  
  28.   
  29.   free(pb);    //将Lb的表头结点释放  
  30. }  
    //带头结点的单链表合并操作
    void LinkedListMergeLaLb(LinkedList La, LinkedList Lb, LinkedList Lc)
    {
      pa=La->next;
      pb=Lb->next;
      Lc=La;          //借用表La的头结点作为表Lc的头结点
      pc=Lc;

      while((pa!=NULL)&&(pb!=NULL))
      {
        if(pa->data<=pb->data)
        {
          pc->next=pa;
          pc=pa;
          pa=pa->next;
        }
        else
        {
          pc->next=pb;
          pc=pb;
          pb=pb->next;
        }
      }
      if(pa!=NULL)
        pc=pa->next;
      else
        pc=pb->next;

      free(pb);    //将Lb的表头结点释放
    }

 附录:

       程序实例:尾插法创建单链表

       首先在VS2010中新建Win32 控制台应用程序的项目LinkedList,结果如下:

                                               

       LinkedList.cpp : 定义控制台应用程序的入口点。

  1. // LinkedList.cpp : 定义控制台应用程序的入口点。  
  2.   
  3.     #include "stdafx.h"  
  4.   
  5.     #include<stdio.h>  
  6.     #include<stdlib.h>  
  7.     typedef struct node  
  8.     {  
  9.       int data;  
  10.       struct node *next;  
  11.     }*LinkedList;  
  12.   
  13.     LinkedList LinkedListCreateTailL(int a[8])  
  14.     {  
  15.       LinkedList p, L, tail;  
  16.       int i=0;  
  17.       L=(struct node*)malloc(sizeof(struct node));  
  18.       tail=L;  
  19.   
  20.       for(i=0; i<8; i++)  
  21.       {  
  22.         p=(struct node*)malloc(sizeof(struct node));  
  23.         p->data=a[i];  
  24.         tail->next=p;  
  25.         tail=p;  
  26.       }  
  27.       tail->next=NULL;  
  28.       return L;  
  29.     }  
  30.   
  31.     void LinkedListPrint(LinkedList L)  
  32.     {  
  33.       LinkedList p;  
  34.       p=L->next;  
  35.       while(p!=NULL)  
  36.       {  
  37.         printf("%d ",p->data);  
  38.         p=p->next;  
  39.       }  
  40.     }  
  41.   
  42.     void main()  
  43.     {  
  44.       int a[8], i;  
  45.       LinkedList L;  
  46.       printf("请输入8个列表元素,以回车结束:\n");  
  47.       for(i=0; i<8; i++)  
  48.       {  
  49.         scanf("%d", &a[i]);  
  50.       }  
  51.   
  52.       L=LinkedListCreateTailL(a);  
  53.       LinkedListPrint(L);  
  54.     }  
// LinkedList.cpp : 定义控制台应用程序的入口点。

    #include "stdafx.h"

    #include<stdio.h>
    #include<stdlib.h>
    typedef struct node
    {
      int data;
      struct node *next;
    }*LinkedList;

    LinkedList LinkedListCreateTailL(int a[8])
    {
      LinkedList p, L, tail;
      int i=0;
      L=(struct node*)malloc(sizeof(struct node));
      tail=L;

      for(i=0; i<8; i++)
      {
        p=(struct node*)malloc(sizeof(struct node));
        p->data=a[i];
        tail->next=p;
        tail=p;
      }
      tail->next=NULL;
      return L;
    }

    void LinkedListPrint(LinkedList L)
    {
      LinkedList p;
      p=L->next;
      while(p!=NULL)
      {
        printf("%d ",p->data);
        p=p->next;
      }
    }

    void main()
    {
      int a[8], i;
      LinkedList L;
      printf("请输入8个列表元素,以回车结束:\n");
	  for(i=0; i<8; i++)
      {
        scanf("%d", &a[i]);
      }

      L=LinkedListCreateTailL(a);
      LinkedListPrint(L);
    }
        Ctrl+F5执行以上cpp文件,程序运行截图:

                                           






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值