9. <tag-链表和两数之和问题>lt-2. 两数相加 + lt-445. 两数相加 II

lt.240-搜索二维矩阵 ||

[案例需求]
在这里插入图片描述

[思路分析]

  • 本道题给定的两条链表比较容易理解, 跟合并两条链表的遍历过程基本是一致的,
  • 我们只需要同时遍历两条链表, 把对应的两个结点的值加在一起,
  • 进位存储起来用于下次求和时加上, 得到的加数的个位数作为新链表结点的val即可;
  • 细节很多, 仔细把握即可;
    1. 两条链表不等长, 同时遍历相加结束的条件是 ? --> 所有的链表均为空;
    2. 对于carry不为空的情况( 即99 + 999的情况), 我们需要在遍历链表结束后, 加上判断, 并把不为0的carry作为新的结点接到新的结果链表中去;

[代码实现]

/**
 * 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 Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        //进位要存储下来
        ListNode temp1 = l1;
        ListNode temp2 = l2;
        int carry = 0;
        int sum = 0;
        int nodeVal = 0;

        ListNode dummyNode = new ListNode(-1);
        ListNode temp = dummyNode;

        while(l1 !=null || l2 != null){
           
            int val1 = l1 == null ? 0 : l1.val;
            int val2 = l2 == null ? 0 : l2.val;

            sum = (carry + val1 + val2);
            nodeVal = sum % 10;
            carry = sum / 10;

            temp.next = new ListNode(nodeVal);
            temp = temp.next;

            if(l1 != null)l1 = l1.next;
            if(l2 != null)l2 = l2.next;
        }
        //链表都遍历完了, carry(进位)依然不为0;
        if(carry != 0){
            temp.next = new ListNode(carry);
        }
        return dummyNode.next;
    }
}

[简洁一点的]

/**
 * 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 Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
      
        //同时遍历两条链表, 获得加数, 被加数, 如果其中一个链表为空了, 就把那个链表对应位置的数值置为0, 同时我们用carry存储进位, 每次加完之后, carry = sum/10 (进位), sum = sum % 10(加数的个位数),  用加数的个位数成立新的加数结点,   往后遍历结点
        //在两条链表全部遍历完之后, 判断进位还存在吗, 存在则再创建一个新的加数结点, 值为carry

        ListNode head = new ListNode(0);
        ListNode temp = head;
        int carry = 0;

        while(l1 != null || l2 != null){
            
            int x = l1 == null ? 0 : l1.val;
            int y = l2 == null ? 0 : l2.val;

            int sum = x + y + carry;

            //取出sum的个位数新建结果链表的结点
            //对carry 取 十位数
            /千万要注意这倆数的次序问题!!!!!!!!!!!!!!
            carry = sum / 10;

            sum = sum % 10;
            //新建结点
            temp.next = new ListNode(sum);
           
            //移动链表指针, 注意判空, 避免空指针异常
            if(l1 != null)l1 = l1.next;
            if(l2 != null)l2 = l2.next;

            temp = temp.next;
        } 

        if(carry != 0){
            temp.next = new ListNode(carry);
        }
        return head.next;
    }
}

lt-445. 两数相加 II

[案例需求]
在这里插入图片描述

[思路分析]

  • 这题比较有意思, 因为看起来是倒序相加的, 链表也是倒序的, 还是那句话, 如果你觉着链表遍历解题比较困难的话, 请考虑一下用集合工具解题, 这道题其实用栈Stack即可, 但是我为了体验一下双端队列, 所以两钟解法都列在了下面;
  • 在使用栈时, 我们需要新建两个栈来存储这两条链表, 然后再出栈相加每个数, 正好就是倒序相加, 而且很方便, 我们把数加完之后直接新建结点, 并通过temp指针连接起来 ;

[代码示例]

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Deque<Integer> stack1 = new LinkedList<Integer>();
        Deque<Integer> stack2 = new LinkedList<Integer>();
        while (l1 != null) {
            stack1.push(l1.val);
            l1 = l1.next;
        }
        while (l2 != null) {
            stack2.push(l2.val);
            l2 = l2.next;
        }
        int carry = 0;
        ListNode ans = null;
        while (!stack1.isEmpty() || !stack2.isEmpty() || carry != 0) {
            int a = stack1.isEmpty() ? 0 : stack1.pop();
            int b = stack2.isEmpty() ? 0 : stack2.pop();
            int cur = a + b + carry;
            carry = cur / 10;
            cur %= 10;
            ListNode curnode = new ListNode(cur);
            curnode.next = ans;
            ans = curnode;
        }
        return ans;
    }
}

[思路分析二, 双端队列]

  • 相比于栈, 这种写法在逻辑上稍微复杂了一些. 把题目中给定的每一条链表都分别进行遍历利用头插法(xx.addFirst())放入到两个双端队列中, 然后取出进行计算.
/**
 * 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 Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        //链表的两数之和
        //尝试一下双端队列
        //addFirst(); removeFirst();
        //addLast(); pollFirst();
        Deque<ListNode> queue1 = new ArrayDeque<>();
        Deque<ListNode> queue2 = new ArrayDeque<>();
        Deque<ListNode> resQueue = new ArrayDeque<>();
        

        //把题目中的两条链表分别进行遍历, 使用头插法插入到双端堆中
        while(l1 != null){
            queue1.addFirst(l1); //头插法. 每次都放到头部 7,2,4,3 就会变味3,4,2,7
            l1 = l1.next;
        }

        while(l2 != null){
            queue2.addFirst(l2);// 5,6,4 变为 4,5,6
            l2 = l2.next;
        }

        ListNode dummyNode = new ListNode(-1);
        ListNode temp = dummyNode;

         int sum = 0, carry = 0, nodeVal = 0;
        while(!queue1.isEmpty() ||  !queue2.isEmpty()){
            //从末尾取出元素, 做和
           
            int val1 = queue1.isEmpty() ? 0 : queue1.pollFirst().val; //从头部取出进行计算
            int val2 = queue2.isEmpty() ? 0 : queue2.pollFirst().val;

            sum = carry + val1 + val2;
            carry = sum / 10;
            nodeVal = sum % 10;

            resQueue.offerFirst(new ListNode(nodeVal));
        }

        if(carry != 0){
            resQueue.offerFirst(new ListNode(carry));
        }

        //取出resQueue
        while(! resQueue.isEmpty()){
            temp.next = resQueue.pollFirst();
            temp = temp.next;
        }
        
        return dummyNode.next;
    }
}

简单的优化一下:

把resQueue舍弃, 直接构建链表, 因为是逆序的, 所以采用头插法构建

/**
 * 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 Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        //链表的两数之和
        //尝试一下双端队列
        //addFirst(); removeFirst();
        //addLast(); pollFirst();
        Deque<ListNode> queue1 = new ArrayDeque<>();
        Deque<ListNode> queue2 = new ArrayDeque<>();
        Deque<ListNode> resQueue = new ArrayDeque<>();
        

        //把题目中的两条链表分别进行遍历, 使用头插法插入到双端堆中
        while(l1 != null){
            queue1.addFirst(l1); //头插法. 每次都放到头部 7,2,4,3 就会变味3,4,2,7
            l1 = l1.next;
        }

        while(l2 != null){
            queue2.addFirst(l2);// 5,6,4 变为 4,5,6
            l2 = l2.next;
        }

        ListNode dummyNode = new ListNode(-1);
        ListNode temp = dummyNode;

         int sum = 0, carry = 0, nodeVal = 0;
        while(!queue1.isEmpty() ||  !queue2.isEmpty()){
            //从末尾取出元素, 做和
           
            int val1 = queue1.isEmpty() ? 0 : queue1.pollFirst().val; //从头部取出进行计算
            int val2 = queue2.isEmpty() ? 0 : queue2.pollFirst().val;

            sum = carry + val1 + val2;
            carry = sum / 10;
            nodeVal = sum % 10;

            //resQueue.offerFirst(new ListNode(nodeVal));
            //头插法, 创建结果链表
            temp = new ListNode(nodeVal);
            temp.next = dummyNode.next;
            dummyNode.next = temp;
        }

        if(carry != 0){
           // resQueue.offerFirst(new ListNode(carry));
           temp = new ListNode(carry);
           temp.next = dummyNode.next;
           dummyNode.next = temp;
        }

        // //取出resQueue
        // while(! resQueue.isEmpty()){
        //     temp.next = resQueue.pollFirst();
        //     temp = temp.next;
        // }
        
        return dummyNode.next;
    }
}

在这里插入图片描述

posted @   青松城  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示