代码随想录算法训练营第三天| 203.移除链表元素、209.设计链表、206.反转链表。

这一部分自刷的时候跳过了(因为据说华子不考),只看了数据结构里面的理论部分。现在补上

链表理论:

定义链表

class ListNode:
    def __init__(self, val, next=None):
        self.val = val
        self.next = next

一个值、一个next指针指向下一个节点的存储位置。

next等于None的时候表示链表结束----->常用判断链表是否结束的语句

while current.next:  ##当前节点的next指针不为空

调用该节点的值和指针的方法:

目前的节点名叫current,eg:current.val(当前节点存储值)     current.next(当前节点存储的指向的下一个节点的指针)

可以重复连续使用:eg:current.next.val(当前节点的下一个节点的值)current.next.next(当前节点下下个位置存储的指针)

在链表中新加入时,构造语法该为:

节点位置 = LinkNode(值,要指向的下个节点位置)

203.移除链表元素

主要是不太熟悉列表理论。next太多了要绕晕,冷静思考!!!

# 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]:
        xunihead = ListNode(next=head)#定义一个虚拟头节点,指针下一个是目标链表
        cur =  xunihead
        while cur.next:
            if cur.next.val == val:#由于设了个虚拟头结点,所以从cur.next(原定头节点)开始找
                cur.next = cur.next.next#找到了目标值,则直接把下一个要读取的位置跳到下下个节点,把cur.next跳过去
            else:
                cur = cur.next#没有找到目标值,于是正常向下读
        return xunihead.next#去掉虚拟头节点

209.设计链表

class LinkNode:
    def __init__(self,val=0,next=None):#构造一个链表,
        self.val = val
        self.next = next

class MyLinkedList:#链表的五种操作

    def __init__(self):#初始化变量的作用。意思是在调用这个类的时候,都要先运行这个。这里定义的变量,后面的函数都可以直接调用
        self.dummy_head = LinkNode()#加入虚拟头节点
        self.size = 0#定义一个size变量,并初始化赋值为0

    def get(self, index: int) -> int:
        if index<0 or index>=self.size:#注意违规条件,也有等号,index的范围应该是0到size-1
            return -1    

        # cur = self.dummy_head.next
        # for i in range(index):
        #     cur = cur.next
        #  return cur.val

        i=0   
        cur = self.dummy_head#对cur赋初始值,掉因init中定义的变量
        while i < index:#i最大值是index-1,i=0的时候cur才等于原head,因此index-1才到index前一位
            cur = cur.next
            i += 1
        return cur.next.val

    def addAtHead(self, val: int) -> None:
        self.dummy_head.next = ListNode(val, self.dummy_head.next)#构造链表的方式,ListNode(值,指向的位置)
        self.size += 1#别忘记size要加1

    def addAtTail(self, val: int) -> None:
        cur = self.dummy_head
        while cur.next:#链表无法直接找到最后一个节点的位置,因此需要从第一个节点开始遍历
            cur = cur.next
        cur.next = LinkNode(val,None)
        self.size+=1

    def addAtIndex(self, index: int, val: int) -> None:
        if index < 0 or index > self.size:#非法操作,则不做任何操作,直接结束
            return

        cur = self.dummy_head
        for i in range(index):
            cur = cur.next
        cur.next = LinkNode(val,cur.next)
        self.size += 1

    def deleteAtIndex(self, index: int) -> None:
        if index < 0 or index >= self.size:#非法操作,则不做任何操作,直接结束,注意有等号
            return

        cur = self.dummy_head
        for i in range(index):#找到index的前一个节点,i=0的时候指向原head的第一个节点,因此最后一次操作刚好指向index-1的节点
            cur = cur.next
        cur.next = cur.next.next
        self.size -= 1


# 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)

链表几个要注意的点

1、链表无法直接到达指定index节点位置,需要从头开始遍历。而且链表的输入输出都只需要头节点,其他的节点是可以从头节点开始往后查的,已经捆绑了!

2、链表index的范围,和列表相似都是0到size-1,在判定违法输入时要特别注意判断条件index是<size还是<=size,注意思考有没有等号

3、使用虚拟头节点的话,如果想要找到index的位置,要注意遍历循环结束时,是停在了index-1的位置还是index的位置。根据不同的需要设定遍历循环的起始位置!

4、如果需要多个列表应该调用多次class LinkNode,eg:

class ListNode:
    def __init__(self, val=0, next=None):#构造时,括号里要写好初始值,别忘了!!
        self.val = val
        self.next = next
        
class MyLinkedList:
    def __init__(self):
        self.head = None
        
    def add_at_head(self, val):
        new_node = ListNode(val)
        new_node.next = self.head
        self.head = new_node
        
# 创建两个链表对象
list1 = MyLinkedList()
list2 = MyLinkedList()

# 向链表中添加节点
list1.add_at_head(1)
list1.add_at_head(2)
list1.add_at_head(3)

5、还有新认识到的类!

函数def __init__(self): 初始化变量的作用。意思是在调用这个类的时候,都要先运行这个。这里定义的变量,后面的函数都可以直接调用。但是记得都要带self!!!例如在init中定义了self.dummy_head,那么之后每次引用时都要带self.,即self.dummy_head,而非是dummy_head

206.反转链表

双指针法:

把cur的指针指向pre,然后cur和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]:
        cur = head#初始化两个指针
        pre = None
        while cur:
            temp = cur.next#因为等下cur.next要指向pre(cur是没变的)

            cur.next = pre#把cur的指针(cur.next)指向前一个(pre)

            cur = temp #更新输入输出变量,指针位置往前移动
            pre = cur           

        return pre#只需要输出头节点,后面的节点式存储在头节点中的

递归法没太看懂……

感谢GPT今天把递归补上了。递归的核心思想就是函数的返回量 是调用这个函数本身,直至满足终止条件,属于是while的函数写法了。把这部分单独写成一个函数的话,应该是能让主函数更加简洁?

# 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:#链表到达最后,此时的pre就是头节点
            return pre

        temp = cur.next
        cur.next = pre #把指针指向前一个节点

        return self.reverse(temp,cur)

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值