面试中算法(链表)

链表相关的题

    有一个单向链表,链表中有可能出现“环”,如图所示,如何用程序来判断该链表是否为有环链表呢?

对于这道题,有一个很巧妙的方法,这个方法利用了两个指针。

   首先创建两个指针pi和p2(在Python里就是两个对象引用),让它们同时指向这个链表的头节点。然后开始循环,在循环体中,让指针p1每次向后移动1个节点,让指针p2每次向后移动2个节点,然后比较两个指针指向的节点是否相同。如果相同,则可以判断出链表有环,如果不同,则继续下一次循环。

 第1步,p1和p2都指向节点10

 第2步,p1指向节点9,p2指向节点5

 第3步,p1指向节点5,p2指向节点6

 第4步,p1指向节点2,p2指向节点3

第5步,p1指向节点6,p2也指向节点6,p1和p2所指相同,说明链表有环。

     这个题类似于数学上的追及问题。在一个环形跑道上,两个运动员从同一地点起跑,一个运动员速度快,另一个运动员速度慢。当两人跑了一段时间后,速度快的运动员必然会再次追上并超过速度慢的运动员,原因很简单,因为跑道是环形的。

       如果链表的节点数量为n,则该算法的时间复杂度为O (n)。除两个指针外,没有使用任何额外的存储空间,所以空间复杂度是O(1)。

class MyNode:
    '''初始化节点'''
    def __init__(self,data):
        self.data=data
        self.next=None

def circle_linked(head):
    #p1,p2指针指向第一个
    p1=p2=head
    #循环判断
    while p1 is not None and p2.next is not None:
        #指针p1每次向后移动1个节点
        p1=p1.next
        #指针p2每次向后移动2个节点,
        p2=p2.next.next
        #判断如果相同,返回True
        if p1==p2:
            return True

    return False


if __name__ == '__main__':
     #节点数据
     n1=MyNode(10)
     n2=MyNode(9)
     n3=MyNode(5)
     n4=MyNode(2)
     n5=MyNode(6)
     n6=MyNode(8)
     n7=MyNode(3)
     #链表
     n1.next=n2
     n2.next=n3
     n3.next=n4
     n4.next=n5
     n5.next=n6
     n6.next=n7
     n7.next=n4

     #调方法
     print(circle_linked(n1))

扩展问题1: 如果链表有环,如何求出环的长度?

      当两个指针首次相遇,证明链表有环的时候,让两个指针从相遇点继续循环前进,并统计前进的循环次数,直到两个指针第2次相遇。此时,统计出来的前进次数就是环长。

环长=每一次速度差×前进次数

class MyNode:
    def __init__(self, data):
        self.data = data
        self.next = None


def hasCycle(head):
    # p1,p2指针指向第一个
    p1 = p2 = head
    #环长
    len = 0
    # 循环判断
    while p1 is not None and p2.next is not None:
        # 指针p1每次向后移动1个节点
        p1 = p1.next
        # 指针p2每次向后移动2个节点,
        p2 = p2.next.next
        # 判断如果相遇,就结束循环
        if p1 == p2:
            break
    #循环判断
    while (p2 != None) & (p2.next != None):
        p1 = p1.next
        p2 = p2.next.next
        len = len + 1
        if p1 == p2:
            break

    return len


if __name__ == '__main__':
     #节点数据
     n1=MyNode(10)
     n2=MyNode(9)
     n3=MyNode(5)
     n4=MyNode(2)
     n5=MyNode(6)
     n6=MyNode(8)
     n7=MyNode(3)
     #链表
     n1.next=n2
     n2.next=n3
     n3.next=n4
     n4.next=n5
     n5.next=n6
     n6.next=n7
     n7.next=n4

     #调方法
     print(hasCycle(n1))


 扩展问题2: 如果链表有环,如何求出入环节点? 

 抽象示意图:

        从链表头节点入环点的距离是D

        从入环点到两个指针首次相遇点的距离是S1

        从首次相遇点回到入环点的距离是S2

 

 

那么,当两个指针首次相遇时,各自所走的距离是多少呢?

指针p1一次只走1步,所走的距离是D+S1。

指针p2一次走2步,多走了n (n>=1)整圈,所走的距离是D+S1+n ( S1+S2)。

由于p2的速度是p1的2倍,所以所走距离也是pi的2倍,因此: 2(D+S1)=D+S1+n(S1+S2)

等式经过整理得出: D=(n-1)(S1+S2)+S2

 

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-29 11:12:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-29 11:12:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-29 11:12:03       82 阅读
  4. Python语言-面向对象

    2024-04-29 11:12:03       91 阅读

热门阅读

  1. 【机器学习与流体力学交叉领域的期刊】

    2024-04-29 11:12:03       31 阅读
  2. 机器人抓取综述

    2024-04-29 11:12:03       33 阅读
  3. NDK 入门(四)—— 静态缓存与 Native 异常

    2024-04-29 11:12:03       32 阅读
  4. css代码的定位及浮动

    2024-04-29 11:12:03       26 阅读
  5. 【c++】【贪心】排队接水

    2024-04-29 11:12:03       32 阅读
  6. 算法:不同的二叉搜索树

    2024-04-29 11:12:03       26 阅读