203.移除链表元素
题目链接/文章讲解/视频讲解::https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html
- 考点
- 虚拟头节点
- 我的思路
- 头节点和其它节点分开讨论
- 视频讲解关键点总结
- 未看视频
- 在头节点前创建一个虚拟头节点指向头节点
- 之后创建循环所用链表变量prev,并将虚拟头节点赋值给prev
- 开始循环,循环条件为prev.next不为None
- 进入循环,如果prev.next.val == val,则让prev.next = prev.next.next,否则,让prev变成prev.next
- 最后输出虚拟头节点所指向的头节点即为答案
- 我的思路的问题
- 头节点和其它节点分开讨论会增加算法的时间复杂度
- 代码书写问题
- 无
- 可执行代码
class Solution(object):
def removeElements(self, head, val):
"""
:type head: ListNode
:type val: int
:rtype: ListNode
"""
dummy_node = ListNode(next=head)
prev = dummy_node
while prev.next is not None:
if prev.next.val == val:
prev.next = prev.next.next
else:
prev = prev.next
return dummy_node.next
707.设计链表
题目链接/文章讲解/视频讲解:https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html
- 考点
- 链表的虚拟头节点
- 我的思路
- 链表类初始化头节点和链表长度
- 之后如果需要用到虚拟头节点,在每个实现方法里创建虚拟头节点
- 视频讲解关键点总结
- 未看视频
- 关键点在于类初始化里直接初始化虚拟头节点和链表长度,不初始化头节点
- 我的思路的问题
- 在删除节点的时候,如果删除的是头节点,则我用新创建的虚拟头节点就无法成功删除,必须要按照类初始化里初始化虚拟头节点的方式才行
- 代码书写问题
- 无
- 可执行代码
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
# leetcode submit region begin(Prohibit modification and deletion)
class MyLinkedList(object):
def __init__(self):
self.dummy_head = ListNode()
self.length = 0
def get(self, index):
"""
:type index: int
:rtype: int
"""
n = 0
prev = self.dummy_head
while prev.next is not None:
if n == index:
return prev.next.val
else:
n += 1
prev = prev.next
return -1
def addAtHead(self, val):
"""
:type val: int
:rtype: None
"""
self.dummy_head.next = ListNode(val=val, next=self.dummy_head.next)
self.length += 1
def addAtTail(self, val):
"""
:type val: int
:rtype: None
"""
new_last = ListNode(val=val)
prev = self.dummy_head
while prev.next is not None:
prev = prev.next
prev.next = new_last
self.length += 1
def addAtIndex(self, index, val):
"""
:type index: int
:type val: int
:rtype: None
"""
if index > self.length:
return
n = 0
new_node = ListNode(val=val)
prev = self.dummy_head
while prev.next is not None:
if n == index:
new_node.next = prev.next
prev.next = new_node
self.length += 1
return new_node
else:
n += 1
prev = prev.next
if n == index:
prev.next = new_node
self.length += 1
return new_node
return -1
def deleteAtIndex(self, index):
"""
:type index: int
:rtype: None
"""
n = 0
prev = self.dummy_head
while prev.next is not None:
if n == index:
prev.next = prev.next.next
self.length -= 1
return 0
else:
n += 1
prev = prev.next
return -1
*206 反转链表
题目链接/文章讲解/视频讲解:https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html
- 考点
- 法一:双指针
- 法二:基于双指针的解法改为对应的递归函数
- 我的思路
- 无思路
- 视频讲解关键点总结
- 法一:双指针
- prev指针从NULL开始,cur从head开始
- 创建一个临时变量a保存cur的next
- 让cur的next等于prev
- 让prev等于cur
- 让cur等于a
- 法二:递归(结合法一看,其实就是对双指针法的递归实现)
- 递归函数的功能:输入两个指针prev和cur,返回反转后链表的头指针;为此,函数体内进行cur节点重定向的操作
- 递归结束条件,cur移动到最后一个节点
- 法一:双指针
- 我的思路的问题
- 没想到用一个初始化为NULL的prev
- 代码书写问题
- 无
- 可执行代码
- 法一:双指针法
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
cur = head
pre = None
while cur:
temp = cur.next # 保存一下 cur的下一个节点,因为接下来要改变cur->next
cur.next = pre #反转
#更新pre、cur指针
pre = cur
cur = temp
return pre
- 法二:递归法
class Solution(object):
def rev(self, prev, cur):
if cur is None:
return prev
temp = cur.next
cur.next = prev
return self.rev(cur, temp)
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
return self.rev(None, head)
138. 随机链表的复制
- 题干
- 思路
- 因为有random指针的存在,所以单次的遍历无法一次完成链表的复制
- 因此分两次遍历完成复制
- 第一次遍历复制val属性和next指针
- 第二次遍历复制random指针
- 复制random指针有基础方法和优化后的方法
- 基础方法
- 定义两个指针分别指向原链表head和复制链表head
- 之后同步向后移动两个指针,直到原链表指针和原链表的当前random指针相同时,则复制链表指针对应的node就是复制链表的当年random指针
- 由于该方法需要内外两层遍历,因此时间复杂度为O(n^2)
- 优化方法
- 在第一次遍历时,利用字典(哈希表)储存原链表node(key)和复制链表node(value)的对应关系
- 在第二次遍历时,每遍历一个原链表节点,其random指针可以直接从字典中取到对应的复制链表node,该node即为复制链表的random指针
- 由于该方法只需要外层遍历,内层直接利用字典实现了O(1)的查找效率,所以整体方法的时间复杂度为O(n)
- 代码
# 基础方法
class Solution:
def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
if not head:
return None
new_head = Node(head.val)
cur = head
cur_new = new_head
while cur:
next_ = Node(cur.next.val) if cur.next else None
cur_new.next = next_
cur_new = cur_new.next
cur = cur.next
cur = head
cur_new = new_head
while cur:
if cur.random:
random_node = cur.random
nod = head
nod_new = new_head
while nod != random_node:
nod = nod.next
nod_new = nod_new.next
random_node = nod_new
else:
random_node = None
cur_new.random = random_node
cur = cur.next
cur_new = cur_new.next
return new_head
#优化方法
class Solution:
def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
if not head:
return None
new_head = Node(head.val)
cur = head
cur_new = new_head
dic = dict()
while cur:
next_ = Node(cur.next.val) if cur.next else None
cur_new.next = next_
dic[cur] = cur_new
cur_new = cur_new.next
cur = cur.next
cur = head
while cur:
dic[cur].random = dic[cur.random] if cur.random else None
cur = cur.next
return new_head