两两交换链表中的节点
题目
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 示例 1: 输入:head = [1,2,3,4] 输出:[2,1,4,3] 示例 2: 输入:head = [] 输出:[] 示例 3: 输入:head = [1] 输出:[1] 提示: 链表中节点的数目在范围 [0, 100] 内 0 <= Node.val <= 100思路
用虚拟头节点,然后三个指针,交换顺序,判断条件就是当前节点的下一个或者下下个是不是None
代码
# 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: 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注意点
1. 谁会断,谁就得用一个临时变量保存
2. and运算法,注意前面是next,后面是next.next,因为and是短路运算法,如果next.next放前面,会出现空指针异常,因为如果只有一个后继,下一个指针不知道指向的哪里
题目链接
24. 两两交换链表中的节点 - 力扣(LeetCode)
删除链表的倒数第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] 提示: 链表中结点的数目为 sz 1 <= sz <= 30 0 <= Node.val <= 100 1 <= n <= sz思路
快慢指针,一个在前面找到最后一个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: 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题目链接
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
链表相交
题目
思路
把二者相差的长度,剪掉,这样后面就是同样的长度,然后比较一下地址如果相同,就说明一样,如果到最后地址都不相同,就说明不对
需要注意的点:
1. 判断想不想等,用的是is,而不是==,因为我们判断的是地址是否相同,而不是数值
代码
class Solution: def getIntersectionNode(self, headA: ListNode, headB: ListNode): lenA = 0 lenB = 0 curA = headA curB = headB # 计算 A 的长度 while curA: lenA += 1 curA = curA.next # 计算 B 的长度 while curB: lenB += 1 curB = curB.next # 指针重新回到头节点 curA = headA curB = headB # 较长链表先走长度差 if lenA > lenB: for _ in range(lenA - lenB): curA = curA.next else: for _ in range(lenB - lenA): curB = curB.next # 一一比较节点 while curA: if curA is curB: return curA curA = curA.next curB = curB.next return None题目链接
面试题 02.07. 链表相交 - 力扣(LeetCode)
环形链表II
题目
思路
1. 判断是否有环路,首先快慢指针,一个每次走一步,一个每次走两步,然后判断是否有一个时刻想等,如果想等说明是环路,但是注意判断条件,当前fast和fast.next,因为fast指针一次走两个,需要判断下一个是不是空
2. 判断环路在哪里成环,这里就需要一个数学计算
slow = x + y
fast = x + y + n(y + z) (n>=1)
速度比 1:2
2(x+y) = x + y + n(y + z)
求x x = (n-1)(y+z) + z
当n = 1,x = z,当n>1, x = n-1圈 + z
说明x和z一样长,说明指针从相遇的地方走到环的开头 和 从head走到环的开头一样长,就能 设处一个等式,最后得到结果
代码
#(版本一)快慢指针法 # 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题目链接
142. 环形链表 II - 力扣(LeetCode)
总结
链表就是虚拟头节点很重要,其他的就是运用链表的性质来做