LeetCode第二题:两数相加(Java)

题目:两数之和

给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

ListNode类需要自己实现

public class ListNode {
    public int val;
    public ListNode next;

    public ListNode(int val) {

        this.val = val;
    }
    public ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }
    
    //print方法便于最后查看结果
    public void print() {
        System.out.print(this.val);
        if (this.next != null) {
            System.out.print("-->");
            this.next.print();
        }
    }
}

 方法一:官方给的方法

学习算法时知道链表,也知道Java有链表实现类。但从没有用过自己写结点组成链表类这种。

最开始我不明白他说的逆序存储是什么意思,后来发现就是存储的链表头节点是个位。按243存储的顺序,他其实是数字342。

也就意味着,这俩个链表相同位置结点(相加满10就要往新链表对应位置的下一个结点进1)。

a表示进位的值(由于每个结点存放一位数,所以a只能是0或者1,1就表示上一个结点以满10需要进位)。俩结点(n1,n2)相加新链表相同位置为(n1+n2+a)%10,进位为(n1+n2+a)/10。

俩链表结点不同,少的用0补齐。

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode head = null;
        ListNode tail = null;
        int a = 0;
        //循环结束条件l1和l2都为空
        while (l1 == null && l2 == null) {
            //结点少的用0补齐
            int n1 = l1 != null ? l1.val : 0;
            int n2 = l2 != null ? l2.val : 0;
            //新结点相同位置的值
            int sum = n1 + n2 + a;
            if (head == null) {
                //确认第一个结点,head结点
                //head结点主要是确认第一个节点的位置,tail结点不断指向下一个增加新节点
                head = tail = new ListNode(sum % 10);
            } else {
                //增加一个新的结点,tail指向新结点
                tail.next = new ListNode(sum % 10);
                tail = tail.next;
            }
            //保留进位数
            a = sum / 10;
            //这样写也可以
            //a = sum >= 10 ? 1 : 0; sum大于1等于10进位
            //l1指向下一个节点,没有下一个结点则为空,在下一次循环下个节点赋值0。
            //若为null就表示l1是短的那条链表需要用0补齐
            if (l1 != null) {
                l1 = l1.next;
            }
            //l2指向下一个节点
            if (l2 != null) {
                l2 = l2.next;
            }
        }
        //防止l1和l2最后一个结点相加,仍需要进位。这时增加一个新节点保存进位数
        if (a > 0) {
            tail.next = new ListNode(a);
        }
        return head;
    }
}

这题感觉挺简单的,只需要注意进位。

 

方法二:递归

当时评论区看到的一位大神写的自己从写了一遍,同样情况下好像递归比循环消耗性能。

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        return test(l1,l2,0);
    }
    //i表示进位数,每次调用生成一个相同位置的结点
    public  ListNode test(ListNode l1, ListNode l2, int i) {
        //递归停止条件l1和l2为空,l1和l2最后一位相加没有进位
        if (l1 == null && l2 == null & i ==0){
            return null;
        }
        //新链表相同位置的值
        int sum = (l1 ==null ? 0 : l1.val)+(l2 ==null ? 0 : l2.val)+ i;
        ListNode node = new ListNode(sum%10);
        //下一个结点进入下一次循环确认
        node.next = test(l1 != null ? l1.next: null, l2 != null ? l2.next: null, sum/10);
        return node;
    }
}

感觉递归和官方给的循环基本一样。退出循环的条件也相同,我个人感觉递归相反没有循环容易理解,我第一反应很少是会用递归解决问题。

俩种方法我都提交了运行时间都是2ms,递归内存消耗多了一点点。

 

新学习到的东西(总结):

会编写ListNode类,实线链表。

有时间去看下LinkedList和List的源码

 

如果有什么错误或者不合理的地方请告诉我,我会即使修改

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值