一、链表基础理论
二、203. 移除链表元素
题目链接:203. 移除链表元素 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——203. 移除链表元素
视频讲解:手把手带你学会操作链表 | LeetCode:203.移除链表元素_哔哩哔哩_bilibili
法一、原链表删除元素
需要判断是否为头节点,如果不是直接指针指向下一个节点,如果是将头节点head→next
定义cur = head而不是cur = head.next,因为需要上一个元素的指针。
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
"""
原链表删除法
"""
cur = head
# 判断是否为头节点,如果是头节点且头节点值为val,则删除头节点
while cur and cur.val == val:
head = cur.next
cur = cur.next
# 当前指针不是头节点,开始遍历链表
while cur and cur.next:
# 当前节点的下一个节点值等于val,则删除该节点
if cur.next.val ==val:
cur.next = cur.next.next
else:
# 如果不等于val,继续遍历
cur = cur.next
return head
法二、虚拟头节点法
需要注意最后返回dummy_head.next而不是dummy_head!
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
"""
虚拟节点法
"""
# 创建虚拟头节点
dummy_head = ListNode(next = head)
cur = dummy_head
# 开始从虚拟头节点遍历
while cur.next:
# 如果虚拟头节点下一个值等于目标值,则删除该节点
if cur.next.val == val:
cur.next = cur.next.next
# 否则继续遍历
else:
cur = cur.next
return dummy_head.next
三、707.设计链表
题目链接:707. 设计链表 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——707.设计链表
视频讲解:帮你把链表操作学个通透!LeetCode:707.设计链表_哔哩哔哩_bilibili
主要考察链表基本操作:获取第几个节点的值;头部插入节点;尾部插入节点;第n个节点前插入节点;删除第n个节点。
错误记录
def addAtIndex(self, index: int, val: int) -> None:
# 判断索引是否合法
if index < 0 or index > self.size - 1:
return
cur = self.dummy_head
for i in range(index):
cur = cur.next
cur.next = ListNode(val, cur.next)
self.size += 1
判断是否合法出错,正确应该是,其中index可以含等,因此不用-1.
def addAtIndex(self, index: int, val: int) -> None:
# 判断索引是否合法
if index < 0 or index > self.size:
return
cur = self.dummy_head
for i in range(index):
cur = cur.next
cur.next = ListNode(val, cur.next)
self.size += 1
正确代码
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class MyLinkedList:
def __init__(self):
self.dummy_head = ListNode() # 定义一个虚拟头节点,方便增删改
self.size = 0
def get(self, index: int) -> int: # 获取第n个节点的值
# 如果下标无效,则返回-1,可以等于size - 1,此时为链表中最后一个节点
if index < 0 or index > self.size - 1:
return -1
# 获取当前节点数值,让cur指向原链表第一个,即dummy_head.next
cur = self.dummy_head.next
# # 遍历index
# while index:
# cur = cur.next
# index -= 1
# 遍历写法2
for i in range(index):
cur = cur.next
return cur.val
def addAtHead(self, val: int) -> None: # 在头部插入节点
# 虚拟节点指针指向下一个节点
self.dummy_head.next = ListNode(val, self.dummy_head.next)
self.size += 1
def addAtTail(self, val: int) -> None: # 在尾部插入节点
cur = self.dummy_head
# 找尾部节点,cur.next为空节点,即cur.next != None
while cur.next:
cur = cur.next
# 插入尾部节点
cur.next = ListNode(val)
self.size += 1
def addAtIndex(self, index: int, val: int) -> None: # 第n个节点前插入节点
# 判断索引是否合法,索引可以等于列表长度,此时直接加在链表末尾
if index < 0 or index > self.size:
return
cur = self.dummy_head
# 查找第n个节点写法1
for i in range(index):
cur = cur.next
# # 查找第n个节点写法2
# while index:
# cur = cur.next
# index -= 1
cur.next = ListNode(val, cur.next)
self.size += 1
def deleteAtIndex(self, index: int) -> None: # 删除第n个节点
# 判断索引是否合法,可以取最后一个节点
if index < 0 or index > self.size:
return
cur = self.dummy_head
# 找到当前节点
for i in range(index):
cur = cur.next
cur.next = cur.next.next
self.size -= 1
# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)
注意
在第n个节点前插入节点和删除第n个节点的操作中,cur为n-1个节点,cur.next才为第n个节点,此时才好操作,否则会出现加错位置的情况。
四、206.反转链表
题目链接:206. 反转链表 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)
视频讲解:帮你拿下反转链表 | LeetCode:206.反转链表 | 双指针法 | 递归法_哔哩哔哩_bilibili
面试高频题目!!!
双指针解法
思想:定义cur和pre两个指针,cur指向pre,cur和pre向前移动,cur再指向pre,不断重复,直到结束。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
"""双指针解法"""
cur = head # 初始化cur指针,指向head
pre = None # 初始化pre指针,为了使cur可以直接指向pre,所以初始化为None
# 终止条件:cur指向None即停止
while cur:
temp = cur.next # 趁链表没断先保存一个cur的临时值
cur.next = pre
# cur和pre整体向后移动,注意先移动pre后移动cur,如果先移动cur则pre不能走到之前cur的位置
pre = cur
cur = temp
return pre
递归解法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
"""递归法"""
# 先定义一个reverse函数,输入的值对应双指针法的两个指针
def reverse(self, cur: ListNode, pre: ListNode) -> ListNode:
# 终止条件:当cur为空时
if cur == None:
return pre
temp = cur.next
cur.next = pre
# 移动cur和pre指针
return self.reverse(temp, cur)
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
# 输入为双指针法cur和pre的输入
return self.reverse(head, None)
先重点掌握双指针法,再去对照学习递归法。