zoukankan      html  css  js  c++  java
  • LeetCode:Add Two Numbers

    题目链接

    You are given two linked lists representing two non-negative numbers. 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.

    Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
    Output: 7 -> 0 –> 8

    大整数加法


    注意:链表中,整数的低位在前                       本文地址

    /**
     * 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) {
            int carryBit = 0;
            ListNode tmpHead(0), *res = &tmpHead;
            while(l1 && l2)
            {
                l1->val += (l2->val + carryBit);
                carryBit = l1->val / 10;
                l1->val %= 10;
                res->next = l1;
                res = l1;
                
                l1 = l1->next;
                l2 = l2->next;
            }
            ListNode *p = (l1 == NULL ? l2 : l1); //此时l1,l2至多一个不为NULL
            while(p)
            {
                if(carryBit == 0)
                {
                    res->next = p;
                    break;
                }
                else
                {
                    p->val += carryBit;
                    carryBit = p->val / 10;
                    p->val %= 10;
                    res->next = p;
                    res = p;
                }
                p = p->next;
            }
            if(carryBit != 0)res->next = new ListNode(carryBit);
            
            return tmpHead.next;
        }
    };


    如果链表存储整数时,高位在前,该如何处理。

    1、最简单的想法是,可以先把链表反转,然后调用上面的算法,最后把结果反转。

    2、可不可以从高位向低位方向处理呢?我们知道进位是从低位传向高位的,如果从高位向低位方向计算,当计算到某一位需要进位时,有没有办法知道该进位传递到前面的哪一位呢?从以下几个例子来看:

    image

    从最高位到最低位我们依次记为第 1,2…,7位。图中红色标记的位置是:下一次需要进位时,进位的1放置的位子

    第1位相加,结果为12,需要进位,这个进位放到第0位;同时标记第1位为下一次的进位标志

    第2位相加,结果为3,不需要进位;标记第2位为下一次进位标志

    第3位相加,结果为3,不需要进位;标记第3位为下一次进位标志

    第4位相加,结果为9,不需要进位;此时进位标志不需要移动,因为9加上一个进位后还要继续向前进位

    第5位相加,结果为9,不需要进位;此时进位标志不需要移动,因为9加上一个进位后还要继续向前进位

    第6位相加,结果为14,需要进位,这个进位放到前面标记的第3位上,同时把第4位和第5位置0,标记第6位为下一次进位标志

    第7位同上

     

    所以综上所述,从高位往低位计算加法时,规则是:

    一、如果当前位没有进位:(1)如果当前位的和小于9,则把改位设置成下一次进位标志(2)如果和等于9,进位标志不变

    二、如果当前位有进位:把进位的1加到前面标志的位子上,同时把标志位和当前位之间的位全部置0(因为他们之间的位肯定全部都是9),把当前位设置成进位标志

     

    上面我们举例的两个加数长度一致,如果长度不相同,则要先处理较长的整数的前面多出的部分。

     

    我们把这一题leetcode的输入反转,测试代码如下:

    /**
     * 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) {
            l1 = reverseList(l1);
            l2 = reverseList(l2);
            int n1 = lenList(l1), n2 = lenList(l2);
            if(n1 < n2)//l1 指向较长的链表
            {
                swap(n1,n2);
                swap(l1,l2);
            }
            //carryLoc是下一次出现进位时,进位的1将要放置的位子,pre指向当前结果链表的最后一个节点
            //p1,p2分别是当前处理的l1,l2节点
            //由于加数的最高位有可能进位,所以添加一个新的节点newHead
            ListNode *newHead = new ListNode(0), *carryLoc = newHead, *pre = newHead, *p1 = l1;
            for(int i = 0; i < n1-n2; i++)//处理l1高位长出的部分
            {
                if(p1->val < 9)carryLoc = p1;
                pre->next = p1;
                pre = p1;
                p1 = p1->next;
            }
            ListNode* p2 = l2;
            while(p1 != NULL)
            {
                pre->next = p1;
                pre = p1;
                
                p1->val += p2->val;
                if(p1->val > 9)
                {
                    carryLoc->val += 1;
                    for(carryLoc = carryLoc->next; carryLoc != p1; carryLoc = carryLoc->next)//carryLoc到p1之间的节点全部置0
                        carryLoc->val = 0;
                    p1->val -= 10;
                }
                if(p1->val < 9)
                    carryLoc = p1;
                
                p1 = p1->next;
                p2 = p2->next;
            }
            if(newHead->val != 0)return reverseList(newHead);
            else return reverseList(newHead->next);
        }
        //反转链表
        ListNode *reverseList(ListNode *l1)
        {
            ListNode *p = l1->next, *pre = l1;
            l1->next = NULL;
            while(p)
            {
                ListNode *tmp = p->next;
                p->next = pre;
                pre = p;
                p = tmp;
            }
            return pre;
        }
        //求链表长度
        int lenList(ListNode *head)
        {
            int res = 0;
            while(head)
            {
                res++;
                head = head->next;
            }
            return res;
        }
    };

     

     

     

    【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3735362.html

  • 相关阅读:
    Python调用R语言
    走迷宫(用栈模拟实现非递归,并输出路径)
    走迷宫(用栈模拟实现非递归,并输出路径)
    《Python数据可视化编程实战》
    《Python数据可视化编程实战》
    一道思考题(二进制枚举的应用的想法)切金条
    Android 自己定义UI圆角button
    Oracle 用户管理(二)
    最大团解析及用处
    用反射完毕学生管理系统(包含数据库连接)
  • 原文地址:https://www.cnblogs.com/TenosDoIt/p/3735362.html
Copyright © 2011-2022 走看看