一、两数相加
此题为leetcode第2题
思路:链表的头结点是个位,依次往后是十位、百位等,在每位的数相加时可能有进位,我们要预先有个进位flag=0,后续可能为0也可能为1,每次相加时都要加上这个进位。加完后的数可能大于10,如果大于10则flag=1,否则flag=0。然后这个数取余便是这位相加后的结果。同时以此遍历两个链表,一个到结尾时另一个继续遍历。
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
res= head = ListNode(0)
p1, p2 = l1, l2
flag = 0
while p1 or p2 or flag != 0:
a1 = p1.val if p1 else 0
a2 = p2.val if p2 else 0
if p1:
p1 = p1.next
if p2:
p2 = p2.next
temp = a1 + a2 + flag
flag = temp // 10
head.next = ListNode(temp % 10)
head = head.next
return res.next
二、两数相加II
此题为leetcode第445题
思路:和第一个题不一样的是,这里数字最高位是链表的开始,而且不能翻转链表。可以遍历链表将val存入栈中,这样出栈的时候就是低位先出来了。剩下相加的过程就和上一题几乎一样了。
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
stack1, stack2 = [], []
p1, p2 = l1, l2
while p1:
stack1.append(p1.val)
p1 = p1.next
while p2:
stack2.append(p2.val)
p2 = p2.next
res = None
flag = 0
while stack1 or stack2 or flag != 0:
a1 = stack1.pop() if stack1 else 0
a2 = stack2.pop() if stack2 else 0
temp = a1 + a2 + flag
flag = temp // 10
node = ListNode(temp % 10)
node.next = res
res = node
return res
三、重排链表
此题为leetcode第143题
思路:分为三步:(1)先利用快慢指针,找到链表的中点,将链表分为两部分;(2)反转后半部分;(3)两部分错位合并
class Solution:
def reorderList(self, head: ListNode) -> None:
"""
Do not return anything, modify head in-place instead.
"""
# 链表长度小于等于2
if head is None or head.next is None or head.next.next is None:
return
# 快慢指针找到链表中间
fast, slow = head, head
while fast is not None and fast.next is not None:
fast = fast.next.next
slow = slow.next
# 反转后半部分
fast = slow.next
slow.next = None
fast = self.reverse(fast)
# 后半部合并到前半部
while fast:
p2 = fast.next
fast.next = head.next
head.next = fast
head = fast.next
fast = p2
# 反转链表
def reverse(self, head):
if head is None or head.next is None:
return head
temp = self.reverse(head.next)
head.next.next = head
head.next = None
return temp
四、排序链表
此题为leetcode第148题
思路:(1)首先如果没有“常数级空间复杂度”的限制,此题使可以用归并排序,显然是递归操作,空间复杂度为
O
(
n
)
O(n)
O(n)。在每层递归中,我们需要找到当前链表的中点。使用快慢指针,慢指针指向head,快指针指向head.next,每次慢指针走一步,快指针走两步,到结尾后慢指针后面部分的链表为被切割的一半链表。将这两半链表进行递归,返回排序好的连个链表的头指针,对这两个排好序的链表进行归并操作。
class Solution:
def sortList(self, head: ListNode) -> ListNode:
# 归并排序
if not head or not head.next:
return head
# 切割链表,找到链表中间
slow, fast = head, head.next
while fast and fast.next:
fast, slow = fast.next.next, slow.next
mid, slow.next = slow.next, None
# 递归左右两边
left, right = self.sortList(head), self.sortList(mid)
# merge `left` and `right` linked list and return it.
h = res = ListNode(0)
while left and right:
if left.val < right.val:
h.next, left = left, left.next
else:
h.next, right = right, right.next
h = h.next
if left:
h.next = left
else:
h.next = right
return res.next
(2)在常数级空间复杂度的限制下,可以使用自底向上的归并排序,迭代完成。迭代的过程如下图所示:
class Solution:
def sortList(self, head: ListNode) -> ListNode:
# 自底向上
# 计算链表长度
h, length = head, 0
while h:
length += 1
h = h.next
intv = 1 # 每层归并时,小单元的长度
res = ListNode(0)
res.next = head
# 开始归并
while intv < length:
prev, h = res, res.next
while h: # 对于每一个intv进行遍历
# 找到第一个需要合并的单元的头节点
h1, i = h, intv
while h and i:
h, i = h.next, i - 1
if i: # 如果i大于0,说明h==none,那么这个intv层就只有这一个单元了,无法进行合并,进入下一层
break
# 找到第二个需要合并的单元的右节点
h2, i = h, intv
while h and i:
h, i = h.next, i - 1
# c1、c2为h1、h2的长度
c1, c2 = intv, intv - i
# 合并
while c1 and c2:
if h1.val < h2.val:
prev.next, h1, c1 = h1, h1.next, c1 - 1
else:
prev.next, h2, c2 = h2, h2.next, c2 - 1
prev = prev.next
# 合并结束后,将prev指向下次要合并的单元的头节点
prev.next = h1 if c1 else h2
while c1 > 0 or c2 > 0:
prev, c1, c2 = prev.next, c1 - 1, c2 - 1
prev.next = h
intv *= 2
return res.next