代码随想录二刷(链表章节)

代码随想录二刷(链表章节)

在这里插入图片描述
链表就是通过指针串联在一起的线性结构,每个节点都是由一个数据域和指针域(存放下一个节点的指针)。
双链表就是每个节点中既有指向前一个节点的,也有指向后一个节点的。
在这里插入图片描述
循环链表就是把头和尾连起来。
在这里插入图片描述
性能分析如下:
在这里插入图片描述
下面来看下链表的具体题目:

Leetcode203

在这里插入图片描述
这里首先要明白处理链表一个技巧就是可以创立一个哨兵节点。这样就能避免处理一些特殊情况,比如只有头的情况下。这样的话,链表始终是有一个元素的。具体来说过程如下图

在这里插入图片描述

# @lc code=start
# 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 = ListNode(next = head)
        cur = dummy
        while cur.next:
            if cur.next.val == val:
                cur.next = cur.next.next
            else:
                cur = cur.next
        return dummy.next  

Leetcode707

在这里插入图片描述

具体程序如下:

class Listnode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
class MyLinkedList:

    def __init__(self):
        self.dummy = Listnode()
        self.size = 0
    def get(self, index: int) -> int:
        if index < 0 or index >= self.size:
            return -1
        cur = self.dummy
        while cur.next:
            if index == 0:
                return cur.next.val
            cur = cur.next
            index -= 1
    def addAtHead(self, val: int) -> None:
        cur = self.dummy
        cur.next = Listnode(val,cur.next)
        self.size += 1
    def addAtTail(self, val: int) -> None:
        cur = self.dummy
        while cur.next:
            cur = cur.next
        cur.next = Listnode(val)
        self.size += 1
    def addAtIndex(self, index: int, val: int) -> None:
        cur = self.dummy
        if index > self.size or index < 0:
            return 
        for _ in range(index):
            cur = cur.next
        cur.next = Listnode(val, cur.next)
        self.size += 1
    def deleteAtIndex(self, index: int) -> None:
        cur = self.dummy
        if index >= self.size or  index < 0:
            return
        for _ in range(index):
            cur = cur.next
        cur.next = cur.next.next
        self.size -= 1

首先分析get函数的实现:
在这里插入图片描述
由于题目要求下标是从0开始,所以要用个self.size记录下链表中元素的数量。那么插入头部和插入尾部以及删除指定Index,都会涉及到self.size的变化。
首先要把下标无效的情况给排除掉。也就是

if index < 0 or index >= self.size:
            return -1

接下里操作链表的话都是要用哨兵节点(这样就可以将只有一个元素的特殊情况也给合并了)。用for循环遍历就可以:

        cur = self.dummy
        for _ in range(index):
            cur = cur.next
        return cur.next.val


插入到第一个元素之前,也就是插入到头之前。这时候就体会到哨兵节点的好用了。

cur.next = Listnode(val,cur.next)

cur代表哨兵节点,哨兵节点的下一个也就是头部的位置,所以创建一个值为val,并且这个节点为原来节点的下一个节点。这样就完成插入的操作了
删除操作的话 ,
在这里插入图片描述

所以还要先判断下标是否超范围:

        if index >= self.size or  index < 0:
            return

然后接着for循环去根据index来。然后要删除的节点。

        for _ in range(index):
            cur = cur.next

所以删除:cur.next = cur.next.next
如果不明白的话。画个图就好理解下,做关于链表的题目。
在这里插入图片描述

在这里插入图片描述
插入操作的也可以画个图:
在这里插入图片描述

        cur = self.dummy
        if index > self.size or index < 0:
            return 
        for _ in range(index):
            cur = cur.next
        cur.next = Listnode(val, cur.next)

下面来看下反转链表的题目。
在这里插入图片描述
这里采用双指针的思想,pre为该节点要指向的新位置,cur为当前要处理的节点。并且当前要处理的节点的下个位置的信息由于你改变了指向会丢失,所以要用临时变量temp给保存起来。这些操作完成后,pre移动到cur,然后cur移动到下个位置也就是pre的位置。
所以程序思路其实知道了双指针后,并不是很难写出来:

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        cur = head
        pre = None
        while cur:
            temp = cur.next
            cur.next = pre
            pre = cur
            cur = temp
        return pre

Leetcode24

下面来看下下道题两两交换的链表题目:

在这里插入图片描述
这个交换链表的也建议是画图的话更好去理解。
在这里插入图片描述
看着这个图去写程序就可以。

class Solution:
    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        dummy_head = ListNode(next = head)
        cur = dummy_head
        pre = None
        while cur.next and cur.next.next:
            temp1 = cur.next
            temp2 = cur.next.next.next
            cur.next = cur.next.next
            cur.next.next = temp1
            cur.next.next.next = temp2
            cur = cur.next.next
        return dummy_head.next

但是while循环要注意不止要判断Cur.next,还要判断cur.next.next。因为程序里面都是两两交换的。

Leetcode19

继续一道倒着删除链表的题目:
在这里插入图片描述

这道题思路是用双指针的思路,因为要删除倒数第n个节点。而链表的话只能按顺序遍历,所以用一个快指针,一个慢指针。快指针先走n步,然后在快指针的基础上慢指针移动,终止条件是快指针到达末尾。这样慢指针停的位置就是刚好要删除节点的前面一个。
具体原理如下:
在这里插入图片描述

class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummy_head = ListNode(0,head)
        slow,fast = dummy_head,dummy_head
        for _ in range(n+1):
            fast = fast.next
        while fast:
            slow = slow.next
            fast = fast.next
        slow.next=slow.next.next
        return dummy_head.next  
posted @ 2024-07-30 19:31  Bathwind_W  阅读(1)  评论(0编辑  收藏  举报