目录
剑指 Offer 52. 两个链表的第一个公共节点(easy)
19. 删除链表的倒数第N个节点(medium)
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
【注意】[1] 1,这种删除头结点的情况
进阶:一次扫描出结果(通过构造哑结点dummy)
构建双指针p1
与p2
,p1
先走n
步,然后一同运动,当p1
指向表尾,p2
指向的next
即是倒数第N个节点,删除即可。
[LeetCode] 19. Remove Nth Node From End of List 删除链表的倒数第N个节点 @python
203. 移除链表元素(easy)
删除链表中等于给定值 val 的所有节点。
输入: 1->2->6->3->4->5->6, val = 6 输出: 1->2->3->4->5
def removeElements(self, head: ListNode, val: int) -> ListNode:
if not head:return head
dummy = ListNode(0)
dummy.next = head
prev = dummy
while prev.next:
if prev.next.val == val:
prev.next = prev.next.next
else:
prev = prev.next
return dummy.next
整个代码的调用从main开始写起,不太会。。。研究了一下午(?),看这里!here(*^▽^*)。
237. 删除链表中的节点(easy)
输入:head = [4,5,1,9], node = 5
输出:[4,1,9]
解释:给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9
class Solution(object):
def deleteNode(self, node):
# 只有对要删除节点node的访问权限
"""
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
"""
# 题目给的是删除节点,那说明这个节点可以舍弃了,我们把下一个节点的值拷贝
# 给当前要删除的节点,再删除下一个节点。
node.val = node.next.val
node.next = node.next.next
206. 反转链表(easy)
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
动态图有助于理解:206. 反转链表 - NuoHui的文章 - 知乎
迭代法:
- 尾节点指好,防止丢失节点;
- 当前节点,反指;
- 前节点后移;
- 尾节点后移;
初始赋值
def reverseList(self, head):
if not head: return head
prev = None
cur = head
while cur:
tail = cur.next
cur.next = prev
prev = cur
cur = tail
return prev
递归法:
当遍历到尾结点时,开始往回走
def recursive(self, head):
if (head == None or head.next == None):
return head
# new_head指向linklist尾结点
new_head = self.recursive(head.next)
head.next.next = head
head.next = None
return new_head
92. 反转链表 II(medium)
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明: 1 ≤ m ≤ n ≤ 链表长度。
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
if not head:return head
prev = None
cur = head
i = 1
while i<m and cur:
prev = cur
cur = cur.next
i+=1
# tag 做标记
p1 = prev
p2 = cur
while i<=n and cur: # 正常反转链表操作
tail = cur.next
cur.next = prev
prev = cur
cur = tail
i+=1
# 特殊判断,如果是头结点开始
if m == 1:
p2.next = cur
return prev
p2.next = cur
p1.next = prev
return head
160. 相交链表(easy)
思路:
def getIntersectionNode(self, headA, headB):
lenA, lenB = 0, 0
pA = headA
pB = headB
while pA:
pA = pA.next
lenA += 1
while pB:
pB = pB.next
lenB += 1
pA = headA
pB = headB
if lenA > lenB:
for i in range(lenA - lenB):
pA = pA.next
else:
for i in range(lenB - lenA):
pB = pB.next
while pA != pB:
pA = pA.next
pB = pB.next
return pA
def double_pointer(self, headA, headB):
if (not headA or not headB):
return None
# 定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部, 最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差)
# 两个指针等于移动了相同的距离, 有交点就返回, 无交点就是各走了两条指针的长度
pA = headA
pB = headB
# 在这里第一轮体现在pA和pB第一次到达尾部会移向另一链表的表头, 而第二轮体现在如果pA或pB相交就返回交点, 不相交最后就是null == null
while pA != pB:
pA = pA.next if pA else headB
pB = pB.next if pB else headA
return pA
141. 环形链表(easy)
142. 环形链表 II(medium)
关于环形链表问题的总结,from神不烦 and Rotten_Pencil
1.快慢指针一直到相遇时的循环次数等于环的长度。(可推导)
2.快慢指针相遇点到环入口的距离 = 链表起始点到环入口的距离。(可推导)
- 判断是否为环形链表
思路:使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。
- 若为环形链表,求环入口点
思路:快慢指针相遇点到环入口的距离 = 链表起始点到环入口的距离
- 求环的长度
思路:记录下相遇点p,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度s
- 判断两个链表是不是相交
思路:如果两个链表相交,那么这两个链表的尾节点一定相同。直接判断尾节点是否相同即可。这里把这道题放在环形链表,因为环形链表可以拆成Y字的两个链表。
代码:141
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
p1 = head # 慢指针
p2 = head # 快指针
# while p1 and p2:
while p2 and p2.next:
# 为什么这样判断可以??
p1 = p1.next
p2 = p2.next.next
# 如何判断遇见两次了呢?已解
if p1 == p2:
return True
return False
代码142:
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
# 环入口怎么求?
# 快慢指针的相遇点到环入口的距离 == 链表起始点到环入口的距离
p1 = head # 慢指针
p2 = head # 快指针
encounter = head
flag = 0
while p2 and p2.next:
p1 = p1.next
p2 = p2.next.next
if p1 == p2:
# 相遇点
encounter = p1
flag = 1
break
if not flag:
return None
# print(encounter.val) # -4
start = head
pos = 0
while start and encounter:
if start == encounter:
pos += 1
# return pos # # 返回相遇节点的位置
return start # 返回相遇点(ac)
start = start.next
encounter = encounter.next
# return -1 # 返回相遇节点的位置
return None
剑指 Offer 06. 从尾到头打印链表(easy)
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
rs = []
if not ListNode:return rs
while listNode:
rs.append(listNode.val)
listNode = listNode.next
return rs[::-1]
83. 删除排序链表中的重复元素(easy)
q是不重复节点的第一个位置。
a 和 c 的长度是1。
# -*- coding:utf-8 -*-
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def deleteDuplication(self, pHead):
# write code here
if not pHead:return pHead
dummy = ListNode(-1)
dummy.next = pHead
p = dummy
while p.next:
# 原来错误是while dummy.next:
# dummy在while中都没有发生改变,起不到循环结束的作用
q = p.next
while (q and p.next.val == q.val):
q = q.next
# 如果不存在重复,长度==1
if p.next.next == q:
p = p.next
# 如果存在重复,长度>1
else: p.next = q
return dummy.next
剑指 Offer 24. 反转链表(easy)
class Solution:
def ReverseList(self, pHead):
# 反转链表需要三个listnode
pre = None
cur = pHead
while cur:
tail = cur.next
cur.next = pre
pre = cur
cur = tail
# return cur # cur目前指的是空
return pre
剑指 Offer 52. 两个链表的第一个公共节点(easy)
class Solution:
def FindFirstCommonNode(self, pHead1, pHead2):
if not pHead1:return pHead1
if not pHead2:return pHead2
len1 = self.getLength(pHead1)
len2 = self.getLength(pHead2)
diff = abs(len1-len2)
p1 = pHead1
p2 = pHead2
if len1>len2:
while diff>0:
diff -= 1
p1= p1.next
if len1<len2:
while diff>0:
diff -= 1
p2 = p2.next
# print(p1.val)
# print(p2.val)
while p1 != p2:
p1 = p1.next
p2 = p2.next
return p1
def getLength(self,head):
cnt = 0
cur = head
while cur:
cnt+=1
cur = cur.next
return cnt
剑指 Offer 25. 合并两个排序的链表(easy)
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
p1,p2 = None,None
rs = None
head = rs
while pHead1 and pHead2:
if pHead1.val < pHead2.val:
rs.next = pHead1
pHead1 = pHead1.next
else:
rs.next = pHead2
pHead2 = pHead2
rs = rs.next
while pHead1:
rs.next = pHead1
while pHead2:
rs.next = pHead2
return head
剑指 Offer 35. 复杂链表的复制(medium)
class Solution:
# 返回 RandomListNode
def Clone(self, pHead):
if not pHead:return None
p = pHead
# 完成节点复制
while p:
node = RandomListNode(p.label)
tail = p.next
p.next = node
node.next=tail
p = tail
# 复制随机指针
q = pHead
while q:
if q.random:
q.next.random = q.random.next
q = q.next
# 开始连接复制的节点
cloNode = pHead
pHead = pHead.next
while cloNode.next:
node = cloNode.next
cloNode.next = node.next
cloNode = node
return pHead
剑指 Offer 22. 链表中倒数第k个节点(easy)
class Solution:
def FindKthToTail(self, head, k):
# write code here
if not head:return head
p = head
cnt = 0
while p:
cnt += 1
p = p.next
if k>cnt:return
n = cnt-k+1
dummy = ListNode(-1)
dummy.next = head
q = dummy
cnt = 0
while q.next:
cnt += 1
if cnt==n:
return q.next.val
q = q.next
链表中环入口的位置
class Solution:
def EntryNodeOfLoop(self, pHead):
p1 = pHead #slow
p2 = pHead #fast
meet = pHead
flag = 0
while p2 and p2.next:
p1 = p1.next
p2 = p2.next.next
if p1 == p2:
flag = 1
meet = p1
break
if not flag:
return None
start = pHead
while meet and start:
if meet == start:
return start
meet = meet.next
start = start.next
return None
附上别人已经总结好的:小小搬运工——链表
本blog的单独链接
https://blog.csdn.net/weixin_31866177/article/details/99711772
https://blog.csdn.net/weixin_31866177/article/details/85923889