首页 > 其他分享 >链表应用 III

链表应用 III

时间:2023-05-23 16:22:15浏览次数:57  
标签:slow ListNode fast next 链表 应用 return III

目录

链表

链表相关的典型应用如下:

序号 题目
1 21. 合并两个有序链表
2 23. 合并 K 个升序链表
3 141. 环形链表
4 142. 环形链表 II
5 876. 链表的中间结点
6 160. 相交链表
7 19. 删除链表的倒数第 N 个结点

应用

应用1:Leetocde.21

题目

21. 合并两个有序链表

分析

定义一个虚节点 \(dummy\),然后开始遍历两个链表,每次将两个链表中较小的节点连接到新链表上,并后移动当前链表的指针。

遍历完后,如果两个链表的长度不相等,将剩余链表直接连接到新链表上。

代码实现

方法一:迭代实现

class Solution:
    def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
        return self.merge(list1, list2)

    def merge(self, left: ListNode, right: ListNode):
        """ 迭代实现 """
        dummy = ListNode(-1)
        node = dummy
        while left and right:
            if left.val < right.val:
                node.next = left
                left = left.next
            else:
                node.next = right
                right = right.next
            node = node.next

        if not left:
            node.next = right
        else:
            node.next = left
        return dummy.next

方法一:递归实现

class Solution:
    def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
        return self.merge(list1, list2)

    def merge(self, left: ListNode, right: ListNode):
        """ 递归实现 """
        if not left:
            return right

        if not right:
            return left

        if left.val < right.val:
            left.next = self.merge(left.next, right)
            return left
        else:
            right.next = self.merge(left, right.next)
            return right

应用2:Leetocde.23

题目

23. 合并 K 个升序链表

分析

方法一:分治

使用分治的思想,将原链表数组拆分,将多个链表的合并,转换为合并两个链表的问题。

方法二:优先级队列

代码实现

把链表的头结点放进一个小根堆,这样堆顶的元素始终是最小的元素,只需要每次弹出一个元素,即最小元素,如果它还有后驱节点,则将其放回小根堆。

方法一:分治

class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        return self.merge(lists, 0, len(lists) - 1)

    def merge(self, lists, left: int, right: int):
        if left == right:
            return lists[left]
        if left > right:
            return None

        mid = (left + right) // 2
        return self.merge_2_lists(self.merge(lists, left, mid), self.merge(lists, mid + 1, right))

    def merge_2_lists(self, list1: ListNode, list2: ListNode):
        if list1 is None:
            return list2
        if list2 is None:
            return list1

        dummy = ListNode()
        p = dummy
        p1 = list1
        p2 = list2
        while p1 and p2:
            if p1.val < p2.val:
                p.next = p1
                p1 = p1.next
            else:
                p.next = p2
                p2 = p2.next
            p = p.next
        if p1:
            p.next = p1
        if p2:
            p.next = p2
        return dummy.next

方法二:优先级队列

class Solution {
    ListNode mergeKLists(ListNode[] lists) {
        if (lists.length == 0) {
            return null;
        }
        // 虚拟头结点
        ListNode dummy = new ListNode(-1);
        ListNode p = dummy;
        // 优先级队列,最小堆
        PriorityQueue<ListNode> pq = new PriorityQueue<>(
            lists.length, (a, b)->(a.val - b.val)
        );

        // 将 k 个链表的头结点加入最小堆
        for (ListNode head : lists) {
            if (head != null)
                pq.add(head);
        }

        while (!pq.isEmpty()) {
            // 获取最小节点,接到结果链表中
            ListNode node = pq.poll();
            p.next = node;
            // 如果当前节点还有next节点,将其放回小根堆
            if (node.next != null) {
                pq.add(node.next);
            }
            // p 指针不断前进
            p = p.next;
        }
        return dummy.next;
    }
}

应用3:Leetocde.141

题目

141. 环形链表

分析

使用快慢指针即可,慢指针走一步,快指针走两步,如果快慢指针相遇,则链表存在环,否则就不存在环。

代码实现

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        if not head or not head.next:
            return False

        slow = head
        fast = head.next

        while slow != fast:
            if not fast or not fast.next:
                return False

            slow = slow.next
            fast = fast.next.next

        return True

应用4:Leetocde.142

题目

142. 环形链表 II

分析

算法步骤:

  • 使用快慢指针 \(slow\) 和 \(fast\),分别指向链表的头节点;

  • 遍历链表,慢指针走一步,快指针走两步,当两者相遇时,则停止遍历;

    • 如果快指针 \(fast\) 指向空节点或者 \(fast\) 的下一个节点为空节点,则不存在环;

    • 否则,重新让慢指针 \(slow\) 指向头节点,\(fast\) 指针从当前位置开始移动,如果两者相遇,则相遇的位置就是环的起点。

代码实现

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast, slow;
        fast = slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                break;
            }
        }

        if (fast == null || fast.next == null) {
            // fast 遇到空指针说明没有环
            return null;
        }

        // 重新指向头结点
        slow = head;
        // 快慢指针同步前进,相交点就是环起点
        while (slow != fast) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

应用5:Leetocde.876

题目

876. 链表的中间结点

分析

使用快慢指针的思路,即慢指针走一步,快指针走两步,当快指针走到链表末尾时,慢指针就指向链表中点。

代码实现

class Solution {
    public ListNode middleNode(ListNode head) {
        // 快慢指针初始化指向 head
        ListNode slow = head, fast = head;
        // 快指针走到末尾时停止
        while (fast != null && fast.next != null) {
            // 慢指针走一步,快指针走两步
            slow = slow.next;
            fast = fast.next.next;
        }
        // 慢指针指向中点
        return slow;
    }
}

