1、两数相加(2)
题目描述:
【中等题】
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
思路分析:
1、此题关键是处理两位相加进位与当前位的确定
2、因为两个数字相加会产生进位,所以使用carry来保存进位,初始为0.
3、则当前位的值为(l1.val + l2.val + carry) % 10
4、则进位值为(l1.val + l2.val + carry) / 10
5、建立新node,然后将进位传入下一层。
【python 代码实现】
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def addTwoNumbers(self, l1, l2):
carry=0 # 为了处置进位
res = ListNode(0) # 创建结果链表的虚拟节点
restemp = res
while l1 or l2: # 链表只要其中一个不为空执行以下循环
x = l1.val if l1 else 0
y = l2.val if l2 else 0
sum = x + y + carry
carry = sum // 10 # 下一步进位处理
restemp.next = ListNode(sum % 10) # 求余
restemp = restemp.next
if l1:
l1 = l1.next
if l2:
l2 = l2.next
if carry != 0: # 注意这一步 若最后相加大于10则需要进位
restemp.next = ListNode(1)
return res.next # 排除掉虚拟节点
-
时间复杂度: O ( m a x ( m , n ) ) O(max(m,n)) O(max(m,n)),m,n分别为两链表的长度
-
空间复杂度: O ( 1 ) O(1) O(1)
2、奇偶链表(328)
题目描述:
【中等题】
给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
思路分析:
\quad \quad
最简单的方法就是建立两个奇偶链表,然后把偶链表放在奇链表后面即可。
1、建立两链表,首先应建立两链表头节点:奇链表头节点为原链表头节点,偶链表头节点应为原链表头节点的下一节点。
2、遍历原链表构建奇偶链表,执行以下循环:
- 奇链表头节点的下一节点应为偶链表头节点的下一节点,然后将奇链表头节点更改为下一节点;
- 偶链表头节点的下一节点应为奇链表头节点的下一节点,然后将偶链表头节点更改为下一节点。
循环执行条件:当偶链表的头节点不为空或偶链表头节点的下一节点不为空
3、将奇链表与偶链表结合起来。
【python3 代码实现】
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def oddEvenList(self, head: ListNode) -> ListNode:
if head is None:
return None
oddhead=head # 奇数链表的头节点
evenhead=head.next # 偶数链表的头节点
even=evenhead
while evenhead != None and evenhead.next != None:
oddhead.next=evenhead.next
oddhead=oddhead.next
evenhead.next=oddhead.next
evenhead=evenhead.next
oddhead.next=even
return head
-
时间复杂度: O ( n ) O(n) O(n)
-
空间复杂度: O ( 1 ) O(1) O(1)
3、两数相加II(445)
题目描述:
【中等题】
给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
进阶:
如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。
思路分析:
题解一:先求和再构成链表
选择easy模式的话,可以直接先求出和,再构建链表。其前提是python中没有最大的整数,所以无论怎么着不会越界!
1、求和:遍历两个链表,以字符串的形式存储;然后将其转化为整数型,再相加。
2、构成链表:相加的数再以字符串的形式呈现,然后遍历字符串,依次构建新节点,构建成链表。
【python 代码实现】
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
s1=''
s2=''
while l1:
s1+=str(l1.val)
l1=l1.next
while l2:
s2+=str(l2.val)
l2=l2.next
s=int(s1)+int(s2)
s=str(s)
temphead=ListNode(0)#建立虚拟节点
head=temphead
for i in s:
temphead.next=ListNode(int(i))
temphead=temphead.next
del temphead # 释放内存
return head.next
-
时间复杂度: O ( m a x ( m , n ) ) O(max(m,n)) O(max(m,n))
-
空间复杂度: O ( m + n ) O(m+n) O(m+n)
题解二:逆序—栈+取出相加
\quad \quad 本题的主要难点在于链表中数位的顺序与我们做加法的顺序是相反的,为了逆序处理所有数位,我们可以使用栈:把所有数字压入栈中,再依次取出相加,相加过程与两数相加(2)题一样。计算过程中需要注意进位的情况。
1、每次将链头元素入栈,栈中每次取出的就是链尾元素
2、用sum记录两栈尾元素之和,创建新链表表头结点head准备链接新生成的结点元素
3、创建新链结点node存储对10取余后的元素,用carry记录除以10得到的进位值0或1
4、每次让新生成的node指向ans(其为空节点),然后新生成的节点赋值给ans,依次逆序链接到新链表头,最后返回ans就是一条新链。
【python3 代码实现】
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
s1,s2=[],[]
# l1,l2进栈
while l1:
s1.append(l1.val)
l1=l1.next
while l2:
s2.append(l2.val)
l2=l2.next
# 出栈,求和,进位处理,逆序添加节点
carry=0 # 进位处理
ans=None
while s1 or s2 or carry !=0:
x=s1.pop() if s1 else 0
y=s2.pop() if s2 else 0
sum=x+y+carry
# 求出进位值0/1
carry=sum // 10
# 创建节点
curnode=ListNode(sum % 10)
# 每次将节点指向空节点 实现反向的链表
curnode.next=ans
ans=curnode
return ans
-
时间复杂度: O ( m a x ( m , n ) ) O(max(m,n)) O(max(m,n))
-
空间复杂度: O ( m + n ) O(m+n) O(m+n)