- 今天的每日一题: Add Two Numbers
- 题目描述:给定两个用链表表示的非负数,链表的顺序与数字的高低位顺序相反,例如123对应的链表则是:3->2->1求两个数字之和,并以链表的形式给出结果.
- eg:输入:3->2->1, 4->5->6,输出:7->7->7;
- 结题思路:链表是常见的一种数据结构,一条长度为n的链表由n个链表节点组成,每个节点都保存有当前节点的值与指向后续节点的信息。由于链表的这一特点,导致我们不能像操作数组一样,随意取得数组中某一项的值。那么,我们可以首先将链表中表示的数转化为正常的数字:
节点构造函数:
const ListNode = (val,next)={
this.val = !!val ? val : 0,
this.next = !!next ? next : 0
}
链表转换为数字:
const convertListToNumber = (list)=>{
let arr = [];
while(list){
arr.unshift(list.val);
list = list.next;
}
return parseInt(arr.join(''))
}
通过covertListToNumber函数,我们可以将list链表表示的数字转化为我们熟悉的十进制数字。然后采用常规的十进制加法得到两数相加的结果,然后才使用convertNumberToList方法将结果转化为链表。
const convertNumberToList = (num)=>{
let head = null;
let list = null;
let carry = 0;
const arr = num.toString().split('');
const len = arr.length;
for(let i = len - 1; i >= 0; i--){
const sum = parseInt(arr[i]) + carry;
carry = parseInt(sum / 10);
const node = new ListNode(arr[i]);
if(!head){
head = node;
list = head;
}else{
list.next = node;
list= node
}
}
return head
}
这种转换的方法确实可以在一定程度上解决我们的麻烦,但是当我们遇到更大的数字,两个数字中一个接近js Number类型表示的范围,我们就无法得到正确的结果。而且上述解法在代码效率上也有重大缺陷,我们首先是将两个list遍历,然后求和,再分解,在遍历生成链表,在整个过程中我们做了很多重复的工作。我们需要一种更优解。
- 我们考虑直接对两个list循环,计算两数之和,代码如下:
const addTwoNumbers = (l1,l2)=>{
let head = nul;
let list = null;
let carry = 0;
let sum = 0;
while(l1 || l2 || prev){
sum += carry;
if(!!l1){
sum += l1.val;
l1 = l1.next;
}
if(!!l2){
sum += l2.val;
l2 = l2.next;
}
const node = new ListNode(sum%10);
carry = parseInt(sum/10);
if(!head){
head = node;
list = head;
}else{
list.next = node;
list = node
}
}
return head;
}
第二种方法在效率上相对第一种更高,简化掉许多不必要的重复计算,同时也能很好的处理大数问题。
好了,这就是今天的LeetCode每日一题。鉴于本人水平有限,欢迎指正赐教!
雄关漫道真如铁, 而今迈步从头越。