代码随想录算法训练营第3天|链表|203.移除链表元素707.设计链表206.反转链表
一、链表理论基础
- 概念:
- 链表是一种数据结构,它由一系列节点组成,每个节点包含两个部分:数据和指向下一个节点的指针。链表的节点可以按照顺序连接在一起,形成一个链状的表。
- 链表的原理是利用指针来连接各个节点,从而实现数据的存储和访问。指针可以指向链表中的任意节点,从而方便地实现数据的插入、删除和查找等操作。
- 在链表中,每个节点都有一个指向下一个节点的指针,最后一个节点的指针指向空,表示链表的结束。由于链表是通过指针连接的,因此它可以在运行时动态地添加和删除节点,这是链表相对于数组的一个优势。
- 链表有多种类型,包括单向链表、双向链表和循环链表等。
- 单向链表只包含一个指向下一个节点的指针;
- 双向链表包含两个指针,分别指向前一个节点和后一个节点;
- 循环链表则是指针可以循环指向,最后一个节点指向第一个节点。
- 链表的定义
# 定义链表节点
class ListNode:
def __init__(self, val=None):
self.val = val # 数据域,用于存储节点的值
self.next = None # 指针域,用于存储指向下一个节点的引用
二、203.移除链表元素
文档链接:代码随想录
题目链接:203.移除链表元素
视频讲解:视频讲解
题目描述:
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == val
的节点,并返回 新的头节点 。
示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
示例 2:
输入:head = [], val = 1
输出:[]
示例 3:
输入:head = [7,7,7,7], val = 7
输出:[]
提示:
- 列表中的节点数目在范围
[0, 104]
内 1 <= Node.val <= 50
0 <= val <= 50
代码:
- 虚拟头节点法
思路:目标值的前一个节点指针直接指向目标值的下一个节点,需要判断目标值是是头节点、尾节点、中间节点。为了避免在删除节点时处理边界情况,通常会创建一个虚拟头节点(dummy node)作为结果链表的头部。这样,无论原始链表是否为空,都可以通过虚拟头节点来方便地访问第一个节点。
# 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) # 创建一个虚拟节点,作为新的链表头部
current = dummy_head # 定义一个指针current,初始指向虚拟节点
# 遍历整个链表
while current.next:
if current.next.val == val: # 如果当前节点的值等于要删除的值val
current.next = current.next.next # 删除该节点,即跳过该节点
else: # 如果当前节点的值不等于要删除的值val
current = current.next # 将current指向下一个节点
return dummy_head.next # 返回虚拟节点所指向的新的头节点
三、707.设计链表
文档链接:代码随想录
题目链接:707.设计链表
视频讲解:视频讲解
题目描述:
你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性:val
和 next
。val
是当前节点的值,next
是指向下一个节点的指针/引用。
如果是双向链表,则还需要属性 prev
以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。
实现 MyLinkedList
类:
MyLinkedList()
初始化MyLinkedList
对象。int get(int index)
获取链表中下标为index
的节点的值。如果下标无效,则返回-1
。void addAtHead(int val)
将一个值为val
的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。void addAtTail(int val)
将一个值为val
的节点追加到链表中作为链表的最后一个元素。void addAtIndex(int index, int val)
将一个值为val
的节点插入到链表中下标为index
的节点之前。如果index
等于链表的长度,那么该节点会被追加到链表的末尾。如果index
比长度更大,该节点将 不会插入 到链表中。void deleteAtIndex(int index)
如果下标有效,则删除链表中下标为index
的节点。
示例:
输入
["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"]
[[], [1], [3], [1, 2], [1], [1], [1]]
输出
[null, null, null, null, 2, null, 3]
解释
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.addAtHead(1);
myLinkedList.addAtTail(3);
myLinkedList.addAtIndex(1, 2); // 链表变为 1->2->3
myLinkedList.get(1); // 返回 2
myLinkedList.deleteAtIndex(1); // 现在,链表变为 1->3
myLinkedList.get(1); // 返回 3
提示:
0 <= index, val <= 1000
- 请不要使用内置的 LinkedList 库。
- 调用
get
、addAtHead
、addAtTail
、addAtIndex
和deleteAtIndex
的次数不超过2000
。
四、206.反转链表
文档链接:代码随想录
题目链接:206.反转链表
视频讲解:视频讲解
题目描述:
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2]
输出:[2,1]
示例 3:
输入:head = []
输出:[]
提示:
- 链表中节点的数目范围是
[0, 5000]
-5000 <= Node.val <= 5000
**进阶:**链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?