24. 两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
题目链接:链接
自己理解题目:建一个虚节点,其下一个节点是头节点,遍历整个链表,计数变量计数到2时,交换pre和cur的值,并重新计数,遍历完后返回头节点,全部过程中只完成值的赋值,指针不变化。
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head==None:
return
cur=head #头节点
pre=ListNode(-1)
pre.next=head #前一个节点
cnt=0 #计数变量
while cur: #遍历链表
cnt+=1 #每遍历一次计数变量加1
if cnt==2: #计数到2时,交换相邻两个节点
cnt=0 #计数清零
tmp=pre.val
pre.val=cur.val
cur.val=tmp #交换节点值
cur=cur.next
pre=pre.next #两个指针往前走
return head #返回头节点
反思总结:1、当输入头节点为[ ]时,如果return [ ] 会报错,自己理解的是因为返回的是链表,不能是列表。
2、参考答案是打断原有链表,重新建立的新链表。
参考答案:
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
dummy_head = ListNode(next=head)
current = dummy_head #cur指向头节点的前一节点
# 必须有cur的下一个和下下个才能交换,否则说明已经交换结束了
while current.next and current.next.next:
temp = current.next # 防止节点修改----保存1奇数节点
temp1 = current.next.next.next #----保存3奇数节点
current.next = current.next.next #2偶数节点赋给1奇数节点
current.next.next = temp #1奇数节点赋给2偶数节点
temp.next = temp1 #1奇数节点往后遍历至3奇数节点
current = current.next.next #0偶数节点遍历至2偶数节点
return dummy_head.next
19. 删除链表的倒数第 N 个结点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
题目链接:链接
自己理解题目:先想着计算链表长度num,然后通过for i in range(num-n)遍历链表,使指针指向倒数第n+1个节点时,删除第n个节点。。。循环太多,复杂。。。
后面看到用相差n+1个节点的两个指针遍历链表的方法,很方便。
反思总结:
参考答案:
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 。
题目链接:链接
自己理解题目:相交的意思没搞明白,一看题解,相交就是遍历到该处时两个链表的指针相等,即curA==curB,属于题目理解不透的问题写不出来。
反思总结:讲真版本一的解法没看太懂,但最后两种是看懂了的
参考答案:
(版本一)求长度,同时出发
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:
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
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
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 #将链表A、B连接,一直遍历至相等的节点为止
pointerB = pointerB.next if pointerB else headA #将链表A、B连接,一直遍历至相等的节点为止
# 如果相交,指针将位于交点节点,如果没有交点,值为None
return pointerA
142. 环形链表 II
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
自己理解题目:之前看过这个题目,不会做,看了答案理解了,现在还不不会。。。该反省啊!
反思总结:再理解题目和代码吧。题解的
参考答案:
(版本一)快慢指针法
# 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:
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