力扣第二题
前面后来自己做的,后面是之前看答案的思路
题目
两数相加
思路及问题
1.首先想了最笨的方法,就是先把两个数分别提出来,然后直接相加,最后得出一个数,然后再把他放进链表里。。。代码如下
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int num1 = 0;
int num2 = 0;
int sum = 0;
// 幂次方
int i = 0;
// 记录最大的次幂,方便用模运算后面拆分
int j = 0;
while (l1 != null) {
num1 = l1.val * (int)Math.pow(10, i) + num1;
i++;
l1 = l1.next;
}
j = 1;
i = 0;
while (l2 != null) {
num2 = l2.val * (int)Math.pow(10, i) + num2;
i++;
l2 = l2.next;
}
i = 3;
sum = num1 + num2;
while (sum / Math.pow(10, j) > 0) {
j++;
}
ListNode output = new ListNode((int) (sum % 10));
if (sum < 10) {
return output;
}
ListNode node = new ListNode((int) (sum % 100 / 10));
output.next = node;
int temp;
while (i <= j) {
node.next = new ListNode((int) (sum % Math.pow(10, i) / Math.pow(10, i - 1)));
node = node.next;
i++;
}
return output;
}
但是有个问题,里面的数超过了int最大值就会出错!换成long或者double之后要么运行超时,要么出错,要么超时,无奈,只能用另外一种方法了
- 另一种方法比较明智,就是每一位各自相加,然后有进位就提出来,然后再下一位计算的时候放进去。
注意: 每次进位之后,相加,要继续判断。 然后就是如果两个数长度不相等得处理。以下自己做的代码:
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode t1 = l1;
ListNode t2 = l2;
int jinwei = 0;
ListNode output;
if (t1.val + t2.val < 10) {
output = new ListNode(t1.val + t2.val);
jinwei = 0;
} else {
output = new ListNode(t1.val + t2.val - 10);
jinwei = 1;
}
ListNode out = output;
while (t1.next != null && t2.next != null) {
t1 = t1.next;
t2 = t2.next;
if (t1.val + t2.val + jinwei < 10) {
output.next = new ListNode(t1.val + t2.val + jinwei);
jinwei = 0;
} else {
output.next = new ListNode(t1.val + t2.val - 10 + jinwei);
jinwei = 1;
}
output = output.next;
}
while(t1.next != null) {
t1 = t1.next;
if (t1.val + jinwei < 10) {
output.next = new ListNode(t1.val + jinwei);
jinwei = 0;
} else {
output.next = new ListNode(t1.val - 10 + jinwei);
jinwei = 1;
}
output = output.next;
}
while(t2.next != null) {
t2 = t2.next;
if (t2.val + jinwei < 10) {
output.next = new ListNode(t2.val + jinwei);
jinwei = 0;
} else {
output.next = new ListNode(t2.val - 10 + jinwei);
jinwei = 1;
}
output = output.next;
}
if(jinwei == 1) {
output.next = new ListNode(1);
jinwei = 0;
}
return out;
}
最后如果还有进位的话,记住最后再加一位。
总结
基本就是在题目下,先大题想一个思路,然后编码,放进去调试,根据错误点继续修改。
----------------------------------------------------------我是分割线---------------------------------------------------------------------
1.首先,没学过怎么用java表示链表,或者学过忘了。所以得查一下怎么表示。
JAVA表示链表*[作者YSOcean]
2.行吧,看了一下午还是不会,然后就直接看答案了,看答案还是有点一愣一愣的,理解得有点模糊,状态都不在了,先缓一下。但是先贴上答案代码,然后再说说自己的理解。
代码
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
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;
}
理解
- 首先看它原题给出的单向链表的代码
//Definition for singly-linked list.
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
这里的val就是一个链表里存的值,next存的是指向下一个链表的地址。然后一个构造函数,把参数的值赋予到链表类的变量中。
然后就看答案给的代码了,一步一步讲。
- 第一条代码
ListNode dummyHead = new ListNode(0);
设置一个最头头的节点,作用就是引出相加和得出的节点,0为参数,得出的答案就是0xxxx(xxx为整数);
- 然后两条
ListNode p = l1, q = l2, curr = dummyHead;
int carry = 0;
- 前面一句没啥,就是换一下变量,(应该算是方便?),然后第二句是进制,就是两个个位数相加溢出,carry就得1(微原倒是有详细的说),再说下这的思路。
- 本来我的思路是用一个整数sum把链表里每个数通过循环然后相加然后乘十再相加的方法,把两个链表中的数提取出来,相加完,再分解存进链表里的。然后一开始链表就卡主了。
- 答案这种思路也想过,只是想得个大概,各个对应的数相加,溢出就拿东西存着。但真正看这答案的实现,还是挺复杂的,想不到这么绕。
- 接着看循环体
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;
}
- 首先循环条件是p不为空或q不为空,也就是两个不同时为空,空就是这个节点没有任何东西,没有val,没有next。为什么要求不同时为空呢?这是以防出现一个的位数比另外一个的位数多的情况,这时,空的一方,就可以将其值设置为0,然后与不空的节点的值相加。
- x,y的初始化就是把p和q的val值存起来,如果p或q为空的话,则设置为0
- 相加
- 因为carry是int类型,而carry+x+y最大的值不超过19(carry=1,x=9,y=9),所以carry等于1或者0(用于处理加法溢出,然后进一位)
- 将得出的数模十(因为要求一个结点只取一位,所以只取个位,溢出的十位由carry存储,并加入下一次加法中),将得出的个位存到curr的next指针中(0开头,然后开始存储下一位)
- 下面三步都是准备下一步循环,将下一节点存储上当前节点,以便进行下一次循环,直至p和q都为空,然后就curr以0开头的链表就存了除最后一位可能进制的位数外所有l1和l2的对应数的 和。
- 然后当然是解决最后一位可能进制的位数啦
if (carry > 0) {
curr.next = new ListNode(carry);
在整个循环结束后,最后补上,如果carry>0,也就是,最后一次循环,两个对应的节点存储的数相加,还有溢出的(还有进一位的),就再新建一个参数为carry的节点,存到curr.next中去。完成了最后一步。
- 最后返回
return dummyHead.next;
返回以dummyHead.next开头的链表,也就是以curr.next开头的,最后两个对应数相加(或者溢出的数)得出的结果为开头的链表。