*链表的相关题目需要分为笔试和面试准备。
*笔记的话可以不用考虑额外的空间复杂度,但是面试的话需要需要提升自己就利用原有的数据的情况下进行题目的解答的过程。
1.链表的基础知识
逻辑结构上能保持数据之间的逻辑顺序,但存储空间不必按照顺序存储。
分类:
单向链表和单向循环链,注意有一个单独的head指针。
2.链表的基本操作
定义一个class Node(object)类似struct 作为基本数据结构,然后再定义class LinkedList(object)。
2.1计算链表长度
输入头节点,返回长度。self.head就是整个链表的head。
2.2从前插入和从后插入
从前插入,1)如果插入的数据为空,直接返回。2)如果该链表没有node,直接调整self.head的指向。3)设置该节点为头节点的步骤是,将新增的节点指向原来的第一个节点,再将self.head的节点指向新的节点。
从后插入,1)如果插入的数据为空,直接返回。2)如果该链表没有没有node直接调整self.head的指向。3)从后插入,设置为尾节点的步骤是定义一个暂时的节点=self.head遍历到最后一个节点(判断条件是node.next=null) 然后将原来最后的节点指向这个新的节点即可。
*注意,传入的都是数字,所有需要在函数中定义一个Node。
2.3查找
见参考:python数据结构之链表(linked list)_python linked list_黄小猿的博客-CSDN博客
2.4删除
我只采用一个变量完成这个过程,注意不能用curr_node指向的该node的data与值进行判断,需要将该curr_node.next.data == data进行判断,然后之间将curr.node.next=curr.node.next.next。
注意需要判断1)删除数据是否存在。2)self.head是否为空。3)是否删除的是头节点。
def deleteAlt(self):
#只定义一个变量来完成删除操作
if data is None:
return
if self.head is None:
return
if self.head.data == data:
self.head = self.head.next
return
curr_node = self.head
while curr_node.next is not None:
if curr_node.next.data == data:
curr_node.next = curr_node.next.next
return
curr_node = curr_node.next
技能
1.反转链表
该方法在面试的时候可能对减少空间复杂度的作用很大。
整个的思路是我定义两个指针分别一前一后的指向两个节点,
1)先移动next指针到下一个node
2)然后再将当前的节点的next指针指向反转的位置。
3)最后再调整pre和head的指针到相应的位置。
class Solution:
# 迭代写法
def ReverseList(self , head: ListNode) -> ListNode:
# 初始化两个指针pre和next,分别用来前一个节点和当前节点
pre,next = None,None
while head:
# 当前节点指向
next = head.next
# 将当前节点指向改为指向前置节点
head.next = pre
# 将当前节点作为前置节点
pre = head
# 节点向后递归
head = next
# 反转链表后,pre节点是头节点
return pre
2.快慢指针
作用:1.找中间值。2. 删除倒数第n个节点。3. 判断是否为环状链表。
判断一个单链表的回文结构。在只给出head的情况下(不知道长度)。
笔试可以直接将链表里面数据取出来放进额外的空间中(因为链表不能随机访问下表取得位置)
放入栈中,然后一个一个弹出与链表中的值进行一一比对。
然后可以使用快慢指针的方法可以缩短一半空间。
快慢指针就是指定义两个指针,一个走的快(一次走两步)一个走的慢(一次走一步),那么在快指针走到尽头的时候,慢指针就走到中间的位置(分奇数偶数的情况考虑)。
Node和LinkedList的定义如所示 Node和LinkedList链接
题目
141.环形列表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
if not head and not head.next:
return False
fast=head.next
slow=head
# 如果采用以下代码,可以更加节约
fast=head.next.next
slow=head.next
while fast!= slow:
if not fast or not fast.next:
# 不可以指空的空,但是可以指向空,所以只需要判断下一个不为空就可以
# 因为下一个不为空不为空,那么下一个的下一个就一定存在。
return False
fast=fast.next.next
slow=slow.next
return True
2.回文链表(快慢指针+栈,快慢指针+反转链表)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def isPalindrome(self, head: Optional[ListNode]) -> bool:
'''#快慢指针+栈储存
if not head.next:
return True
fast=head.next
slow=head
stack=[]
stack.append(slow.val)
while(fast is not None and fast.next is not None):
fast=fast.next.next
slow=slow.next
stack.append(slow.val)
if(fast is None):
stack.pop()
while(slow.next is not None): #注意判断条件是下一个不为none
slow=slow.next
if stack.pop()!=slow.val:
return False
return True
'''
if not head:
return True
fast = slow = head
while fast.next and fast.next.next:
fast = fast.next.next
slow = slow.next #让慢指针停留在中间靠左边的位置
pre = None
cur = slow.next
slow.next = None #左右两个链表断开
while cur: #反转右半部分的链表
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
#pre指针是右边部分的开头,奇数也不怕
while pre:
if head.val != pre.val:
return False
head = head.next
pre = pre.next
return True