給定兩個非空鏈表來代表兩個非負(fù)整數(shù)犹菱。數(shù)字最高位位于鏈表開始位置绕辖。它們的每個節(jié)點只存儲單個數(shù)字胖腾。將這兩數(shù)相加會返回一個新的鏈表霍比。
你可以假設(shè)除了數(shù)字 0 之外幕袱,這兩個數(shù)字都不會以零開頭。
進(jìn)階:
如果輸入鏈表不能修改該如何處理悠瞬?換句話說们豌,你不能對列表中的節(jié)點進(jìn)行翻轉(zhuǎn)。
示例:
輸入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出: 7 -> 8 -> 0 -> 7
思路:
- 毫無疑問,難點在于進(jìn)位的處理,不需要進(jìn)位的情況下,僅僅只是簡單的同位相加
- 由于鏈表無法逆向遍歷,需要通過其他手段輔助定位,如:鏈表反轉(zhuǎn),集合. 也可以通過轉(zhuǎn)為10進(jìn)制進(jìn)行操作,不過這也是效率較低的選擇(注意溢出)
- 在不知曉鏈表長度情況下,重建鏈表的效果要高于在原立案表上進(jìn)行改動
代碼1:
public ListNode addTwoNumbers1(ListNode l1, ListNode l2) {
if (l1 == null || l2 == null)
return l1;
ListNode temp = l1, cur;
long num1 = 0, num2 = 0;
//轉(zhuǎn)為十進(jìn)制數(shù)
while (temp != null) {
num1 = num1 * 10 + temp.val;
temp = temp.next;
}
temp = l2;
while (temp != null) {
num2 = num2 * 10 + temp.val;
temp = temp.next;
}
//求和并重構(gòu)鏈表
num1 = num1 + num2;
if (num1 > 0) {
ListNode res = new ListNode(0);
res.next = temp;
int k;
while (num1 != 0) {
k = (int) (num1 % 10);
cur = res.next;
temp = new ListNode(k);
res.next = temp;
temp.next = cur;
num1 = num1 / 10;
}
} else {
temp = new ListNode(0);
}
return temp;
}
分析:
- 將鏈表轉(zhuǎn)為十進(jìn)制,自動進(jìn)位進(jìn)位處理,思路非常簡單
- 測試用例中有許多越界數(shù)組,該方法還需要添加溢出的處理,例如按位數(shù)用數(shù)組分批存儲數(shù)字等
代碼2
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
Stack<Integer> sta1 = new Stack<Integer>();
Stack<Integer> sta2 = new Stack<Integer>();
Stack<Integer> sta = new Stack<Integer>();
//構(gòu)建棧
while (l1 != null) {
sta1.push(l1.val);
l1 = l1.next;
}
while (l2 != null) {
sta2.push(l2.val);
l2 = l2.next;
}
int c = 0;
//相加進(jìn)位,壓入新棧
while (!sta1.isEmpty() && !sta2.isEmpty()) {
int sum = sta1.pop() + sta2.pop() + c;
c = sum / 10;
sum = sum % 10;
sta.push(sum);
}
if (!sta2.isEmpty())
sta1 = sta2;
//為了應(yīng)對兩鏈表長度不同,另開一個循環(huán)進(jìn)行處理
while (!sta1.isEmpty()) {
int sum = sta1.pop() + c;
c = sum / 10;
sum = sum % 10;
sta.push(sum);
}
if (c == 1)
sta.push(1);
ListNode dump = new ListNode(0);
ListNode ret = dump;
while (!sta.isEmpty()) {
dump.next = new ListNode((int) sta.pop());
dump = dump.next;
}
return ret.next;
}
分析:
- 使用棧進(jìn)行操作,通過出棧操作達(dá)到逆向遍歷鏈表的目的
- 此處也可以使用list等其他存儲集合,但是效率都很低
代碼3:
public ListNode addTwoNumbersBest(ListNode l1, ListNode l2) {
ListNode root1 = exec(l1);
ListNode root2 = exec(l2);
ListNode root = null, current = null;
int bits = 0;
ListNode n1 = root1, n2 = root2;
for(;n1 != null && n2 != null;n1 = n1.next, n2 = n2.next) {
int value = n1.val + n2.val + bits;
bits = value / 10;
if(root == null) {
root = new ListNode(value % 10);
current = root;
}else {
current.next = new ListNode(value % 10);
current = current.next;
}
}
for(;n1 != null;n1 = n1.next) {
int value = n1.val + bits;
bits = value / 10;
current.next = new ListNode(value % 10);
current = current.next;
}
for(;n2 != null;n2 = n2.next) {
int value = n2.val + bits;
bits = value / 10;
current.next = new ListNode(value % 10);
current = current.next;
}
if(bits != 0) {
current.next = new ListNode(bits);
current = current.next;
}
return exec(root);
}
//反轉(zhuǎn)方法
public ListNode exec(ListNode root) {
ListNode node = root, previous = null;
while(node != null) {
ListNode next = node.next;
node.next = previous;
previous = node;
node = next;
}
return previous;
}
分析:
- 執(zhí)行效率分布中非城匙保靠前的方法
- 先反轉(zhuǎn)鏈表,使其可以逆向遍歷,之后使用相同的處理方式,計算和值
總結(jié):
- 本題主要考察當(dāng)順序遍歷無法滿足結(jié)題要求時,對數(shù)據(jù)的處理方法
- 逆向鏈表與棧都是非常好的方法,若使用轉(zhuǎn)為十進(jìn)制進(jìn)行操作,需要處理數(shù)值溢出問題