应用6:Leetocde.160

题目

160. 相交链表

分析

代码实现

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        if not headA or not headB:
            return None

        p1 = headA
        p2 = headB
        while p1 != p2:
            p1 = headB if not p1 else p1.next
            p2 = headA if not p2 else p2.next
        return p1

应用7:Leetocde.19

题目

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

分析

算法思路:

  • 先通过双指针的思路,找到倒数第 \(n + 1\) 个节点,即待删除节点的前一个节点;

    查找倒数的 \(k\) 个节点的思路:

    • 使用两个指针p1p2,同时指向头节点;

    • 先让 p1 先移动 k 步;

    • p1p2 同时后移,直到 p1 移动到链表末尾。

  • 删除倒数第 \(n + 1\) 个节点的下一个节点;

代码实现


class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        if not head:
            return head
        dummy = ListNode(-1, head)
        # 找到倒数第n+1个节点
        node = self.findFromEnd(dummy, n + 1)
        node.next = node.next.next
        return dummy.next

    def findFromEnd(self, head: ListNode, k) -> ListNode:
        """ 找到链表的倒数第k个节点 """
        p1 = head
        # p1先移动k步
        for i in range(k):
            p1 = p1.next

        p2 = head
        # p2移动 n - k 步
        while p1:
            p1 = p1.next
            p2 = p2.next
        return p2

    def removeNthFromEnd2(self, head: ListNode, n: int) -> ListNode:
        dumy = ListNode(-1, head)
        fast, slow = head, dumy

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

        while fast:
            fast = fast.next
            slow = slow.next

        slow.next = slow.next.next

        return dumy.next

参考:

标签:slow,ListNode,fast,next,链表,应用,return,III
From: https://www.cnblogs.com/larry1024/p/17425167.html

相关文章

  • golang context 应用
    packagemainimport( "context" "fmt" "time")funcmain(){ //创建初始上下文 ctx:=context.Background() //派生可取消的上下文 cancelCtx,cancel:=context.WithCancel(ctx) //启动一个Goroutine执行任务 godoTask(cancelCtx) //等待一段时......
  • Android开发 UsageStatsManager应用使用情况管理
    前言  UsageStatsManager是用来知晓,设备中应用的使用情况的管理。它能给我们提供应用的进入前台动作与时间戳、进入后台的动作与时间戳、上次的使用时间、使用总时长等等信息。此功能在原生的设置-应用-使用统计中有所展示。所需权限<uses-permissionandroid:name="android.......
  • Lazada详情接口的应用
    Lazada是东南亚电商领域的一家知名企业,Lazada商品详情接口是Lazada提供的一种获取Lazada平台商品详细信息的接口。本文将介绍Lazada商品详情接口的使用方法和相关注意事项。第一步:申请访问Lazada商品详情接口在使用Lazada商品详情接口之前,需要先向Lazada申请访问该接口的权......
  • 启发式算法在三维装箱问题上的应用
    启发式算法的出现时间比较难以确定,因为很多算法的提出都是在不同的领域和不同的时间段内,而且随着时间的推移,这些算法也在不断地完善和发展。以下是一些比较有代表性的启发式算法及其出现时间:1953年,模拟退火算法(SimulatedAnnealing,SA)模拟退火算法是一种基于固体物理学中固体退火......
  • 关于AI与api-Java接口的区别应用点
    AI和API是目前互联网技术中的两个趋势,它们在许多领域都发挥了重要作用。在技术的领域中,AI代表的是人工智能,而API代表的是应用程序接口。在本文中,将讨论AI和API的详细分析。AI是人工智能的简称,是指通过计算机技术模拟人类智能的一种技术体系。AI可以学习数据并自我改进,以达到更好的......
  • 图解LeetCode——剑指 Offer 36. 二叉搜索树与双向链表
    一、题目输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。二、示例为了让您更好地理解问题,以下面的二叉搜索树为例:我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对......
  • 无线振弦传感采集仪在工程监测中的应用解决方案
    无线振弦传感采集仪在工程监测中的应用解决方案 无线振弦传感采集仪是一种高性能的工程监测设备,具有多种优点,如无线传输、高精度、高灵敏度和高可靠性等。在工程监测领域,无线振弦传感采集仪被广泛应用于桥梁、隧道、建筑物等结构物的动态监测、损伤诊断、安全评估和监测预警等......
  • ADG级联备库环境PSU应用验证
    上篇文章源端为备库的场景下Duplicate失败问题我只在中间备库环境应用了PSU,解决了级联备库从中间备库duplicate数据库的问题:细心的朋友已经发现,因为是备库环境,并没有做数据库执行相关脚本部分,所以如果去DB查询补丁应用信息是没有的:SQL>r1*select*fromdba_registry_......
  • 盘点界面控件DevExpress WinForms的几大应用程序主题
    DevExpressWinForm控件包含了50+个自定义皮肤,其中涵盖了MicrosoftOffice和Windows11启发式的应用程序主题。PS:DevExpressWinForm拥有180+组件和UI库,能为WindowsForms平台创建具有影响力的业务解决方案。DevExpressWinForm能完美构建流畅、美观且易于使用的应用程序,无论是Of......
  • 浅析视频技术与AI智能识别技术在智慧矿山场景中的应用
    一、背景分析 能源与矿业是我国国民经济的重要物质生产部门和支柱产业之一,同时也是一个安全事故多发的高危行业,施工阶段的现场管理对工程成本、进度、质量及安全等至关重要。国家矿山安监局陆续发布(矿安〔2022)128号)文、(矿安综〔2023〕5号)文推动矿山重大灾害风险防控,山西、......