链表进阶系列2
24 两两交换链表中的结点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例2:
输入:head = []
输出:[]
示例3:
输入:head = [1]
输出:[1]
我的代码
没看任何资料,自己整理逻辑写出来的。
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]:
virtual = ListNode(0,head)
first = virtual
second = first.next
while first.next != None and first.next.next != None:
temp = second.next
first.next = temp
second.next = temp.next
temp.next = second
first = second
second = second.next
return virtual.next
力扣的示例代码
# 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]:
if head==None or head.next==None:
return head
next = head.next
head.next = self.swapPairs(next.next)
next.next = head
return next
代码随想录的代码
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
dummy_head = ListNode(next=head)
current = dummy_head
# 必须有cur的下一个和下下个才能交换,否则说明已经交换结束了
while current.next and current.next.next:
temp = current.next # 防止节点修改
temp1 = current.next.next.next
current.next = current.next.next
current.next.next = temp
temp.next = temp1
current = current.next.next
return dummy_head.next
19 删除链表的倒数第 N 个结点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例2:
输入:head = [1], n = 1
输出:[]
示例3:
输入:head = [1,2], n = 1
输出:[1]
我的代码
小记:这题第一次看的时候一点思路没有,看完解答后恍然大悟,还是对链表的数据结构特点不熟悉,也对快慢指针的灵活运用不熟悉。
大致的思路:双指针,fast先移动n步,然后slow,fast一起移动,fast.next为空时,slow.next = slow.next.next即可。
根据代码随想录的思路,明白后自己写出的代码:
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]:
virtual = ListNode(0,head)
slow = virtual
fast = virtual
for i in range(n):
fast = fast.next
while fast.next :
slow = slow.next
fast = fast.next
slow.next = slow.next.next
return virtual.next
力扣的示例代码
# 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]:
head_dummy = ListNode()
head_dummy.next = head
pre = head_dummy
cur = head_dummy
while n >= 0:
cur = cur.next
n -= 1
while cur != None:
pre = pre.next
cur = cur.next
pre.next = pre.next.next
return head_dummy.next
代码随想录的代码
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
# 创建一个虚拟节点,并将其下一个指针设置为链表的头部
dummy_head = ListNode(0, head)
# 创建两个指针,慢指针和快指针,并将它们初始化为虚拟节点
slow = fast = dummy_head
# 快指针比慢指针快 n+1 步
for i in range(n+1):
fast = fast.next
# 移动两个指针,直到快速指针到达链表的末尾
while fast:
slow = slow.next
fast = fast.next
# 通过更新第 (n-1) 个节点的 next 指针删除第 n 个节点
slow.next = slow.next.next
return dummy_head.next
160 链表相交
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
(示例情况参见力扣官网吧,有图方便理解)
160 链表相交
小记1:这题第一次看的时候一点思路没有,看完解答后恍然大悟,还是对链表的数据结构特点不熟悉,没有意识到链表不像数组,直观上给出的数据的长度,但是我们可以通过遍历,在O(n)的时间内,获得这一信息,在本题中,链表长度是十分重要的信息。
小记2:这里的相等是指的是指针相等,不是数值相等,因为链表中不同结点的数值可能相等。
我的代码
大致的思路:先求出两个链表的长度,然后作差,让短的链表先前进x步,然后只要两个指针不相等且不为None,就一直next。
根据代码随想录的思路,明白后自己写出的代码:
class ListNode:
def __init__(self,val=0,next=None):
self.val = val
self.next = next
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
virtualA = ListNode(0,headA)
virtualB = ListNode(0,headB)
curA = virtualA
curB = virtualB
countA = countB = 0
while virtualA.next:
countA = countA + 1
virtualA = virtualA.next
while virtualB.next:
countB = countB + 1
virtualB = virtualB.next
if countA >= countB:
diff = countA - countB
for i in range(diff):
curA = curA.next
while curA:
if curB==curA:
return curA
else:
curB = curB.next
curA = curA.next
else:
return None
else:
diff = countB - countA
for i in range(diff):
curB = curB.next
while curA:
if curB==curA:
return curA
else:
curB = curB.next
curA = curA.next
else:
return None
力扣的示例代码
# 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:
lenA, lenB = 0, 0
cur = headA
while cur:
cur = cur.next
lenA += 1
cur = headB
while cur:
cur = cur.next
lenB += 1
curA, curB = headA, headB
if lenA > lenB:
curA, curB = curB, curA
lenA, lenB = lenB, lenA
while (lenB - lenA) > 0:
curB = curB.next
lenB -= 1
while curA:
if curA == curB:
return curA
else:
curA = curA.next
curB = curB.next
return None
代码随想录的代码
(版本一)求长度,同时出发
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
lenA, lenB = 0, 0
cur = headA
while cur: # 求链表A的长度
cur = cur.next
lenA += 1
cur = headB
while cur: # 求链表B的长度
cur = cur.next
lenB += 1
curA, curB = headA, headB
if lenA > lenB: # 让curB为最长链表的头,lenB为其长度
curA, curB = curB, curA
lenA, lenB = lenB, lenA
for _ in range(lenB - lenA): # 让curA和curB在同一起点上(末尾位置对齐)
curB = curB.next
while curA: # 遍历curA 和 curB,遇到相同则直接返回
if curA == curB:
return curA
else:
curA = curA.next
curB = curB.next
return None
(版本二)求长度,同时出发 (代码复用)
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
lenA = self.getLength(headA)
lenB = self.getLength(headB)
# 通过移动较长的链表,使两链表长度相等
if lenA > lenB:
headA = self.moveForward(headA, lenA - lenB)
else:
headB = self.moveForward(headB, lenB - lenA)
# 将两个头向前移动,直到它们相交
while headA and headB:
if headA == headB:
return headA
headA = headA.next
headB = headB.next
return None
def getLength(self, head: ListNode) -> int:
length = 0
while head:
length += 1
head = head.next
return length
def moveForward(self, head: ListNode, steps: int) -> ListNode:
while steps > 0:
head = head.next
steps -= 1
return head
(版本三)求长度,同时出发 (代码复用 + 精简)
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
dis = self.getLength(headA) - self.getLength(headB)
# 通过移动较长的链表,使两链表长度相等
if dis > 0:
headA = self.moveForward(headA, dis)
else:
headB = self.moveForward(headB, abs(dis))
# 将两个头向前移动,直到它们相交
while headA and headB:
if headA == headB:
return headA
headA = headA.next
headB = headB.next
return None
def getLength(self, head: ListNode) -> int:
length = 0
while head:
length += 1
head = head.next
return length
def moveForward(self, head: ListNode, steps: int) -> ListNode:
while steps > 0:
head = head.next
steps -= 1
return head
(版本四)等比例法
# 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:
# 处理边缘情况
if not headA or not headB:
return None
# 在每个链表的头部初始化两个指针
pointerA = headA
pointerB = headB
# 遍历两个链表直到指针相交
while pointerA != pointerB:
# 将指针向前移动一个节点
pointerA = pointerA.next if pointerA else headB
pointerB = pointerB.next if pointerB else headA
# 如果相交,指针将位于交点节点,如果没有交点,值为None
return pointerA
142 环形链表II
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例2:
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例3:
输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
小记:这道题很难,认为是链表部分最难的一道题了,具体分析也没什么好写的,只能说代码随想录的题目解析全是精华。
142 环形链表II–全是精华
代码随想录的代码
(版本一)快慢指针法
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# If there is a cycle, the slow and fast pointers will eventually meet
if slow == fast:
# Move one of the pointers back to the start of the list
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow
# If there is no cycle, return None
return None
(版本二)集合法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
visited = set()
while head:
if head in visited:
return head
visited.add(head)
head = head.next
return None
力扣的示例代码
# 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
pos = -1
while fast != None and fast.next != None:
fast = fast.next.next
slow = slow.next
if fast == slow:
index1 = slow
index2 = head
pos = 0
break
if pos == -1:
return None
while index1 != index2:
index1 = index1.next
index2 = index2.next
pos += 1
return index1