1. 链表理论基础
什么是链表?
- 链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。
- 链表的入口节点称为链表的头结点也就是head。
1.1.链表的定义
class ListNode:
def __init__(self, val, next=None):
self.val = val
self.next = next
1.2. 链表的类型
- 单链表
- 单链表中的指针域只能指向节点的下一个节点
- 单链表中的指针域只能指向节点的下一个节点
- 双链表
- 每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点
- 既可以向前查询也可以向后查询
- 循环链表
- 链表首尾相连
- 链表首尾相连
1.3.链表的存储方式
- 数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。
- 链表是通过指针域的指针链接在内存中各个节点。
- 所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。
1.4.链表的操作
- 删除节点
- 修改链表指针指向即可,删除后的节点python中会自动释放内存
- 删除D节点,如图所示:
- 只要将C节点的next指针 指向E节点就可以了
- 添加节点
- 可以看出链表的增添和删除都是O(1)操作,也不会影响到其他节点
- 但是要注意,要是删除第五个节点,需要从头节点查找到第四个节点通过next指针进行删除操作,查找的时间复杂度是O(n)
1.5链表与数组对比
- 数组在定义的时候,长度就是固定的,如果想改动数组的长度,就需要重新定义一个新的数组。
- 链表的长度可以是不固定的,并且可以动态增删, 适合数据量不固定,频繁增删,较少查询的场景
2.203.移除链表元素
2.1 题目及讲解
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
题目链接:https://leetcode.cn/problems/remove-linked-list-elements/description/
讲解视频:https://www.bilibili.com/video/BV18B4y1s7R9/?spm_id_from=333.788&vd_source=d49b1b867faa78fdf891abde70b7422f
文字讲解:https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html
2.2 代码实现
# 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]:
dummy_head = ListNode(next=head) # 定义虚拟节点
cur = dummy_head
while cur.next: # 遍历除虚拟节点之后的所有节点,尾节点的next为null,循环结束
if cur.next.val == val:
cur.next = cur.next.next #下一节点的值如果等于目标值,那么循环时跳过下个节点,直接到下下个节点
else:
cur = cur.next
return dummy_head.next
3.707.设计链表
3.1 题目及讲解
你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。
如果是双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始
题目链接:https://leetcode.cn/problems/design-linked-list/description/
视频讲解:https://www.bilibili.com/video/BV1FU4y1X7WD/?spm_id_from=333.788&vd_source=d49b1b867faa78fdf891abde70b7422f
文字讲解:https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html
3.2 代码实现
class ListNode:
def __init__(self,val=0, next=None):
self.next = next
self.val = val
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
cur = self.dummy_head.next
count = 0
while count < index: # 循环遍历到cur等于index的时候输出val
count += 1
cur = cur.next
return cur.val
def addAtHead(self, val: int) -> None:
# self.dummy_head.next = ListNode(val, self.dummy_head.next)
node = ListNode(val,self.dummy_head.next)
self.dummy_head.next = node
self.size += 1
def addAtTail(self, val: int) -> None:
node = ListNode(val)
cur = self.dummy_head
while cur.next != None: # 循环结束时,cur指向最后一个节点
cur = cur.next
cur.next = node
self.size += 1
def addAtIndex(self, index: int, val: int) -> None:
node = ListNode(val)
if index > self.size or index <0:
return
cur = self.dummy_head # 要在某一个节点之前添加节点,那么必须要知道这个节点之前的节点
for i in range(index): # 循环结束时cur指向下标为index的节点之前的一个节点
cur = cur.next
node.next = cur.next
cur.next = node
self.size += 1
def deleteAtIndex(self, index: int) -> None:
if index >= self.size or index <0:
return
cur = self.dummy_head
for i in range(index):
cur = cur.next
cur.next = cur.next.next # cur指向的节点即cur.next,重新指向cur.next.next
self.size -= 1
4.206. 反转链表
4.1题目及讲解
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
题目链接:https://leetcode.cn/problems/reverse-linked-list/description/
视频讲解:https://www.bilibili.com/video/BV1nB4y1i7eL/?spm_id_from=333.788&vd_source=d49b1b867faa78fdf891abde70b7422f
文字讲解:https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html
4.2代码实现
方法一:双指针
# 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:
tmp = cur.next # 临时浮标
cur.next= pre #翻转
pre = cur #pre后移
cur = tmp #cur后移
return 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]:
return self.reverse(head, None)
def reverse(self, cur: ListNode, pre: ListNode) -> ListNode:
if cur ==None:
return pre
tmp = cur.next
cur.next = pre # 翻转
return self.reverse(tmp,cur)
总结:
对链表的基础理论熟悉了,能够理解讲解的方法,但是代码实现还是不熟练,没办法独立写出来