目录
注意:
和b站up主大雪菜一起刷题https://www.bilibili.com/video/BV1jt411J7tC
19. 删除链表的倒数第N个节点
思路:
- 首先,链表题一般可以直接画图得到思路
- 要删除倒数第N个节点的话,我们实际需要找到的是倒数第N+1个节点的位置,然后令其的next=next.next
- 由于可能头结点被删除,则可以添加一个虚节点指向头结点
- 题目要求只扫描一次完成,设置双指针,第一个first指针从虚节点起往后走N步,然后用last指针从虚节点起和first同步往后移,当first指向了最后一个节点,则last所指的指针即为倒数N+1各节点
- 注意返回的时候不要返回head,因为可能头结点已经被删掉了,而应该返回dummy.next
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
dummy = ListNode()
dummy.next = head
first,last = dummy,dummy
k = 0
# first先走
while first:
first = first.next
k += 1
if k == n:
break
# last开始
while first.next:
first = first.next
last = last.next
last.next = last.next.next
return dummy.next
237. 删除链表中的节点
思路:
- 这道题是需要你完成一个函数,这个函数只给定需要删除的节点node
- 这个时候可以利用下一个节点的值将当前值覆盖,达到删除的目的,因为需要删除的节点绝对不是末尾的节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteNode(self, 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
83. 删除排序链表中的重复元素
思路:
- 重复元素要保留第一个即可,那么只需判断当前节点的下一个节点值与当前节点的值是否相等,相等的话则将下一个节点进行删除,否则当前节点后移
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
cur = head
while cur:
# 重复元素
if cur.next and cur.next.val == cur.val:
cur.next = cur.next.next
else:# 不同的元素
cur = cur.next
return head
61. 旋转链表
思路:
- 旋转末尾k个位置的数字到头结点之前,这时候要考虑k的大小问题,k可能超过链表长度,所以需要取模
- 可以利用前面的双指针的方法找到倒数第k+1个位置,和最后一个位置,然后进行处理即可
- 注意k的大小,和链表为空的情况
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def rotateRight(self, head: ListNode, k: int) -> ListNode:
n = 0
first = head
while first:
n += 1
first = first.next
if n == 0 or not head:
return head
k = k%n
first,second = head,head
while k:
k -= 1
first = first.next
while first.next:
first = first.next
second = second.next
first.next = head
head = second.next
second.next = None
return head
24. 两两交换链表中的节点
思路:
- 画图分析
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
dummy = ListNode(-1)
dummy.next = head
p = dummy
while p.next and p.next.next:
a,b = p.next,p.next.next
p.next = b
a.next = b.next
b.next = a
p = a
return dummy.next
206. 反转链表
思路:
- 思路,关键让头尾中间的节点互相的指向对调
- 最后让头指针的next改为None即可
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head:
return []
a,b = head, head.next
while b:
# 防止断链
c = b.next
b.next = a
a, b = b, c
head.next = None
return a
92. 反转链表 II
思路:
- 和上一题思路类似,这题主要在上一题的基础上加了限制范围
- 那就要找到四个位置,a:m-1位置,b:m位置,c:n位置,d:n+1位置
- 对b~c里相邻节点进行指针方向的转换,和上一题思路一样
- a指向c,b指向d即可完成
- 由于可能会对头结点的位置进行改变,建立一个虚拟节点dummy
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
if m==n:
return head
dummy = ListNode(-1)
dummy.next = head
a,c = dummy,dummy
while m-1:
m -= 1
a = a.next
# print("a:{}".format(a.val))
while n:
n -= 1
c = c.next
# print("c:{}".format(c.val))
b, d = a.next, c.next
p, q = b, b.next
while q!=c:
o = q.next
q.next = p
p, q = q, o
q.next = p
b.next = d
a.next = c
return dummy.next
160. 相交链表
思路:
- 当相遇的时候,走过的路程是等长的,把握好这一核心点
- 如果是两条没有相交的链表,最后都会等于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:
Pa, Pb = headA, headB
while Pa!=Pb:
if not Pa:
Pa = headB
else:
Pa = Pa.next
if not Pb:
Pb = headA
else:
Pb = Pb.next
return Pb
142. 环形链表 II
思路:
- 快慢指针的一个妙用,fast每次走两步,slow每次走一步
- 第一次相遇之后,slow从起点再次走,和fast同步往后移一步,既可以找到环的入口
# 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:
fast, slow = head, head
while fast:
fast = fast.next
slow = slow.next
if fast:
fast = fast.next
else:
break
# 第一次相遇
if fast == slow:
slow = head
while fast!=slow:
fast = fast.next
slow = slow.next
else:
return fast
return None
148. 排序链表
思路:
- 这道题由于限制了时间复杂度和空间复杂度,这道题适合使用归并排序解决
- 归并排序的关键点是写好merge函数,分而治之的思想,当我们分到只有一个节点的两个链表进行排序就很简单了。再依次往上就可以。
- 【不过题目要求的空间复杂度为常数级别,使用了递归就肯定不是,得改成循环,我暂时只会写递归的版本,先给自己埋个坑,以后看懂闫神的代码再改吧】
- 快慢指针不仅可以用来在链表中找环,也可以用来在链表里找到终点。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def sortList(self, head: ListNode) -> ListNode:
# 寻找中间节点
if not head or not head.next:
return head
fast, slow, pre= head, head, head
while fast and fast.next:
pre = slow
fast = fast.next.next
slow = slow.next
# 从中间节点断开
pre.next = None
return self.merge(self.sortList(head), self.sortList(slow))
def merge(self, h1, h2):
# 建立虚拟头节点
dummy = ListNode(-1)
cur = dummy
while h1 and h2:
if h1.val < h2.val:
cur.next = h1
h1 = h1.next
else:
cur.next = h2
h2 = h2.next
cur = cur.next
if h1:
cur.next = h1
if h2:
cur.next = h2
return dummy.next