LeetCode2 addTwoNumbers

题目描述

  • 给出两个非空链表用来表示两个非负整数。其中他们各自的位数按照逆序的方式存储,并且每个节点只存储一位数字。如果将两个数加起来,则返回一个新的链表来表示它的和。
  • Example:

Eg1:
(2 -> 4 ->3) + (5 -> 6 -> 4)
(7 -> 0 -> 8)
342 + 465 = 807

Eg2:
(1 -> 8) + (0)
(1 -> 8)

Eg3:
(9 -> 9) + (1)
(0 -> 0 -> 1)

上面三个用例分别反映了这个问题三个需要注意的点:
Eg1是两个等长的数相加;Eg2是两个不等长的数相加;Eg3是最后一位有进位的情况。

思路

一 整体思路:

进行循环对两个链表的 每一位结点 对应位的值与来自下一位的进位carry(in)相加取余取整操作得到每一位的结果result和进位carry(out)。

(伪 leetCode2.1)
while(){
	/* 中间循环体,如下:*/
	num1 = p.val;
	num2 = q.val;
	sum = num1 + num2 +carry;
	result = sum%10;
	carry = sum/10;
	/*  末尾循环体 */
	{ ... }
	}

二 边界情况(特殊)

1 两个链表不等长: 当其中一个链表走到头之后,只有链表i执行:

(伪 leetcode2.2)
/* 中间循环体,如下:*/
sum = numi + carry;
result = sum%10;
carry = sum/10;

2 最后一位有进位(如:99+1):再新建一个值为carry的结点:

(伪 leetcode2.3)
if(carry != 0)//或if(carry == 1){
	{新建一个值为carry的结点}
}

三 细节

1 对每一位结点相加 -> 循环

1.哪种循环: 遍历整个链表显然while(p == null){}语句更常用也更方便)
2.循环要素:
终止条件(条件表达式): 指针指向空结点意味着整个链表遍历结束(p == null)
末尾循环体:指针前进(p = p.next; q = q.next; cur = cur.next;)

2 结果链表使用哑元头结点(dummy head),方便结果返回。

Java Solution

初级版(对思路的整合)

class Solution{ // Solution
	public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
		ListNode dummyhead = new ListNode(0); // 结果链表的dummyhead
		// 指针
		ListNode p = l1;    			   // 初始时刻指向l1链表的第一个结点
		ListNode q = l2;			   // 初始时刻指向l1链表的第一个结点
		ListNode cur = dummyhead;   // 初始时刻指向l1链表的第一个结点
		// 结果暂存变量
		int sum = 0;    // 求和(num1 + num2 + carry)
		int carry = 0;  // 进位
		// ******************** (伪 leetCode2.1)的实现  ******************* //
		while((p != null) || (q != null)) { // 当两个链表至少有一个不为空时 ...
			// 两个链表都不为空时,num1+num2+carry(i)
			if((p != null)&&(q != null)) {
				sum = p.val + q.val + carry;
				carry = sum/10;	
				// 末尾循环体
				p = p.next;
				q = q.next;
			}
			// ********* (伪 leetcode2.2) 边界情况1 ******** //
			// 当链表1空2不空时,num2+carry(i)
			else if((p == null)&&(q != null)) {
				sum = q.val + carry;
				carry = sum/10;
				// 末尾循环体更新
				q = q.next;
			}
			// ##链表2空1不空时,num1+carry(i)
			else { // if((p != null)&&(q == null)) 
				sum = p.val + carry;
				carry = sum/10;
				// 末尾循环体更新
				p = p.next;
			}
			// *********(伪 leetCode2.1 末尾循环体)********** //
			cur.next = new ListNode(sum%10);
			// 末尾循环体更新
			cur = cur.next;
		}
		// ********** (伪 leetcode2.3) 边界情况2 ********** //
		// 两个链表都为空时,看进位是否为空,不空再加一个链表
		if (carry != 0) {
			cur.next = new ListNode(carry);
		}
		// 结果为dummyhead后继指针指向的子链表
		return dummyhead.next;
	}
}

优化版1

利用 x?y:z 运算对边界情况1优化
注意:
初级版程序中使用的是
if{…}else if{…}else{…}
而优化版使用的是 if{…}if{…}
这是因为初级版利用的是分类讨论的思想,每种情况是不能同时发生的,每次只发生其中一种。

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode result = new ListNode(0);
        ListNode p = l1;
        ListNode q = l2;
        ListNode curr = result;
        int carry = 0;
        int sum = 0;
        while(p != null || q != null){
            int x = (p != null)?p.val:0;
            int y = (q != null)?q.val:0;
            sum = x + y + carry;
            carry = sum/10;
            curr.next = new ListNode(sum%10);
            curr = curr.next;
            // ***** 边界情况1 ********* //
            if (p != null){
                p = p.next;
            }
            if (q != null){
                q = q.next;
            }
        }
        // ********** 边界情况2 *********** //
        if (carry > 0){
            curr.next = new ListNode(carry);
        }
        return result.next;
    }
}

优化版2

和优化版1出发点相同
当链表1不为空:链表1值取出并前进指针
当链表2不为空:链表2值取出并前进指针
注意:
初级版程序中使用的是
if{…}else if{…}else{…}
而优化版使用的是 if{…}if{…}
这是因为初级版利用的是分类讨论的思想,每种情况是不能同时发生的,每次只发生其中一种。

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummyhead = new ListNode(0); 
		ListNode p = l1;
		ListNode q = l2;
		ListNode cur = dummyhead;
		int sum = 0;
		int carry = 0;
		while((p != null) || (q != null)) {
            sum = carry;
            if(p != null){
                sum += p.val;
                p = p.next;
            }
            if(q != null){
                sum += q.val;
                q = q.next;
            }
            carry = sum/10;
            cur.next = new ListNode(sum%10);
            cur = cur.next;
		}
		if (carry != 0) {
			cur.next = new ListNode(carry);
		}
		return dummyhead.next;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值