203. 移除链表元素
https://leetcode.cn/problems/remove-linked-list-elements/
思路
删除单链表中的一个元素,即将该节点前一个的节点连接到该节点的后一个节点,由于单链表的限制,我们只能修改前一个结点的信息。这样推到后面会出现一个问题,如何处理头节点?通常而言我们有两种方法:
(1)对头节点的情况单独处理,先创建一个循环,不断删除头节点,直到头节点对应的元素不是 val。
(2)创建一个虚拟头节点 dummyHead,这个节点指向原本的头节点(dummyHead.next = head),这样我们的 head 就有了前驱 dummyHead,可以和后续删除操作进行统一。
解答
根据上述思路,给出对应的如下代码:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
dummyHead = ListNode(next=head) # 创建一个dummyHead指向原本头节点
# 链表遍历的模板,但我们从虚拟头节点开始遍历
curNode = dummyHead
while curNode.next:
if curNode.next.val == val: # 删除节点
curNode.next = curNode.next.next
else: # 继续向后遍历
curNode = curNode.next
return dummyHead.next
时间复杂度:遍历了整个链表,所以是 O ( n ) O(n) O(n)。
707. 设计链表
https://leetcode.cn/problems/design-linked-list/
解答
注意插入的时候防止断链。
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class MyLinkedList:
def __init__(self):
self.dummyHead = ListNode() # 虚拟头节点
self.size = 0
def get(self, index: int) -> int:
if index < 0 or index >= self.size:
return -1
curNode = self.dummyHead.next
for i in range(index):
curNode = curNode.next
return curNode.val
def addAtHead(self, val: int) -> None:
self.addAtIndex(0, val)
def addAtTail(self, val: int) -> None:
self.addAtIndex(self.size, val)
def addAtIndex(self, index: int, val: int) -> None:
# 索引无效
if index > self.size:
return
# 找到待插入位置的前驱
curNode = self.dummyHead
for i in range(index):
curNode = curNode.next
# 插入新节点
newNode = ListNode(val, curNode.next)
curNode.next = newNode # 防止断链
self.size += 1
def deleteAtIndex(self, index: int) -> None:
# 索引无效
if index < 0 or index >= self.size:
return
# 删除元素
curNode = self.dummyHead
for i in range(index):
curNode = curNode.next
curNode.next = curNode.next.next
self.size -= 1
206. 反转链表
https://leetcode.cn/problems/reverse-linked-list/
解答
迭代法(双指针法)
简而言之就是不断改变链表箭头的朝向,为方便表示,我们用一个 curNode 表示当前节点,preNode 节点来记录节点原本的前驱(变换后会变成后继)。现在我们要做的就是把 preNode -> curNode 变成 curNode -> preNode,链表就变成了这样:None <- ... <- preNode <- curNode | curNode.next -> ...。我们发现了一个新问题:链表断开了。为了防止断链,我们可以用一个 tmp 节点来临时存储原本的 curNode.next,接下来只需要将 preNode 和 curNode 在原链表的次序上移动一格,即赋值 preNode = curNode,curNode = tmp。
(1)

(2)

(3)

class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
preNode = None
curNode = head
while curNode:
tmp = curNode.next
curNode.next = preNode
preNode = curNode
curNode = tmp
return preNode
时间复杂度:
O
(
n
)
O(n)
O(n);
空间复杂度:
O
(
1
)
O(1)
O(1)。
递归法
假设链表的其余部分已经被反转,现在应该如何反转它前面的部分?
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
# 递归终止条件:链表为空或只有一个节点
if not head or not head.next:
return head
# 递归反转后续链表
newHead = self.reverseList(head.next)
# 将当前节点与后续节点反转
head.next.next = head
head.next = None
return newHead
其他解法
我们可以用数组(或者栈)来帮忙,遍历链表获取元素存在一个数组中,然后将这个数组中的元素倒序遍历(栈可以直接弹出),存入新链表中。
# 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]:
curNode = head
newHead = None
nums = []
while curNode:
nums.append(curNode.val)
curNode = curNode.next
for num in nums:
newHead = ListNode(num, newHead) #
return newHead
时间复杂度:
O
(
n
)
O(n)
O(n);
空间复杂度:
O
(
n
)
O(n)
O(n)。

3080

被折叠的 条评论
为什么被折叠?



