链表

链表 - Day1

val 为节点值,next 为节点 listnode

创建虚拟节点 会方便删除等操作 dummy = listnode[next = head]

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

## self调用实例,例如data.min()前面的即为实例

创建装饰器(本质上是一个高阶函数,它接受一个函数作为参数,并返回一个新的函数,可以使函数每次都连带执行)

@staticmethod:将方法定义为静态方法,不需要传递 self 参数。

@classmethod:将方法定义为类方法,第一个参数是类对象 cls。

@property:将方法转换为属性,可以通过访问属性的方式调用方法。

from typing import Optional, List
class ListNode:
    def __init__(self, val, next = None):
        self.val = val
        self.next = next

# 辅助函数: 将列表转换成链表
def list_to_linkedlist(elements: List[int]) -> Optional[ListNode]:
    dummy_head = ListNode()
    current = dummy_head
    for element in elements:
        current.next = ListNode(val=element)
        current = current.next
    return dummy_head.next

# 辅助函数: 将链表转换成列表
def linkedlist_to_list(head: Optional[ListNode]) -> List[int]:
    elements = []
    current = head
    while current:
        elements.append(current.val)
        current = current.next
    return elements

# 装饰器: 转换输入和输出
def convert_input_output(func):
    def wrapper(self, head_list: List[int], val: int) -> List[int]:
        head = list_to_linkedlist(head_list)        # 将列表转换成链表
        new_head = func(self, head, val)            # 调用原函数
        result_list = linkedlist_to_list(new_head)  # 将结果链表转换回列表
        return result_list
    return wrapper

203.移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

主要在于加虚拟节点,然后依次遍历

class Solution:  
    @convert_input_output
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:

        dummy_head = ListNode(next = head)              # 创建虚拟头部节点以简化删除过程
        
        current = dummy_head                            # 遍历列表并删除值为val的节点
        while current.next:
            if current.next.val == val:
                current.next = current.next.next
            else:
                current = current.next
        
        return dummy_head.next

707.设计链表的五个接口

获取链表第index个节点的数值

在链表的最前面插入一个节点

在链表的最后面插入一个节点

在链表第index个节点前面插入一个节点

删除链表的第index个节点

class MyLinkedList:

    def __init__(self):
        self.dummy_head = ListNode()
        self.size = 0
        
    def get(self, index: int) -> int:
        current = self.dummy_head
        if index >= 0 and index <= self.size:
            for i in range(index):
                current = current.next
            return current.val
        else:
            return -1

    def addAtHead(self, val: int) -> None:
        new_head = ListNode(val, self.dummy_head.next)
        self.size += 1

    def addAtTail(self, val: int) -> None:
        current = self.dummy_head
        while current.next:
            current = current.next
        current.next = ListNode(val)
        self.size += 1

    def addAtIndex(self, index: int, val: int) -> None:
        current = self.dummy_head

        if index >= 0 and index <= self.size:
            for i in range(index-1):
                current = current.next
            new_node = ListNode(val, current.next)
            current.next = new_node
        else:
            return
        self.size += 1


    def deleteAtIndex(self, index: int) -> None:
        current = self.dummy_head

        if index >= 0 and index <= self.size:
            for i in range(index - 1):
                current = current.next
            current.next = current.next.next
        else:
            return
        self.size -= 1

链表 - Day2

206.反转链表

双指针,类似数组,但要注意的是需要增加临时节点存储原链表下一节点,否则链表转向后会断开无法继续循环

class Solution:
    @convert_input_output
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:

        cur = head
        pre = None              # 不可以用listnode(),会使得结果增加一个节点

        while cur:
            tmp = cur.next      # 存储下一节点,为了遍历节点
            cur.next = pre      # 反转方向
            pre = cur           # 更新 新链表
            cur = tmp           # 遍历原方向下一个节点
        return pre

24.两两交换链表中的节点

需要递归,循环内交换前后两个节点,前节点向后连接时递归后面的节点

class Solution:
    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None or head.next is None:
            return head
            
        pre = head
        cur = head.next
        next = head.next.next

        cur.next = pre                      # 后节点连接前节点
        pre.next = self.swapPairs(next)     # 前节点连接后后节点,该节点需更新,递归
        return cur

19.删除链表的倒数第 N 个结点

好牛逼的思路,快指针先走n+1步,剩下走的路就是慢指针需要走的路,就可以找到倒数n的节点位置

class Solution:
    @convert_input_output
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
  
        dummy = ListNode(next = head)
        slow = fast = dummy

        for i in range(n+1):
            fast = fast.next

        while fast:
            slow = slow.next
            fast = fast.next
        
        slow.next = slow.next.next
        return dummy.next

面试题 02.07. 链表相交

重点在于对齐,因为如果相交,后续节点长度相等,只要从短的一条链同步进行即可,从后往前判断不现实

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:

        lenA = 0
        lenB = 0
        curA = headA
        curB = headB

        while curA:                    # 计算长度
            lenA += 1
            curA = curA.next
        while curB:
            lenB += 1
            curB = curB.next

        curA = headA                    # 重置,并排序
        curB = headB
        if lenA > lenB:                
            curA, curB = curB, curA
            lenA, lenB = lenB, lenA
        
        for i in range(lenB - lenA):    # 长度对齐
            curB = curB.next

        while curA:
            if curA == curB:
                return curA
            curA = curA.next
            curB = curB.next
        return None      
                    

142.环形链表 II

快的走两步,慢的走一步,环形的话一定会相遇,相遇时重置慢指针

2(x+y) = x+n(y+z)+y

x+y = n(y+z) 原地走n圈

x = n(y+z)-y 即回到相遇点

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        
        slow = head
        fast = head

        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                slow = head
                while slow != fast:
                    slow = slow.next
                    fast = fast.next
                return slow
        
        return None

全部评论

相关推荐

程序员花海:实习太简单了 学历可以的 实习描述应该是先介绍业务 再介绍技术 技术咋推动业务的 做到了啥收益 有没有做实验 实验组和对照组有什么不同 你最后学到了什么 有没有参与处理过线上问题 有没有参与过公司的code review 有没有参与过技术分享 这些都是可以在实习描述中写的 并且实习和项目不一样不会撞车 应该放在最前面 放在教育背景下面 另外项目有点烂大街 可以看下我主页的简历优化案例
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务