LeetCode-两数相加
两数相加
LeetCode题目如下:
给出两个非空的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
链表的概念
(这是写给没有接触过链表的同学,如果了解链表,请移步:创建链表或求解步骤)
我之前已经写过一篇链表的博客,为什么我这里要再重新介绍链表的概念呢?
- 这里使用到了链表,并且我选择了使用C#语言来写
- 对于没有接触过数据结构与内存的同学来说,理解链表的概念并不容易
链表是具有相连关系的一组节点,节点可以被定义为以下结构(这个是LeetCode上的原样代码):
public class ListNode {
public int val;
public ListNode next;
public ListNode(int val=0, ListNode next=null) {
this.val = val;
this.next = next;
}
}
可以看到ListNode中有一个ListNode字段,该字段是指向下一个对象的引用变量
如果你不理解引用变量,请移步我的博客,深度理解值类型与引用类型:https://www.cnblogs.com/erosion2020/p/14101652.html
链表的内存图,大致是这个样子的:
list变量引用了地址为0xd27038的对象,而该对象又引用了0xbff794,位于0xbff794内存区域的对象又引用了位于0xba7586内存区域的对象,而位于0xba7586对象无任何引用,这表明链表走到了尽头,也就是说0xba7586就是链表的尾节点。
创建链表
这里编写的是一个辅助类,类的功能创建链表,以方便我们接下来解题用。
使用尾插法创建一个无头节点的链表,链表中的数据从source数组中读取。
public ListNode CreateLinkTable(int[] source)
{
if (source == null || source.Length < 1)
return null;
ListNode list = new ListNode(source[0]);
ListNode p = list;
for(int i = 1;i < source.Length;i++)
{
p.next = new ListNode(source[i]);
p = p.next;
}
return list;
}
如果你还是不理解链表,请移步:https://www.cnblogs.com/erosion2020/p/14088537.html
求解
我这里第一想法是对两个链表中的数据同时遍历。
但是可能会遇到以下问题:
- 第一个或第二个链表是空链表,或两个链表都为空
- 第一个链表比第二个链表短
- 第二个链表比第一个链表短
- 当前节点相加大于10,需要进位
- 两个链表都遍历完毕,但是数值相加大于10,存在进位情况
public ListNode AddTwoNumbers(ListNode l1, ListNode l2)
{
ListNode list = new ListNode(); //链表
ListNode temp = list; //temp是一个ListNode指针,该指针指向链表
int result = 0; //记录两数相加的和 以及进位的值
int v1 = 0; //记录第一个链表中的值
int v2 = 0; //记录第二个链表中的值
while(true)
{
//如果result = 0, 表示上一个节点运算时其结果小于10,并不需要进位,但是为了统一操作,我们依旧加上0
//如果result = 1, 表示上一个节点运算时其结果大于等于10,此时属于需要进位的情况
//如果有任何一个链表走到了链表尽头我们就让那个值变为0,如果链表并没有到尽头,就取出链表中的值
v1 = l1 == null ? 0 : l1.val;
v2 = l2 == null ? 0 : l2.val;
//result为链表l1中的数据加上l2中的数据加上result本身的数据(也就是进位的情况),如果存在
result += v1 + v2;
temp.val = result % 10;
//求余法算出是否需要进位
result /= 10;
//如果此时链表已经为null,也就是表示走到了尽头,就不执行后移操作
if(l1 != null)
l1 = l1.next;
if(l2 != null)
l2 = l2.next;
//当存在两个链表都走到了链表尽头,并且此时不需要进位时,计算完毕,退出
if(l1 == null && l2 == null && result == 0)
{
break;
}
temp.next = new ListNode();
temp = temp.next;
}
return list;
}
测试
编写Main方法,用以测试数据:
这里给出的是其中一种极端情况:第二个链表为空,其它极端情况我就不写了,都是差不多的。
static void Main(String[] args)
{
int[] source1 = { 9, 9, 9, 9, 9, 9, 9, 9, };
ListNode temp0 = new Solution().CreateLinkTable(source1);
int[] source2 = { };
ListNode temp1 = new Solution().CreateLinkTable(source2);
new Solution().AddTwoNumbers(temp0, temp1);
}