代码随想录|链表 203. 移除链表元素,707. 设计链表,206.反转链表
python
一、链表理论基础
通过指针串联在一起的线性结构,由数据域和指针域组成,最后一个结点的指针域指向null,头节点head
分类:单链表、双链表、循环链表(约瑟夫环问题)
内存非连续
1、链表的定义
class ListNode:
def __init__(self, val, next=None):
self.val = val
self.next = next
2、链表的操作
(1)删除结点
只许指针指向下下结点
(2)添加结点
前一个指针指向添加结点,添加结点指针指向下下结点
链表:方便插入删除;数组:方便查询
二、203.移除链表元素
1.核心代码
1、注意点是如果要删除第一个怎么办,所以先设置一个虚拟头结点,vhead.next->head
cur=vhead
2、然后还是判断
while cur.next!= None:
cur->cur.next
if cur.val==val:
cur->next=cur->next->next
return vhead.next
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
# 创建虚拟头部节点以简化删除过程
dummy_head = ListNode(next = head)
# 遍历列表并删除值为val的节点
current = dummy_head
while current.next:
if current.next.val == val:
current.next = current.next.next
else:
current = current.next
return dummy_head.next
python与c++的区别:用.访问类型的对象,而不是c++中针对指针的->。实际上,在python中,所有的变量都是对对象的引用,相当于都是指针。
注意cur=cur.next必须在val不等下进行!必须在else中!
2.输入输出
在写链表的输入输出时遇到了问题,搜到了卡码网的题解
卡码网github题解
但是只有下一题的输入输出,所以这边先不管,学会下一题的输入输出
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def removeElements(head, val):
dummy_head = ListNode(0)
dummy_head.next = head
current_node = dummy_head
while current_node.next is not None:
if current_node.next.val == val:
current_node.next = current_node.next.next
else:
current_node = current_node.next
return dummy_head.next
def create_linked_list(elements):
dummy_node = ListNode(0)
current_node = dummy_node
for val in elements:
current_node.next = ListNode(val)
current_node = current_node.next
return dummy_node.next
def print_linked_list(head):
elements = []
while head:
elements.append(head.val)
head = head.next
print(' -> '.join(map(str, elements)))
# 从用户那里得到输入
elements = [int(x) for x in input("请输入链表元素,以空格分开:").split()]
val = int(input("请输入要从链表中删除的元素:"))
# 创建链表并删除元素
head = create_linked_list(elements)
head_without_val = removeElements(head, val)
# 输出处理后的链表
print_linked_list(head_without_val)
三、707.设计链表
1、获取下标为index的结点,但是链表没有下标,只能通过指针链接,因此
1、核心代码
class MyLinkedList(object):
def __init__(self):
self.size=0
self.dummyhead=ListNode(0)
def get(self, index):
"""
:type index: int
:rtype: int
"""
if index>=self.size or index<0:
return -1
cur=self.dummyhead.next
while index:
cur=cur.next
index-=1
return cur.val
def addAtHead(self, val):
"""
:type val: int
:rtype: None
"""
newNode=ListNode(val)
newNode.next = self.dummyhead.next
self.dummyhead.next=newNode
self.size+=1
def addAtTail(self, val):
"""
:type val: int
:rtype: None
"""
newNode=ListNode(val)
cur=self.dummyhead
while cur.next:
cur=cur.next
cur.next=newNode
self.size+=1
def addAtIndex(self, index, val):
"""
:type index: int
:type val: int
:rtype: None
"""
if index<=self.size:
newNode=ListNode(val)
cur=self.dummyhead
while index:
cur=cur.next
index-=1
newNode.next=cur.next
cur.next=newNode
self.size+=1
def deleteAtIndex(self, index):
"""
:type index: int
:rtype: None
"""
if index<=self.size-1 and index>=0:
cur=self.dummyhead
while index:
cur=cur.next
index-=1
cur.next=cur.next.next
self.size-=1
链表中的取固定索引都是通过while循环.next操作逐步取到
2、输入输出
链表输入输出特别复杂,我问chatgpt都修正了三四次才得到正确的代码
import ast
#定义链表节点
class LinkedNode:
def __init__(self, val = 0, next = None):
self.val = val
self.next = next
#定义链表基本操作
class MyLinkedList:
def __init__(self):
self._size = 0
self._dummyHead = LinkedNode(0)
#获取到第index个节点数值,如果index是非法数值直接返回-1, 注意index是从0开始的,第0个节点就是头结点
def get(self, index):
#省略......
def addAtHead(self, val):
def addAtTail(self, val):
def addAtIndex(self, index, val):
def deleteAtIndex(self, index):
class LinkedListRunner:
def __init__(self):
self.LinkedList = MyLinkedList()
self.output = []
def run(self):
commands = ast.literal_eval(input("Enter your commands: "))
arguments = ast.literal_eval(input("Enter your arguments: "))
for cmd, args in zip(commands, arguments):
cmd = cmd.strip(' ')
if cmd == "MyLinkedList":
self.output.append(None)
elif cmd == "addAtHead":
self.LinkedList.addAtHead(args[0])
self.output.append(None)
elif cmd == "addAtTail":
self.LinkedList.addAtTail(args[0])
self.output.append(None)
elif cmd == "addAtIndex":
self.LinkedList.addAtIndex(args[0], args[1])
self.output.append(None)
elif cmd == "get":
self.output.append(self.LinkedList.get(args[0]))
elif cmd == "deleteAtIndex":
self.LinkedList.deleteAtIndex(args[0])
self.output.append(None)
else:
raise ValueError(f"Command '{cmd}' not recognised.")
return self.output
if __name__ == '__main__':
runner = LinkedListRunner()
print(runner.run())
用户输入输出案例为:
输入:
[“MyLinkedList”,“addAtHead”,“addAtTail”,“addAtIndex”,“get”,“deleteAtIndex”,“get”]
[[],[1],[3],[1,2],[1],[1],[1]]
输出:
[null,null,null,null,2,null,3]
从控制台输入读取命令。ast.literal_eval()是一种安全的方法,可以将输入的字符串(字符串应符合Python字面量语法)解析为Python值。
例如,如果你输入的是[“addAtHead”, “addAtTail”, “get”],ast.literal_eval()会将其解析为Python的列表结构:[‘addAtHead’, ‘addAtTail’, ‘get’]。
同样,如果输入的是"[1, 2, 3]",ast.literal_eval()将其解析为Python的列表[1, 2, 3]。
ast 是 Python 的一个内置模块,名字的全称是 Abstract Syntax Trees(抽象语法树)。这个模块可以把 Python 代码转化为抽象语法树,或者把抽象语法树转化为 Python 代码。
在Python中,zip函数将多个可迭代对象打包成一个元组的迭代器。每个迭代器中的元素由输入的可迭代对象中相应位置上的元素组成。
.strip(’ '):这是对字符串进行操作的一个方法。strip() 方法用于移除字符串头尾指定的字符(默认为空白符,包括空格、换行符、制表符等)。
’ ':这是strip()方法的参数,指定了需要去除的字符。在这个例子中,我们指定去除空格字符。
如果字符串 cmd 的两侧有空格,使用这个方法后,这些空格会被去掉,但字符串中间的空格不会被影响。
(1)print() 表示换行
(2)print(x,end=‘’)表示以’ '隔开
(3)while Ture 程序进入一个死循环,除非程序异常或者主动退出
(4)初始化要记得
(5)try:xxx except:xxx 是程序遇到错误的跳转模块,可以由多个except对应多个错误
(6)append在列表的末尾添加
3、其他问题
python中报黄线:
(1)没打空格:可以用ctrl+alt+L,一键自动排版
(2)def的函数不建议用大写,建议用下划线 def name_what 与类 class nameWhat 进行区分
Python2 和 Python3 是 Python 语言的两个主要版本,它们之间存在一些重要的差异:
打印语句:在 Python2 中,print 是一个语句,你可以直接使用 print “Hello World” 就可以打印内容。但在 Python3 中,print 成了一个函数,你需要使用 print(“Hello World”)。
整数除法:在 Python2 中,两个整数相除的结果会自动取整,例如:5 / 2 = 2。但在 Python3 中,两个整数相除的结果会保留小数,例如:5 / 2 = 2.5。
Unicode:Python3 支持 Unicode,可以处理更多的文本数据。在 Python2 中,字符串默认是 ASCII 编码的,需要加u前缀创建 Unicode 字符串,如 u"hello"。
xrange : 在 Python2 中有 range 和 xrange,xrange比range效率更高,因为不会引发内存溢出。但是在 Python3 中,range 函数已经是像 xrange 那样进行优化,而且xrange已经不存在了。
异常处理:Python2中使用 raise ValueError, “math domain error” 或者 raise ValueError(“math domain error”) 来抛出异常,同时使用 , 来从异常中捕获相关变量。Python3中使用 raise ValueError(“math domain error”) 来抛出异常,同时使用 as 来从异常中捕获相关变量。
这只是 Python2 和 Python3 之间的一部分差异。虽然 Python2 继续得到支持,但 Python3 是 Python 的未来,如果你正在学习 Python 或者开发新的项目,我建议你使用 Python3。
三、206.反转链表
1、核心代码
(版本一)双指针法
# 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: 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
说是双指针,其实还保存了一个temp变量
基本思想比较简单
2、输入输出
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverseList(head: ListNode) -> ListNode:
previous = None
current = head
while current:
next_temp = current.next
current.next = previous
previous = current
current = next_temp
return previous
def create_list(nums: list) -> ListNode:
dummy = ListNode(0)
ptr = dummy
for num in nums:
ptr.next = ListNode(num)
ptr = ptr.next
return dummy.next
def list_to_array(head: ListNode) -> list:
arr = []
ptr = head
while ptr:
arr.append(ptr.val)
ptr = ptr.next
return arr
# 获取用户输入,例如:head = [1,2,3,4,5]
input_str = input("请输入链表,格式为 head = [1,2,3,4,5]:")
# 解析输入字符串,提取数字列表
nums_str = input_str[input_str.find("[")+1:input_str.find("]")]
nums_list = list(map(int, nums_str.split(',')))
# 根据数字列表创建链表
head = create_list(nums_list)
# 反转链表
reversed_head = reverseList(head)
# 将反转后的链表转换成列表形式并输出
print("输出:", list_to_array(reversed_head))
nums_str = input_str[input_str.find(“[”)+1:input_str.find(“]”)] 用find定位
总结
链表的输入输出是重点
输入字符串——变为列表——变为链表——核心代码——变为列表输出
变为链表:用指针串起来
变为列表:把值一个个加在list后面