目录
203. 移除链表元素
题目链接:. - 力扣(LeetCode)
文章讲解:代码随想录
解题卡点:没分清链表结构,例如虚拟头节点没有用类实例化,使用node.next == val进行了判断
移除链表元素,需要知道它的上一个元素。该元素需要被移除时,让上一个节点的指针指向下一个节点。即上一个节点node.next.val==val时,node.next=node.next.next。若链表头节点需被移除,将节点指针向后移动一位,也就是第二个节点作为头节点。另外也可以使用虚拟头节点法,对全列表进行统一操作。
全篇是对current_code进行处理,为什么最后的dummy_head.next是正确答案?准确的说内存中只有1个链表,虚拟头节点在创捷后接上了原链表,是1个链表,current_node是副本链表,是(虚拟头节点+原链表)的弱引用,他们指向的是同1个对象实例。由于弱引用,改变current_node的指针会让(虚拟头节点+原链表)的指针同时受到影响。为何需要current_node,不对原链表处理呢?由于node=node.next,直接使用原链表会使原链表中只有最后一个元素。下面的print(current_node)也是这一情况的体现。故对(虚拟头节点+原链表)潜复制为current_node,current_node的指针变化反映在(虚拟头节点+原链表)上,元素变化不反映在其上。
以[7,2,7,3]移除7为例,每次循环以及最终结果如下。可以看到对于链表第一个元素,dummy_head可以移除,head移除不了,故最后返回dummy_head.next。图片结果与代码中输出结果相同。
总结:链表元素的移除就是改变指针next。next里实际储存的是下一个节点的类实例。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# 以[7,2,7,3]移除7为例
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
# print(head)
dummy_head = ListNode(None, head) # 创建虚拟头节点,下一个节点是原本的头节点
current_node = dummy_head # 遍历所有节点的指针
while current_node.next: # 当前节点仍有下一个元素时继续循环
if current_node.next.val == val: # 当前节点的下一个元素为目标值时
current_node.next = current_node.next.next # 当前节点下一个节点变为下下个节点,当前节点没有变化
else:
current_node = current_node.next # 只有当前节点的下一个元素不为目标值时,当前节点才往前进一位
# print(current_node)
# print(head)
# print(dummy_head)
return dummy_head.next # 返回真实的头节点
# ListNode{val: 7, next: ListNode{val: 2, next: ListNode{val: 7, next: ListNode{val: 3, next: None}}}}
# ListNode{val: 3, next: None}
# ListNode{val: 7, next: ListNode{val: 2, next: ListNode{val: 3, next: None}}}
# ListNode{val: None, next: ListNode{val: 2, next: ListNode{val: 3, next: None}}}
# 时间复杂度 O(n)
# 空间复杂度 O(1)
707.设计链表
题目链接:. - 力扣(LeetCode)
文章讲解:代码随想录
解题卡点:不清楚init里需要初始化什么内容
init里需要初始化一个空的虚拟头节点,方便后续的操作,同时还需要初始化一个size,用来保存链表中用多少个元素,方便后续的下标判断。除此之外不难。
此外,使用for i in range(index)进行当前节点的后移会比使用count计数判断简单易读。
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:
if index > self.size-1:
return -1
count = 0
current_node = self.dummy_head
while count <= index:
current_node = current_node.next
count += 1
return current_node.val
def addAtHead(self, val: int) -> None:
new_head = ListNode(val, self.dummy_head.next)
self.dummy_head.next = new_head
self.size += 1
def addAtTail(self, val: int) -> None:
new_tail = ListNode(val, None)
current_node = self.dummy_head
while current_node.next:
current_node = current_node.next
current_node.next = new_tail
self.size += 1
def addAtIndex(self, index: int, val: int) -> None:
if index > self.size:
return -2
elif index == self.size:
self.addAtTail(val)
else:
new_node = ListNode(val, None)
count = 0
current_node = self.dummy_head
while count < index:
current_node = current_node.next
count += 1
new_node.next = current_node.next
current_node.next = new_node
self.size += 1
def deleteAtIndex(self, index: int) -> None:
if index > self.size-1:
return -3
count = 0
current_node = self.dummy_head
while count < index:
current_node = current_node.next
count += 1
current_node.next = current_node.next.next
self.size -= 1
# 答案写的
class MyLinkedList:
def __init__(self):
self.dummy_head = ListNode()
self.size = 0
def get(self, index: int) -> int:
if index < 0 or index >= self.size:
return -1
current = self.dummy_head.next
for i in range(index):
current = current.next
return current.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:
current = self.dummy_head
while current.next:
current = current.next
current.next = ListNode(val)
self.size += 1
def addAtIndex(self, index: int, val: int) -> None:
if index < 0 or index > self.size:
return
current = self.dummy_head
for i in range(index):
current = current.next
current.next = ListNode(val, current.next)
self.size += 1
def deleteAtIndex(self, index: int) -> None:
if index < 0 or index >= self.size:
return
current = self.dummy_head
for i in range(index):
current = current.next
current.next = current.next.next
self.size -= 1
# 时间复杂度 涉及index相关操作为O(index),其余为O(1)
# 空间复杂度 O(n)
206.反转链表
题目链接:. - 力扣(LeetCode)
文章讲解:代码随想录
解题卡点:原地反转链表没思路
反转链表不需要重新定义一个新的链表,只需要修改原链表的next指针。(纠正:动画应该是先移动pre,让pre为cur,再移动cur,让cur为temp)
解题可分为四个步骤:①新链表pre,初始化时为新链表的最后一个None,原链表的当前节点cur,初始化时为原链表的第一个节点,pre在前,cur在后;②将pre赋值给cur的next,实现一次局部反转;③局部反转完成后,pre和cur同时往前移动一个位置,pre到cur的位置,cur到next的位置;④循环上述过程,直至cur为None,此时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]:
pre = None # 反转后链表的最末端
cur = head # 当前链表的第一个节点
while cur:
temp = cur.next # 保存当前节点的后续链表
cur.next = pre # 让当前链表的第一个节点指向None完成反转
pre = cur # 反转后链表的最末端和前一个节点
cur = temp # 当前节点在原链表上前进一位
return pre
# 时间复杂度 O(n)
# 空间复杂度 O(1)