链表
160. 相交链表
链表
- 🔑🔑 难度:Easy 简单
示例1: 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5]
,链表 B 为 [5,6,1,8,4,5]
。
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
tmpA, tmpB = headA, headB
while tmpA != tmpB:
if tmpA == None:
tmpA = headB
else:
tmpA = tmpA.next
if tmpB == None:
tmpB = headA
else:
tmpB = tmpB.next
return tmpA
思路:直接背吧.. 从两个链表头开始遍历,一直到尾,如果先为None了,就指向另一个链表头,继续遍历,直到两个指针相等,就是相交的节点。如果一直没有相交,说明它们两个都是独立的。自然直接返回None.
206. 反转链表
必看经典题
- 🔑🔑 难度:Easy 简单
示例1: 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
prev = None
curr = head
while curr != None:
tmp = curr.next # 保存下后面还没处理的
curr.next = prev # 把未来替换成过去的
prev = curr # 把过去的扩展到现在
curr = tmp # 剩下的都是后面还没处理的
return prev
个人更习惯迭代的做法。重要的是要记得引入 prev 指针。总共 4 行!
141. 环形链表
经典题!
- 🔑🔑 难度:Easy 简单
示例1: 给你一个链表的头节点
head
,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪
next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回
true
。 否则,返回false
。
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
if head == None:
return False
l = head
r = head
while r != None:
if r.next != None:
l = l.next
r = r.next.next
else:
return False
if r == l:
return True
return False
注意快慢指针。一开始都从head出发,一定要注意判断 fast.next
是否为空!另一个值得注意的事情是,还有一种快慢指针是 fast 直接赋 head.next
。但是这种判断在下一道题中就有所不同了。
142. 环形链表 II
经典题!2!
- 🔑🔑 难度:Medium 中等
示例1: 给定一个链表的头节点
head
,返回链表开始入环的第一个节点。 如果链表无环,则返回null
。如果链表中有某个节点,可以通过连续跟踪
next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果pos
是 -1,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改链表。
输入:
head = [3,2,0,-4]
,pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head == None:
return None
l = head
r = head
while r != None:
l = l.next
if r.next == None:
return None
r = r.next.next
if l == r:
tmp = head
while tmp != l:
tmp = tmp.next
l = l.next
return tmp
return None
记忆:相遇的时候,慢的走了 N
,快的走了2 * N
。只需要此时从head开始继续走一个指针,就能在相交的地方再度相聚了。
19. 删除链表的倒数第k个节点
- 🔑🔑 难度:Medium 中等
示例1:
给你一个链表,删除链表的倒数第
n
个结点,并且返回链表的头结点。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
result = ListNode(0)
result.next = head
slow = head
fast = head
for i in range(n):
fast = fast.next
if fast == None:
break
if fast == None:
return head.next
while fast.next != None:
fast = fast.next
slow = slow.next
slow.next = slow.next.next
return result.next
要注意,可能要删除的是第一个节点!所以分情况讨论,如果删除的是第一个节点,那么head.next
,否则就利用快慢指针进行操作。