目录

LeetCode数学分类-2.-两数相加暴力与优化

⭐LeetCode(数学分类) 2. 两数相加——暴力与优化⭐

⭐LeetCode(数学分类) 2. 两数相加——暴力与优化⭐

https://i-blog.csdnimg.cn/direct/dfb294d838c14e53ad36d90a27fed164.png

https://i-blog.csdnimg.cn/direct/4b2c6136d58647e39252cd741f5a5e9a.png

提示:

每个链表中的节点数在范围 [1, 100] 内

0 <= Node.val <= 9

题目数据保证列表表示的数字不含前导零

题解:

暴力与优化,暴力即转换为十进制解题,优化即直接在链表上进行操作,模拟十进制即可进行进位;

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */

 // 暴力法 转换为十进制
class Solution1 {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode res = new ListNode();
        // 不用long时由于链表长度可达100会超int 但long依旧超限制
        long n1 = 0;  
        long n2 = 0;
        long stand = 1;
        while(l1 != null){
            long tmp = l1.val * stand;
            n1 += tmp;
            stand *= 10;
            l1 = l1.next;
        }

        stand = 1;
        while(l2 != null){
            long tmp = l2.val * stand;
            n2 += tmp;
            stand *= 10;
            l2 = l2.next;
        }

        long n = n1 + n2;
        if(n == 0){
            res.val = 0;
            return res;
        }
        ListNode head = res;
        while(n > 0){
            int tt = (int)(n % 10);
            ListNode tmp = new ListNode(tt);
            head.next = tmp;
            head = head.next;
            n /= 10;
        }

        return res.next;
    }
}


// 最优解 直接在链表上模拟十进制运算进行加法及进位操作 
// 难点在于模拟过程需要对进位进行合理处理
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        // 保存最终链表头部的指针
        ListNode res = new ListNode();
        // 用于帮助构建res的遍历指针
        ListNode head = res;
        // 暂存器 用于l1和l2后面均为null时若前一节点有需要进位的1时则置为一 无该情况默认0
        int extra = 0;
        // 标志位 用于标志哪一个链表在退出第一个while后还有多余未遍历的节点
        boolean f1 = false;
        boolean f2 = false;
        // 采用双指针统一遍历 模拟十进制加法 遇到进位需额外处理 直到某一链表遍历完全或均遍历完全则退出模拟
        while(l1 != null && l2 != null){
            int n1 = l1.val;
            int n2 = l2.val;
            int n = n1 + n2;
            // 发生进位
            if(n >= 10){
                int tmp = n % 10;
                // 及时进1给高位 若l1后不空可进位到l1下一点 若空进到l2下一点
                // 若后面均空则进位到暂存器extra
                if(l1.next != null)
                    l1.next.val++;
                else if(l2.next != null)
                    l2.next.val++;
                else    
                    extra = 1;
                ListNode tNode = new ListNode(tmp);
                head.next = tNode;
            }
            // 未进位 直接新增和的节点
            else{
                ListNode tNode = new ListNode(n);
                head.next = tNode;
            }
            // head记得要移动
            head = head.next;

            // 越界判断 方便while模拟加法过程退出后哪一链表会剩余节点
            if(l1.next == null && l2.next == null){
                f1 = true;
                f2 = true;
            }
            else if(l1.next == null){
                f1 = true;
            }
            else if(l2.next == null){
                f2 = true;
            }

            // 固定移动
            l1 = l1.next;
            l2 = l2.next;
        }
        // 不可直接将余下的直接链接 因可能存在低位向不为null的节点高位+1情况 会导致9->10 故要检查
        // eg: l1 = [9,9,9,9,9,9,9] l2 = [9,9,9,9] 
        // 不加额外操作输出 [8,9,9,9,10,9,9]
        // 正确为 [8,9,9,9,0,0,0,1]
        if(f1 && !f2){
            if(l2.val == 10){
                // 标志位 标志l2余下链表是否有东西
                boolean flag = false;
                // 若出现上述预测情况 则要进行循环判断 因可能后1进到前1导致前由9->10 故要继续进位
                while(l2.val == 10){
                    ListNode tNode = new ListNode(0);
                    head.next = tNode;
                    head = head.next;
                    // 后有东西直接进位+1
                    if(l2.next != null){
                        l2 = l2.next;
                        l2.val++;
                    }
                    // 后无东西则创建一新节点即可 同时l2代表遍历完全
                    else{
                        ListNode tmpNode = new ListNode(1);
                        head.next = tmpNode;
                        flag = true;
                        break;
                    }
                }
                // 直至余下链表中无10 此时可直接链接
                if(!flag)
                    head.next = l2;
            }

            // 无10 可直接链接
            else{
                head.next = l2;
            }
        }
        // 同上
        else if(!f1 && f2){
            if(l1.val == 10){
                // 标志位 标志余下链表是否有东西
                boolean flag = false;
                // 若出现上述预测情况 则要进行循环判断 因可能后1进到前1导致前由9->10 故要继续进位
                while(l1.val == 10){
                    ListNode tNode = new ListNode(0);
                    head.next = tNode;
                    head = head.next;
                    // 后有东西直接进位+1
                    if(l1.next != null){
                        l1 = l1.next;
                        l1.val++;
                    }
                    // 后无东西则创建一新节点即可 同时l1代表遍历完全
                    else{
                        ListNode tmpNode = new ListNode(1);
                        head.next = tmpNode;
                        flag = true;
                        break;
                    }
                }
                // 直至余下链表中无10 此时可直接链接
                if(!flag)
                    head.next = l1;
            }

            // 无10 可直接链接
            else{
                head.next = l1;
            }
        }

        // 此不存在上述情况 但可能存在extra 故要考虑是否要因进位而多增加一个节点 其val=1
        else if(f1 && f2){
            if(extra == 1){
                ListNode tNode = new ListNode(1);
                head.next = tNode;
            }
        }

        // res为带头节点的链表 故返回其next
        return res.next;
    }
}

结果:

https://i-blog.csdnimg.cn/direct/c9e2e5b8a4d648dab78d768a2e38620b.png