[链表]leetcode2-两数相加和leetcode-445两数相加Ⅱ

[链表]–两数相加和两数相加Ⅱ


题目链接

leetcode 2.两数相加

相似题型 相同题型

面试题 02.05.链表求和

题目

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

解析

  1. 两个数字相加可能存在进位,所以需要一个 carry 来保存进位。除此之外,相加后需要一个新链表来保存,当然 temp 作为工具针必不可少;
  2. 新链表每一个节点的值是 两个链表对应节点的值以及 carry 的值之和去掉进位。当然,节点为 null 那值就是 0 没跑了;
  3. 将新节点连接在 temp 后面,然后继续遍历就需要判断两个链表是否相加完:使用三目运算符就 OK,节点是 null 那就继续是 null 吧,不为 null 就需要遍历下一个节点,同时 carry 怎么算?我也不知道;
  4. 什么时候结束?不仅是两个链表都遍历完,carry 同时也不能为空。不怕万一就怕一万,相加以后多出来一位数。
  5. 返回的一定是 dummyHead.next,不然体现不到傀儡和工具针的作用。
public class Solution2 {

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

    /**
     * 每一次创建新节点的值 时 l1.val/0 + l2.val/0 + carry;
     * 1.定义一个傀儡头结点用作连接新链表
     * 2.只有 l1、l2 为 null 并且进位 carry = 0 时才说明计算结束
     * 3.计算三者之和创建新节点连接在新链表后面
     * 4.每次的进位等于这次三者之和 sum/10
     */
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        int carry = 0;// 进位
        ListNode dummyHead = new ListNode(0);
        ListNode temp = dummyHead;
        while (l1 != null || l2 != null || carry > 0) {
            int sum = carry;
            sum += l1 == null ? 0 : l1.val;
            sum += l2 == null ? 0 : l2.val;
            ListNode  node = new ListNode(sum % 10);
            temp.next = node;
            temp = temp.next;
            l1 = l1 == null ? null : l1.next;
            l2 = l2 == null ? null : l2.next;
            carry = sum / 10;
        }
        return dummyHead.next;
    }
}
题目链接

leetcode 445.两数相加Ⅱ

题目

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。

示例

输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 8 -> 0 -> 7

解析

还行不难,它既然不反转了,那我反转:编写一个辅助方法 reverse() 用于反转链表,学以致用!

  1. 定义新链表 dummyHead 以及配套工具针 temp;
  2. 反转两个链表;
  3. leetcode 2.两数相加
  4. 反转新链表返回就好了;
  5. 运行 beat 90% 也可。突然下面有行字看不清,CV 过来看清楚点。

进阶:如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。
这个… 行吧,不翻转还想相加还存在进位…
对了,有个结构叫做 栈----Stack :先进的后出

  1. 链表压栈,当然了,是两个栈;
  2. 然后把链表操作换成栈的操作就行了呗:next = pop();
public class Solution445 {

    /**
     * Definition for singly-linked list
     */
    class ListNode {
        int val;
        ListNode next;
        public ListNode(int val) {
            this.val = val;
        }
    }
    
    /**
     * 需要一个反转链表函数进行辅助
     * 1.反转两个链表
     * 2.定义一个进位 carry, 只有 l1 l2 为空且 carry = 0 时, 才能说明运算结束, 否则还要继续运算
     * 3.l1、l2 的 val 在它们不为空时 就是本身 val, 为空时等于 0
     * 4.新结点的 val = (carry + l1.val + l2.val) % 10, %10 是因为 val 大于时应该有进位, 只需要取个位即可
     * 5.使用 val 创建结点, 连接在新链表后面, 然后判断了 l1、l2 为空时等于 null 就行, 不为空继续遍历, carry 需要使用 val/10 取十位上的数
     * 6.直到第二步说的条件结束才结束, 反转新链表就结束了
     */
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummyHead = new ListNode(-1);
        ListNode temp = dummyHead;
        l1 = reverse(l1);
        l2 = reverse(l2);
        int carry = 0;
        while (l1 != null || l2 != null || carry > 0) {
            int sum = carry;
            sum += ((l1 == null) ? 0 : l1.val) + ((l2 == null) ? 0 : l2.val);
            ListNode node = new ListNode(sum % 10);
            temp.next = node;
            temp = temp.next;
            l1 = (l1 == null) ? null : l1.next;
            l2 = (l2 == null) ? null : l2.next;
            carry = sum / 10;
        }
        return reverse(dummyHead.next);
    }

    /**
     * 反转链表
     */
    public static ListNode reverse(ListNode head) {
        if (head == null) return null;
        ListNode prev = null;
        while (head != null) {
            ListNode headNext = head.next;
            head.next = prev;
            prev = head;
            head = headNext;
        }
        return prev;
    }

}

进阶

public class Solution445 {

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

    /**
     * 1.将两个链表的结点全都压栈, 这样弹出顺序就是计算顺序
     * 2.定义一个进位 carry ,两个栈都为空并且进位为 0 时结束计算
     * 3.当栈为空但是运算没结束时, 就让它等于0, 求三者之和创建新结点
     * 4.注意: 定义的 head 是头结点, 所以让它时刻等于新创建的结点, 这样最后就不用反转链表
     */
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Stack<ListNode> stack1 = new Stack<>();
        Stack<ListNode> stack2 = new Stack<>();
        // 将结点压栈, 弹出顺序就是计算顺序
        while (l1 != null) {
            stack1.push(l1);
            l1 = l1.next;
        }
        while (l2 != null) {
            stack2.push(l2);
            l2 = l2.next;
        }
        ListNode head = null;// 新链表的头结点
        int carry = 0;// 进位
        while (!stack1.isEmpty() || !stack2.isEmpty() || carry > 0) {
            int sum = carry;
            sum += (stack1.isEmpty() ? 0 : stack1.pop().val) + (stack2.isEmpty() ? 0 : stack2.pop().val);
            ListNode node = new ListNode(sum % 10);
            // 头结点是紧跟着新创建结点的, 这样可以保证最后结束时, head 就是新链表的头结点, 不用进行反转
            node.next = head;
            head = node;
            carry = sum / 10;
        }
        return head;
    }
}

-----------------------------------------------------------------------------有始有终分割线----------------------------------------------------------------------------------

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值