一、24. 两两交换链表中的节点
题目链接:24. 两两交换链表中的节点 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——24. 两两交换链表中的节点
视频讲解:帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点_哔哩哔哩_bilibili
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy_head = ListNode(next = head)
cur = dummy_head
# 遍历停止条件:偶数节点cur.next不为空,奇数节点cur.next.next不为空
# 先判断cur.next再判断cur.next.next为了防止空指针异常报错
while cur.next != None and cur.next.next != None:
# 定义两个临时节点,存储节点1和节点3.不保存节点2因为此时已经变成cur.next了
temp = cur.next
temp1 = cur.next.next.next
# 交换节点
cur.next = cur.next.next
cur.next.next = temp
temp.next = temp1
cur = cur.next.next
return dummy_head.next
Notes:cur需要指向将要操作的两个节点的前一个节点,如:要操作3、4,cur则需要指向2。初始cur指向定义的虚拟节点。
二、19.删除链表的倒数第N个节点
题目链接:19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——19.删除链表的倒数第N个节点
视频讲解:链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点_哔哩哔哩_bilibili
Note:cur指针要指向操作节点的前一个节点
思路:双指针法,快指针先走n+1步,然后快慢指针同时移动,当快指针指向None时,慢指针指向的就是删除节点的前一个节点。
# 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]:
dummy_head = ListNode(next = head)
fast = dummy_head
slow = dummy_head
# 快指针走n+1步
for i in range(n+1):
fast = fast.next
# 同时移动两个指针
while fast:
slow = slow.next
fast = fast.next
# 删除节点
slow.next = slow.next.next
return dummy_head.next
三、面试题 02.07. 链表相交
题目链接:面试题 02.07. 链表相交 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——面试题 02.07. 链表相交
思路:让A B两个链表尾部对齐,后两个指针也对齐开始查找,找到相同的就返回
Note:数值相同,不代表指针相同。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
# 初始化A B链表长度
len_A, len_B = 0, 0
# 获取A链表长度
cur_A = headA
while cur_A:
cur_A = cur_A.next
len_A += 1
# 获取B链表长度
cur_B = headB
while cur_B:
cur_B = cur_B.next
len_B += 1
# 复位cur_A, cur_B指向headA, headB
cur_A, cur_B = headA, headB
# 分两种情况A比B长
if len_A > len_B:
# 让两个链表尾部对齐
for i in range (len_A - len_B):
cur_A = cur_A.next
# 开始遍历
while cur_A:
# 如果两个相等则返回交点
if cur_A == cur_B:
return cur_A
# 否则继续遍历
else:
cur_A = cur_A.next
cur_B = cur_B.next
# 没有交点返回空集
return None
else:
for i in range (len_B - len_A):
cur_B = cur_B.next
while cur_B:
if cur_B == cur_A:
return cur_B
else:
cur_A = cur_A.next
cur_B = cur_B.next
return None
四、142.环形链表II
题目链接:142. 环形链表 II - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——142.环形链表II
视频讲解:把环形链表讲清楚! 如何判断环形链表?如何找到环形链表的入口? LeetCode:142.环形链表II_哔哩哔哩_bilibili
判断是否有环:双指针法,快指针每次走两个节点,慢指针一次走一个节点,两个指针一定会在环内相遇。
找环的入口:相遇点和头节点同时以相同速度分别出发一个指针 index1、index2,相交点就是环的入口,具有推导见文章讲解。
# 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]:
# 定义两个指针
fast = head
slow = head
# 移动快慢指针
while fast and fast.next: # 终止条件为快指针或快指针下一个点为空,因为快指针一次跳两步,要保证fast.next不为空
fast = fast.next.next
slow = slow.next
# 判断是否有环,也就是快慢指针是否能相遇
if slow == fast:
index1 = fast # 从相遇节点走,index2 = slow也可以
index2 = head # 从头走
# 两个index相遇时候终止
while index1 != index2:
index1 = index1.next
index2 = index2.next
return index1
return None