Add Two Numbers
问题简介:输入两个数字链表,输出求和后的链表(链表由数字位数倒序组成)
问题详解:
给定两个非空链表,表示两个非负整数. 数字以相反的顺序存储,每个节点包含一位数字.对两个整数作求和运算,将结果倒序作为链表输出.
举例:
输入: (1 -> 4 -> 2) + (5 -> 6 -> 4);
输出: 6 -> 0 -> 7;
说明: 241 + 465 = 706.
链表结构:
public class ListNode {
int val;//当前节点数值
ListNode next;//下一节点的引用
ListNode(int x) { val = x; }
}
Java 解法一:
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode head=new ListNode(0);//定义一个链表头部为空
int carry = 0;//进位
ListNode curr=head;
int x1;//传入l1的值
int x2;//传入l2的值
int sum;//求和
while(l1!=null||l2!=null){//整个过程中需要判断传入的两个链表是否有数据,因为链表长度不同
x1=(l1!=null)?l1.val:0;
x2=(l2!=null)?l2.val:0;
sum=x1+x2+carry;
carry=sum/10;
curr.next=new ListNode(sum%10);
curr=curr.next;
if(l1!=null){l1=l1.next;}
if(l2!=null){l2=l2.next;}
}
if(carry>0){curr.next=new ListNode(carry);}//判断最后是否进位
return head.next;
}
}
官方实现 : Elementary Math
实现过程是差不多的,只是在定义x,y时的位置不一样.
ListNode dummyHead = new ListNode(0);
ListNode p = l1, q = l2, curr = dummyHead;
int carry = 0;
while (p != null || q != null) {
int x = (p != null) ? p.val : 0;
int y = (q != null) ? q.val : 0;
int sum = carry + x + y;
carry = sum / 10;
curr.next = new ListNode(sum % 10);
curr = curr.next;
if (p != null) p = p.next;
if (q != null) q = q.next;
}
if (carry > 0) {
curr.next = new ListNode(carry);
}
return dummyHead.next;
}
复杂度分析:
时间复杂度 :近似于O(n):单层循环,由链表长度决定,近似于n次.
空间复杂度 :近似于 O(n):单层循环,新链表的长度最长近似于n.
拓展提问:
如果输入的链表是顺序存储的该怎么做?
举例:
输入: (2 -> 4 -> 1) + (4 -> 6 -> 5);
输出: 7 -> 0 -> 6;
说明: 241 + 465 = 706.
注:
1.求单链表长度
int getListNodeLength( ListNode l)
{
ListNode head = new ListNode(0);
ListNode curr = head;
int length = 0;
while(curr.val!=null){
length++;
curr = curr.next;
}
return length;
}
2.数组和链表的关系:
数组:静态分配内存,在内存中连续,利用下标定位查询,时间复杂度为0(1),插入和删除的复杂度为o(n).
优点:查找速度快.
缺点:
1.可能浪费内存(因为是连续的,所以每次申请数组之前必须规定数组的大小,如果大小不合理,则可能会浪费内存);
2.内存空间要求高,必须有足够的连续内存空间;
3.数组大小固定,不能动态拓展.
链表:动态分配内存,内存不连续,链表定位元素时间是复杂度O(n),链表插入或删除元素的的时间复杂度O(1)。
优点:
1.插入删除速度快(通过next的指向可以方便的删除元素);
2.内存利用率高,基本不会浪费内存(可以使用内存中细小的不连续空间,并且在需要空间的时候才创建空间);
3.大小没有固定,拓展灵活.
缺点:
不能随机查找,通过遍历的方式查找,效率低
小白刷题之路,请多指教— — 要么大器晚成,要么石沉大海