1. 程式人生 > >【leetcode】Add Two Numbers 解析以及拓展

【leetcode】Add Two Numbers 解析以及拓展

題目:

You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8

解析:題目很簡單,輸入兩個連結串列,分別代表兩個整數,每一個節點代表數字的每一位,從個位數開始計算,將每個節點的值相加即可,注意兩個連結串列長度不同,以及最後有進位的情況,Java AC程式碼:
public class Solution {

	public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
		int carry = 0;
		ListNode res = new ListNode(-1);
		ListNode head = res;
		while (l1 != null || l2 != null) {
			int num = (l1 == null ? 0 : l1.val) + (l2 == null ? 0 : l2.val)
					+ carry;
			if(l1!=null){
				l1 = l1.next;
			}
			if(l2!=null){
				l2 = l2.next;
			}
			res.next = new ListNode(num % 10);
			res = res.next;
			carry = num / 10;
		}
		if(carry==1){
			res.next = new ListNode(1);
		}
		return head.next;
	}
}

拓展:如果輸入的兩個連結串列表示的數字不是從個位開始,而是從高位到低位,該如何處理呢?比如:

Input: (3->4->2)+(4->6->5)

Output: (8->0->7)

解析:拓展的這種解法看起來和原題差不多,實際上會更復雜更多,主要要注意兩個問題。首先,因為兩個連結串列的長度可能不一樣,所以剛開始可以比較兩個連結串列的長度,用0填充較短的連結串列;原題是求出新的節點後放在舊的節點後面,拓展題目需要新增節點到結果連結串列的頭部,所以用遞迴呼叫解決。遞迴需要傳遞兩個引數:結果連結串列節點和進位,可以建立內部類包含這兩個引數,Java 實現程式碼如下所示:

/**
 * Input: (3->4->2)+(4->6->5) Output: (8->0->7)
 */

public class AddTwoNumbersExp {

	public static void main(String[] args) {
		ListNode node11 = new ListNode(3);
		ListNode node12 = new ListNode(4);
		ListNode node13 = new ListNode(2);
		ListNode node21 = new ListNode(4);
		ListNode node22 = new ListNode(6);
		ListNode node23 = new ListNode(5);
		node11.next = node12;
		node12.next = node13;
		node21.next = node22;
		node22.next = node23;
		ListNode res = new AddTwoNumbersExp().addTwoNumbers(node11, node21);
		while (res != null) {
			System.out.print(res.val+" ");
			res = res.next;
		}
	}

	public class Node {
		public ListNode sum = null;
		int carry;
	}

	public ListNode addTwoNumbers(ListNode l1, ListNode l2) {

		// 查詢兩個連結串列長度,將短的連結串列用0填充
		int len1 = getLength(l1);
		int len2 = getLength(l2);
		l1 = len1 < len2 ? paddingZero(l1, len2 - len1) : l1;
		l2 = len2 < len1 ? paddingZero(l2, len1 - len2) : l2;

		// 對兩個連結串列求和
		Node sum = addTwoList(l1, l2);

		// 判斷是否有進位
		if (sum.carry == 0) {
			return sum.sum;
		}
		ListNode node = new ListNode(1);
		node.next = sum.sum;
		return node;

	}

	public int getLength(ListNode node) {
		int length = 0;
		while (node != null) {
			length++;
			node = node.next;
		}
		return length;
	}

	public ListNode paddingZero(ListNode l1, int zeroN) {
		ListNode res = new ListNode(-1);
		res.next = l1;
		for (int i = 0; i < zeroN; i++) {
			ListNode node = new ListNode(0);
			node.next = res.next;
			res.next = node;
		}
		return res.next;
	}

	public Node addTwoList(ListNode l1, ListNode l2) {
		if (l1 == null && l2 == null) {
			Node res = new Node();
			return res;
		}
		Node after = addTwoList(l1.next, l2.next);

		int val = after.carry + l1.val + l2.val;
		ListNode cur = new ListNode(val % 10);
		cur.next = after.sum;

		Node res = new Node();
		res.carry = val / 10;
		res.sum = cur;
		return res;
	}

}