题目信息
题号:2 题目描述:
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
题目难度:中等
测试参数:
参数一 输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8]
参数二 输入:l1 = [0], l2 = [0] 输出:[0]
参数三 输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] 输出:[8,9,9,9,0,0,0,1]
提示信息:
每个链表中的节点数在范围 [1, 100] 内
0 <= Node.val <= 9
题目数据保证列表表示的数字不含前导零
解法一:递归
题解思路:
题目给的示例看出,其实就可以看成是两个数字的加法运算,我们按照相同位数字相加,大于10则进行进位,
下一位运算带上进位做相同运算操作。这种重复相同的操作让我们想起是否可以利用递归去完成,每次都是同一位
的数字相加再加上一位运算的进位。
java代码示例
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
List result = new ArrayList<>();
sumNum(l1,l2,false,result);
ListNode nextNode = null;
for(int i=result.size()-1;i>=0;i--){
ListNode newNode = new ListNode((int) result.get(i));
newNode.next = nextNode;
nextNode = newNode;
}
return nextNode;
}
private static void sumNum(ListNode node1,ListNode node2,boolean isAdd,List result){
if(node1 == null && node2 == null){
if(isAdd){
result.add(1);
}
return;
}
if(node1 == null){
int num = (node2.val +(isAdd?1:0)) % 10;
result.add(num);
isAdd = (((node2.val +(isAdd?1:0)) / 10) == 1);
sumNum(null,node2.next,isAdd,result);
}
if(node2 == null){
int num = (node1.val +(isAdd?1:0)) % 10;
result.add(num);
isAdd = (((node1.val +(isAdd?1:0)) / 10) == 1);
sumNum(node1.next,null,isAdd,result);
}
if(node1!=null && node2 !=null){
int num = (node1.val + node2.val +(isAdd?1:0)) % 10;
result.add(num);
isAdd = (((node1.val + node2.val +(isAdd?1:0)) / 10) == 1);
sumNum(node1.next,node2.next,isAdd,result);
}
}
上述代码我们再进行一次优化 如下:
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
List<Integer> result = new ArrayList<>();
sumNum(l1,l2,false,result);
ListNode nextNode = null;
for(int i=result.size()-1;i>=0;i--){
ListNode newNode = new ListNode((int) result.get(i));
newNode.next = nextNode;
nextNode = newNode;
}
return nextNode;
}
private static void sumNum(ListNode node1,ListNode node2,boolean isAdd,List<Integer> result){
if(node1 == null && node2 == null && !isAdd){
return;
}
int sum = (node1 == null?0:node1.val) + (node2 == null?0:node2.val) +(isAdd?1:0);
int num = sum % 10;
isAdd = sum > 9;
result.add(num);
sumNum(node1 == null?null:node1.next,node2 == null?null:node2.next,isAdd,result);
}
效果不是很明显,只是在代码的简洁度上有所提高,也有所收获嘛!
复杂度分析:
时间复杂度:O(max(m,n))
空间复杂度:O(max(m,n)) 开辟了一块List的空间
解法二:指针循环(官方叫模拟)
题解思路:
其实跟上一解法类似,除了用递归去处理同一位的数字计算,我们还可以考虑是不是可以直接循环遍历处理。
其实最大遍历也是链表长度最长的次数,但是我们要考虑可能存在两个链表不一致长度,同一位用0代替处理,
以及最后一次计算完如果有进位,也需要加到新的结果链表中去。图解跟上一解法一样,只不过循环结束的条件即是
递归结束的条件。
java代码示例
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode result = new ListNode();
ListNode currentNode = result;
ListNode n1 = l1;
ListNode n2 = l2;
int add = 0;
while(n1 != null || n2 != null || add > 0){
int sum = (n1 == null? 0:n1.val) + (n2 == null?0:n2.val) + add;
add = sum / 10;
int nextVal = sum % 10;
currentNode.next = new ListNode(nextVal);
n1 = n1 == null?null:n1.next;
n2 = n2 == null?null:n2.next;
currentNode = currentNode.next;
}
return result.next;
}
复杂度分析:
时间复杂度:O(max(m,n))
空间复杂度:O(1) 返回值不计入空间复杂度
总结
这种算法题,我们主要就是找规律,然后看是否有算法模型可以对得上,在进行尝试的基础上做优化。抓住终止条件的处理,也是对边界问题的把握!再多说写就扯了,还是多刷找感觉吧!