GIS与Climate
V1
2022/09/23阅读:23主题:默认主题
算法60天:Day 3-链表初识

本系列是代码随想录算法训练营的学习笔记之day3,主要记录一下刷题的过程,以及核心知识点和一些值的记录的问题。
代码随想录的资源都是免费的,具体可以看参考链接【1】。
今日知识点
链表理论基础:
-
链表是一种串联、线性结构; -
每个节点有两部分组成,值域和指针域,指针域存放指向下一个节点的指针; -
最后一个节点的指针域指向null(注意不同语言的写法,比如python是None);
今日题目
-
移除链表元素(203)
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
链接:https://leetcode.cn/problems/remove-linked-list-elements/
解题思路
-
需要删除所有满足条件的节点,所以在循环中要遍历到所有的节点; -
对于链表的增删,因为要考虑到是否是首节点,所以增加虚拟节点,具体的可以看Carl师兄的讲解; -
删除当前节点就相当于跳过当前节点,只需要修改上一个节点的指针域即可;
# 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]:
vir_ln = ListNode(next=head)
cur = vir_ln
while cur.next!=None:
if cur.next.val==val:
cur.next = cur.next.next
else:
cur = cur.next
return vir_ln.next
-
要注意要返回的是头结点!
-
设计链表(707)
设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。在链表类中实现这些功能:
get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。 addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。 addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。 addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。 deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
链接:https://leetcode.cn/problems/design-linked-list/
解题思路
-
这道题个人认为比较难,就是实现链表的各种功能,按照题目要求一个个写就行,但是需要考虑清楚题目中说的特殊情况,比如索引无效的时候返回-1,插入节点的时候如果index大于链表长度就不会插入节点(返回空); -
在头部插入和在尾部插入节点是在特定index插入节点的特殊情况; -
在插入节点之后要更新链表的节点数量,否则后续就无法操作;
class Node:
def __init__(self,val):
self.val = val
self.next = None
class MyLinkedList:
def __init__(self):
self._head = Node(0)
self._count = 0
def get(self, index: int) -> int:
if 0<= index < self._count:
node = self._head
for _ in range(index+1):
node = node.next
return node.val
else:
return -1
def addAtHead(self, val: int) -> None:
self.addAtIndex(0,val)
def addAtTail(self, val: int) -> None:
self.addAtIndex(self._count,val)
def addAtIndex(self, index: int, val: int) -> None:
if index<0:
index =0
elif index>self._count:
return
self._count += 1
add_node = Node(val)
pre_node, cur_node = None, self._head
for _ in range(index+1):
pre_node, cur_node = cur_node,cur_node.next
else:
pre_node.next, add_node.next = add_node, cur_node
def deleteAtIndex(self, index: int) -> None:
if 0 <= index < self._count:
self._count -= 1
pre_node,cur_node = None, self._head
for _ in range(index+1):
pre_node,cur_node = cur_node,cur_node.next
else:
pre_node.next,cur_node.next = cur_node.next, None
# 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)
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
链接:https://leetcode.cn/problems/reverse-linked-list/
解题思路
-
这道题理解起来比较简单,就是修改下链表中指针的方向; -
操作的时候注意使用中间变量,否则不保存当前节点的原始指针的话,无法往后遍历链表; -
另外就是注意while的循环条件要用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 != None:
temp = cur.next
cur.next = pre
pre = cur
cur = temp
return pre
补充知识点
-
链表的几种类型
上面说的是最简单的链表,实际上链表有几种:
-
单链表

-
双链表:一个节点有两个指针域,分别指向前一个和后一个节点;

-
循环链表:单链表的特殊情况,首尾相连。

-
链表的存储方式
数组在内存中是连续存储的,但是链表不是,因为链表有指针,可以顺利找到下一个元素。
-
链表与数组的性能分析

今日思考
-
怎么形象理解链表中的插入和删除?
想象一个N个同学手拉手的样子,然后中间插入新同学和踢出旧同学。。。
参考
【1】代码随想录:https://programmercarl.com/
作者介绍
GIS与Climate
V1
公众号:GIS与Climate,欢迎关注