链表基础
链表和数组在查询和增删的时候的时间复杂度如下(图源:代码随想录):
关于删除:C|C++需要手动free内存,但是Java和Python等会自动回收内存。
Python定义链表如下:
class ListNode:
def __init__(self, val, next=None):
self.val = val
self.next = next
203.移除链表元素
思路
原链表删除:需要单独判断需要删除的是不是head,如果是的话需要把当前的head往后移动一个。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def removeElements(self, head, val):
"""
:type head: ListNode
:type val: int
:rtype: ListNode
"""
# 原链表删除
current = head
while current.next:
if current.val == val:
head = current.next
current = head
elif current.next.val == val:
current.next = current.next.next
else:
current = current.next
return current
虚拟头节点(dummy_head):为了解决如果需要删除头节点的情况,不用再写一个if单独判断。方法是定义一个在原来head之前的节点dummy_head,使得dummy_head.next = head,这样以dummy_head作为起点删除任何的节点都是从第二个开始,可以统一成一个while里。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def removeElements(self, head, val):
"""
:type head: ListNode
:type val: int
:rtype: ListNode
"""
# 虚拟节点
dummy_head = ListNode(next = head)
current = dummy_head # 从虚拟节点作为起始点开始,所有的删除都是在第二个节点开始,可以统一到一个while里面
while current.next: # 用当前节点的下一个是否是None来判断是否是最后一个节点
if current.next.val == val:
current.next = current.next.next
else:
current = current.next
return dummy_head.next # 注意!!返回的是dummy的后一个
707.设计链表(很重要!!涉及链表的全部操作)
思路
单链表+dummy_head
# 定义节点类,需要传入data和next指针
class LinkNode:
def __init__(self, val = 0, next = None):
self.val = val
self.next = next
class MyLinkedList(object):
def __init__(self):
self.dummy_head = LinkNode() # 定义一个虚拟节点(实际上是链表的第一个节点)
self.size = 0 # 用于index合法性判断
# 获取当前节点的值
def get(self, index):
"""
:type index: int
:rtype: int
"""
# 合法性判断
if index < 0 or index >= self.size:
return -1
current = self.dummy_head.next # 当前从头节点开始,for range之后就是停留在目标节点
for _ in range(index):
current = current.next
return current.val
# 添加头节点
def addAtHead(self, val):
"""
:type val: int
:rtype: None
"""
self.dummy_head.next = LinkNode(val, self.dummy_head.next) # 也就是把dummy_head的next指向新的节点,在此之前需要先把原头节点的指针传给新节点的next,不然会丢失!!!!
self.size += 1
def addAtTail(self, val):
"""
:type val: int
:rtype: None
"""
current = self.dummy_head # 从dummy开始for range之后停留在index节点的前一个
while current.next:
current = current.next
current.next = LinkNode(val, None) # None也可以不加
self.size += 1
def addAtIndex(self, index, val):
"""
:type index: int
:type val: int
:rtype: None
"""
# 合法性检验
if index < 0 or index > self.size:
return
current = self.dummy_head
for _ in range(index):
current = current.next
current.next = LinkNode(val, current.next) # 和插入头节点类似
self.size += 1
def deleteAtIndex(self, index):
"""
:type index: int
:rtype: None
"""
if index < 0 or index >= self.size:
return
current = self.dummy_head
for _ in range(index):
current = current.next
current.next = current.next.next # 相当于跨过了current.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)
206.反转链表
思路
图:代码随想录
双指针+循环
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
# 双指针法
pre = None # pre初始化为None,是新链表的末尾
cur = head # cur是当前的节点,初始化为head
while cur: # 当cur没有走到None的时候
temp = cur.next # 首先保存cur的下一个节点,为了下一步移动cur
cur.next = pre # 然后把当前cur的指向反转到pre
# 更新pre和cur,注意顺序
pre = cur
cur = temp
return pre
递归
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
return self.reserve(head, None)
# 递归法
def reserve(self, cur, pre):
if cur == None: # 递归退出条件:当前节点是None
return pre
temp = cur.next # 先保存当前节点的下一个
cur.next = pre # 反转指向pre
return self.reserve(temp, cur) # 更新
第三天结束🎉