• 20190524-快慢指针的各种应用


    快慢指针

    定义

    快慢指针就是定义两根指针,移动的速度一快一慢,以此来制造出自己想要的差值。这个差值可以让我们找到链表上相应的节点以及一系列操作

    应用

    1. 找出链表的中间节点
    2. 判断链表是否存在环
    3. 删除链表的倒数第n的节点
    4. 将有序链表转换为二叉搜索树

    找出链表的中间节点

    给定一个带有头结点 head 的非空单链表,返回链表的中间结点。

    如果有两个中间结点,则返回第二个中间结点。

    题目描述

    示例 1

    输入:[1,2,3,4,5]

    输出:此列表中的结点 3 (序列化形式:[3,4,5]),返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。

    注意,我们返回了一个 ListNode 类型的对象 ans,这样:ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.

    示例 2

    输入:[1,2,3,4,5,6]

    输出:此列表中的结点 4 (序列化形式:[4,5,6])

    由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。

    示例1图示:下图为一个链表,每个方格表示一个节点,每个节点都指向下一个节点

    1

    2

    3

    4

    5

                     ↑中间节点

    1

    2

    3

    4

    5

    6

                                ↑中间节点

    测试数据

    class Node():
        '''定义一个链表类'''
        def __init__(self,val,next =None):
            self.val = val
            self.next = next
    #构造测试数据[1,2,3,4,5],其中1,2,3,4,5,均为Node节点
    head = None
    for i in range(5,0,-1):
        head = Node(i,head)
    #构造测试数据[1,2,3,4,5,6],其中1,2,3,4,5,6,均为Node节点
    head1 = None
    for i in range(6,0,-1):
        head1 = Node(i,head1)

    常规思路

    1. 拿到链表的长度。而拿到这个长度也比较简单,只需要遍历前设定一个计数count,遍历的时候 count++ ,遍历结束,就拿到单链表的长度了。
    2. 根据链表的长度求出链表的中间值,再次遍历链表获取中间值。由此可知求链表的中间节点值总共遍历了链表2次
    3. 首先定义2个指针,快指针quick,慢指针slow快指针的移动速度是慢指针移动速度的2倍,因此当快指针到达链表尾时,慢指针到达中点。
    4. 程序还要考虑链表结点个数的奇偶数因素,当快指针移动x次后到达表尾(1+2x),说明链表有奇数个结点,直接返回慢指针指向的数据即可。以示例链表[1,2,3,4,5,6]如下图:

    代码

    ####################链表的中间节点值常规思路########################
    #第一步:求链表的长度
    def get_NodeLength(head):
        '''求链表的长度'''
        length = 0
        while head:
            length+=1
            head = head.next
        return length
    print(get_NodeLength(head))#输出5
    print(get_NodeLength(head1))#输出6
    #第二步:根据链表的长度求链表的中间节点
    def get_ModemidValue(head):
        '''根据链表的长度求链表的中间节点'''
        length = get_NodeLength(head)#调用求链表长度函数,获取链表的长度
        mid = length//2#中间节点是链表长度的一半
        while mid >0:
            mid -=1
            head = head.next
        return head#返回的是一个Node
    #检查函数返回的正确性:遍历返回的Node和其后面节点的查看结果
    new_head = get_ModemidValue(head)
    while  new_head:
        print(new_head.val)
        new_head = new_head.next
    #输出3,4,5
    new_head1 = get_ModemidValue(head1)
    while  new_head1:
        print(new_head1.val)
        new_head1 = new_head1.next
    #输出4,5,6

    使用快慢指针思路

    代码

    ####################使用快慢指针求链表的中间节点########################
    def get_Nodemidvalue_with2point(head):
        '''使用快慢指针求链表的中间节点'''
        quick = head#快指针,每次走两步
        slow = head#慢指针,每次走一步
        while quick and quick.next:#循环结束条件为快指或者快指针的下一个节点不为空
            quick = quick.next.next
            slow = slow.next
        return slow#返回的是一个Node
    #检查函数返回的正确性:遍历返回的Node和其后面节点的查看结果
    new_head_with2point = get_Nodemidvalue_with2point(head)
    while new_head_with2point:
        print(new_head_with2point.val)
        new_head_with2point = new_head_with2point.next
    #输出3,4,5
    new_head_with2point1 = get_Nodemidvalue_with2point(head1)
    while new_head_with2point1:
        print(new_head_with2point1.val)
        new_head_with2point1 = new_head_with2point1.next

    判断链表是否存在环

    题目描述

    给定一个链表,判断链表中是否有环。

    为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

    示例 1

    输入:head = [3,2,0,-4], pos = 1

    输出:true

    解释:链表中有一个环,其尾部连接到第二个节点。

    示例 2

    输入:head = [1,2], pos = 0

    输出:true

    解释:链表中有一个环,其尾部连接到第一个节点。

    示例 3

    输入:head = [1], pos = -1

    输出:false

    解释:链表中没有环。

    测试数据

    class Node():
        '''定义一个链表类'''
        def __init__(self,val,next =None):
            self.val = val
            self.next = next
    #构造测试数据[1,2,3,4,5],其中1,2,3,4,5,均为Node节点,无环
    head = None
    for i in range(5,0,-1):
        head = Node(i,head)
    #构造测试数据[1,2,3,4,5,6,7...],其中1,2,3,4,5,6,7均为Node节点,有环
    head1 = Node(7)
    temp = head1#temp用于构建环
    for i in range(6,0,-1):
        head1 = Node(i,head1)
    temp.next = head1

    常规思路

    遍历链表,使用一个列表存储已经遍历过的节点,当链表节点指向None时候证明无环,当链表遍历的时候链表已在result中,则证明有环。

    代码

    def hasCycle(head):
        result =[]
        while head:
            if head in result:
                return True#有环
            result.append(result)
            head = head.next
    return False#无环
    print(hasCycle(head))#输出False
    print(hasCycle(head1))#输出True

    使用快慢指针

    1. 首先定义2个指针,快指针quick,慢指针slow快指针的移动速度是慢指针移动速度的2倍,如果快指针到达NULL,说明链表以NULL为结尾,没有环。如果快指针追上慢指针,则表示有环。

    代码

    ####################使用快慢指针链表的是否有环########################
    def hasCycle(head):
        quick = head
        slow = head
        while quick and quick.next:
            quick = quick.next.next
            slow = slow.next
            if quick ==slow:
                return True#有环
        return False#无环       
    print(hasCycle(head))#输出False
    print(hasCycle(head1))#输出True

    删除链表的倒数第n的节点

    题目描述

    给定一个链表,删除链表的倒数第 个节点,并且返回链表的头结点。

    示例:

    给定一个链表: 1->2->3->4->5, 和 n = 2.

    当删除了倒数第二个节点后,链表变为 1->2->3->5.

    说明:

    给定的 n 保证是有效的。

    测试数据

    class Node():
        '''定义一个链表类'''
        def __init__(self,val,next =None):
            self.val = val
            self.next = next
    #构造测试数据[1,2,3,4,5],其中1,2,3,4,5,均为Node节点
    head = None
    for i in range(5,0,-1):
        head = Node(i,head)

    常规思路

    1. 拿到链表的长度。而拿到这个长度也比较简单,只需要遍历前设定一个计数count,遍历的时候 count++ ,遍历结束,就拿到单链表的长度了。
    2. 根据链表的长度拿到倒数第n个节点所在位置,进行删除

    代码

    使用快慢指针

    使用2个指针,一个是quick一个是slow。先让quick走n-1步,然后再让quick和slow同时往前走,当quick走到头时,slow即是倒数第n个节点了

    图示-以链表1->2->3->4->5, 和 n = 2为例

    代码

    def removeNthFromEnd(head,n):
            quick = head#quick指针
            slow = head#slow指针
            pre = None
            while quick:
                if quick.next is None:#当quick指向队尾的时候,slow指向的是倒数第n个节点
                    if pre is not None:#pre指向的是倒数第n-1个节点
                        pre.next = slow.next#pre非空,则删除第n个节点
                    else:#pre空,head = slow.next
                        head = slow.next
                quick = quick.next
                n-=1
                if n<=0:#当n<=0的时候slow开始移动
                    pre = slow
                    slow = slow.next
            return head
    result = removeNthFromEnd(head,2)
    while result:
        print(result.val)
        result=result.next
    #输出结果1,2,3,5

    将有序链表转换为二叉搜索树

    题目描述

    给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。

    本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

    示例:

    给定的有序链表: [-10, -3, 0, 5, 9],

    一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:

          0

         /

       -3   9

       /   /

     -10  5

    测试数据

    class Node():
        '''定义一个链表类'''
        def __init__(self,val,next =None):
            self.val = val
            self.next = next
    #构造测试数据[-10, -3, 0, 5, 9],其中-10, -3, 0, 5, 9均为Node节点
    head = None
    for i in [9,5,0,-3,-10]:
        head = Node(i,head)
     
    class TreeNode(object):
        def __init__(self, x):
         self.val = x
         self.left = None
         self.right = None

    使用快慢指针

    代码

    def get_midNode(head):#获取链表的中间节点
        '''获取链表的中间节点'''
        sp = head
        qp = head
        pre = None
        while qp and qp.next:
            pre = sp
            sp = sp.next
            qp = qp.next.next
        if pre is not None:
            pre.next = None
        else:
            head = None
        return head,sp    
     
    def sortedListToBST(head):#转换为二叉搜索树
        '''将链表的中间节点作为树的根节点,递归的方式,左子链表去构建左子树,右子链表构建右子树'''
        new_head,second_head = get_midNode(head)
        if head is None:
            return None
        result = TreeNode(second_head.val)
        result.left = self.sortedListToBST(new_head)
        result.right = self.sortedListToBST(second_head.next)
    return result
    #检验二叉树构建是否成功,如果成功,二叉树的中序遍历结果应该是升序
    treenode = sortedListToBST(head)
    print(treenode)
    def treenode_inorder_traversal(TreeNode):
        if TreeNode is None:
            return []
        center = [TreeNode.val]
        left = treenode_inorder_traversal(TreeNode.left)
        right = treenode_inorder_traversal(TreeNode.right)
        return left+center+right
    print(treenode_inorder_traversal(treenode))#输出:[-10, -3, 0, 5, 9]
  • 相关阅读:
    安卓app_sl_4_14询问是否退出的对话框关闭程序退出程序
    安卓app_sl4_12使用Notification在状态栏上显示通知
    安卓app_sl4_15带图标的列表对话框
    安卓app_sl4_13使用AlertDialog创建对话框
    JAVA字符串怎么转换成整数
    安卓app_sl4_16实现仿Windows 7图片预览窗格效果
    PCC工业控制全程含义
    Vue3 + TypeScript + Vite创建项目
    pinia介绍与使用
    微服务架构Spring Cloud(注册中心eureka、配置中心config、负载均衡feign、断路器hystrix、仪表盘hystrix、授权认证模块auth、路由网关zuulgateway、用户管理中心usermgr、日志模块log、服务管理模块mgr等)
  • 原文地址:https://www.cnblogs.com/hyj691001/p/10915876.html
Copyright © 2020-2023  润新知