LeetCode 206. 反转链表
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def reverseList(self, head):
"""
:type head: Optional[ListNode]
:rtype: Optional[ListNode]
"""
dummy_head = ListNode(val=0, next=None) ### 虚拟头结点设置
dummy_head.next = head
#### 与反转数组不同,反转数组是针对数组下标进行修改,链表需要根据指针
if dummy_head.next == None or head.next == None: ##空链表 / 只有一个元素的链表
return dummy_head.next
else:
left, right = dummy_head, dummy_head.next
while right != None: #### 注意链表的操作顺序,这个是关键
if left == dummy_head:
temp = right.next
left.next = None
right.next = None
left = right
right = temp
else:
temp = right.next
right.next = left
left = right
right = temp
if right == None:
dummy_head.next = left
return dummy_head.next
思路:
- 对于虚拟头结点部分,需要断开虚拟头结点的next指针和将头结点的指针改为尾节点,即将头节点的指针改为None
- 对于非虚拟头结点部分,需要通过两个指针来进行操作,其中需要先创建一个temp变量来存储right.next,以获得下一次移动的位置,因为后续right.next会被修改了。随后进行两个相邻节点的反转操作,并将双指针同步右移一位。
LeetCode 19.删除链表的倒数第N个节点
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: Optional[ListNode]
:type n: int
:rtype: Optional[ListNode]
"""
### 删除倒数第N个节点,意味着我们要在倒数第N+1个节点位置进行操作,对倒数第N个节点进行删除。
### 单向链表只能单向移动,要找到倒数第N+1节点的位置,可以使用滑动窗口,滑动窗口的大小利用双指针实现
dummy_head = ListNode(val=0, next=None)
dummy_head.next = head
left, right = dummy_head, dummy_head
k = 0
while k != n+1: ### 先满足滑动窗口大小
right = right.next
k += 1
while right != None: ### 找到倒数第n+1个节点
left = left.next
right = right.next
delete = left.next
left.next = delete.next
delete = None
return dummy_head.next
思路:
-
删除倒数第N个节点,意味着我们要在倒数第N+1个节点位置进行操作,对倒数第N个节点进行删除。
-
单向链表只能单向移动,要找到倒数第N+1节点的位置,可以使用滑动窗口,滑动窗口的大小利用双指针实现
LeetCode 160.链表相交
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
dummy_head_A = ListNode(0)
dummy_head_B = ListNode(0)
dummy_head_A.next = headA
dummy_head_B.next = headB
### 链表相交一定是取决于最短那方,因此最长那方不需要完全遍历
A_length = self.get_Length(dummy_head_A)
B_length = self.get_Length(dummy_head_B)
min_length = min (A_length, B_length)
if min_length == 0: ### 存在空链表
return None
k = 0
if A_length > B_length: ### B是最短
while k != A_length - min_length:
headA = headA.next
k += 1
elif A_length < B_length:
while k != B_length - min_length:
headB = headB.next
k += 1
while headA != None and headA != headB:
headA = headA.next
headB = headB.next
if headA == headB and headA != None:
return headA
else:
return None
def get_Length(self, head):
right = head.next
total_num = 0
if head.next == None:
return total_num
else:
while right != None:
right = right.next
total_num += 1
return total_num
思路:
- 链表相交一定取决于最短那方,最长那方不需要都进行遍历。因此需要求出两个链表的各自长度,并将最长链表的起始遍历位置改为其长度 - 最短链表长度。之后链表同时进行遍历判断。
- 链表相交是指针相等,因此通过判断指针是否一致就可以判断出是否相交,要注意指针相等不一定是相交,因为还有None的情况需要排除。
Leet Code 142.环形链表II
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
### 这道题需要画图加以理解,涉及数学推理的理解。
dummy_head = ListNode(0)
dummy_head.next = head
if head == None or head.next == None: ## 空链表 / 单元素链表 不存在环状
return None
slow, fast = head, head
### 判断不是环状。fast和slow指针永远不会相遇。因此可以转换为“链表相交”问题的思路
### 判断是环状。首先需要找到二者在环内相遇时,fast指针的位置
while fast == head or slow != fast:
if fast == None or fast.next == None:
return None
slow = slow.next
fast = fast.next.next
if slow == fast: ### 如果不加这句,会陷入死循环,因为相交点在头结点的话,while循环会一直执行
break
slow = head
fast = fast
while slow != fast:
slow = slow.next
fast = fast.next
return slow ### 此时为刚好进入环的索引节点
思路:
- 首先需要判断链表的长度是否能形成环状。
- 记住结论:fast比slow速度快一位的话,判断 fast 在移动过程中是否会为None,如果会,则不是环。反之,fast 跟 slow一定会在环内相遇,此时fast 在环内相遇位置开始, slow在起点位置开始,二者以相同一位的速度进行移动,最终一定是在相交点相遇。