今天是秋招预备队算法篇第七天,今天继续摆烂,只写了一道题,并且博客是第二天补上的
问题:链表相加
描述:
假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。给定两个这种链表,请生成代表两个整数相加值的结果链表。
数据范围0≤n,m≤1000000,链表任意值 0≤val≤9
要求:空间复杂度 O(n),时间复杂度 O(n)
解题方法:
链表从尾部开始计算,反向遍历做运算,组成新链表,所以要想办法到达两个链表的尾部,然后再做逻辑运算
1、栈
1)将两个链表分别压入两个栈中,链表结点刚好反转
2)依次从两个栈顶取出结点,进行值的相加
3)若和不小于10,则为下一次所取的结点和进1,若小于10,则直接作为新链表结点值
4)重复②③,直到其中一个栈为空
5)若在链表为空前的和向前进1,则与另一个栈的元素进行运算,直到这个栈也为空,否则直接将另一个栈的元素连在新链表上
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head1 ListNode类
* @param head2 ListNode类
* @return ListNode类
*/
public ListNode addInList (ListNode head1, ListNode head2) {
//两个链表为空
if(head1 == null && head2 == null){
return null;
}
//head1为空
if(head1 == null && head2 != null){
return head2;
}
//head2为空
if(head1 != null && head2 == null){
return head1;
}
//入栈
Stack<ListNode> stack1 = new Stack<>();
Stack<ListNode> stack2 = new Stack<>();
while(head1 != null){
stack1.push(head1);
head1 = head1.next;
}
while(head2 != null){
stack2.push(head2);
head2 = head2.next;
}
//新链表表头
ListNode head = null;
//进位
int carry = 0;
//两个栈至少有一个不为空
while(!stack1.isEmpty() || !stack2.isEmpty()){
//进位
int sum = carry;
//链表结点的值
if(!stack1.isEmpty())
sum = sum + stack1.pop().val;
//另一个链表结点的值
if(!stack2.isEmpty())
sum = sum + stack2.pop().val;
//计算进位
carry = sum / 10;
//新链表结点
ListNode tmp = new ListNode(sum % 10);
//连接新链表
tmp.next = head;
//移动头节点
head = tmp;
}
//如果最后结点存在进位
if(carry > 0){
ListNode tmp = new ListNode(carry);
tmp.next = head;
head = tmp;
}
return head;
}
}
时间复杂度:O(n)。取决于链表的长度。
空间复杂度:O(n),使用了栈存储长度为n的链表
2、反转链表法(推荐使用)
1)任意一个链表为空,返回另一个链表就行了,因为链表为空相当于0,0加任何数为0,包括另一个加数为0的情况。
2)相继反转两个待相加的链表
3)设置返回链表的链表头,设置进位carry=0.
4)从头开始遍历两个链表,直到两个链表节点都为空且carry也不为1. 每次取出不为空的链表节点值,为空就设置为0,将两个数字与carry相加,然后查看是否进位,将进位后的结果(对10取模)加入新的链表节点,连接在返回链表后面,并继续往后遍历。
5)返回新链表。
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head1 ListNode类
* @param head2 ListNode类
* @return ListNode类
*/
public ListNode addInList (ListNode head1, ListNode head2) {
//任意一个链表为空,返回另一个
if(head1 == null){
return head2;
}
if(head2 == null){
return head1;
}
//反转链表
ListNode pHead1 = reverseList(head1);
ListNode pHead2 = reverseList(head2);
//按照链表做逻辑运算
//新链表头结点
ListNode head = null;
//进位
int carry = 0;
//当两个链表还存在结点时
while(pHead1 != null || pHead2 != null){
//计算和
int sum = carry;
if(pHead1 != null){
sum += pHead1.val;
pHead1 = pHead1.next;
}
if(pHead2 != null){
sum += pHead2.val;
pHead2 = pHead2.next;
}
ListNode tmp = new ListNode(sum % 10);
//连接链表
tmp.next = head;
head = tmp;
//进位
carry = sum / 10;
}
//当链表最后结点计算完成后,还存在大于0的进位,则还需为其增加一个结点
if(carry > 0){
ListNode tmp = new ListNode(carry);
tmp.next = head;
head = tmp;
}
//返回新链表
return head;
}
//链表反转函数
public ListNode reverseList(ListNode head){
ListNode pre = null;
while(head != null){
ListNode tmp = head.next;
head.next = pre;
pre = head;
head = tmp;
}
return pre;
}
}
时间复杂度:O(n)。取决于链表的长度。
空间复杂度:没有用到额外的空间,所以为O(1)。