链表-5.13-5.15 判断链表是否相交

题目一(判断无环单链表是否相交):

现在有两个无环单链表,若两个链表的长度分别为m和n,请设计一个时间复杂度为O(n + m),额外空间复杂度为O(1)的算法,判断这两个链表是否相交。

给定两个链表的头结点headAheadB,请返回一个bool值,代表这两个链表是否相交。保证两个链表长度小于等于500。

注意:对于单链表来说,只要一个点相交,那么因为next相同,所以之后的所有结点都相交

思路:

如果只判断是否相交,其实只需要判断最后一个结点是否相同即可。如果要求返回相交的第一个结点,那么我们需要先计算两个链表长度,然后从较长的那个链表开始向后移动,直到两链表剩下的相同,再逐一比较两个链表。比如链表1长100,链表2长50,我们先移动到链表1长50的的位置,然后与链表2一起一边向后移动一边比较

 代码:

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

# 只判断是否相交
class CheckIntersect:
    def chkIntersect(self, headA, headB):
        # write code here
        curA, curB = headA, headB
        while curA.next:
            curA = curA.next
        while curB.next:
            curB = curB.next

        return curA == curB

# 需要返回相交的第一个结点
class CheckIntersect:
    def chkIntersect(self, headA, headB):
        # write code here
        curA, curB = headA, headB
        m, n = 0, 0
        while curA or curB:
            if curA:
                m += 1
                curA = curA.next
            if curB:
                n += 1
                curB = curB.next
        
        curA, curB = headA, headB
        if m > n:
            for i in range(m-n):
                curA = curA.next
        else:
            for i in range(m-n):
                curB = curB.next

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

        return None

题目二(判断有环单链表是否相交):

如何判断两个有环单链表是否相交?相交的话返回第一个相交的节点,不想交的话返回空。如果两个链表长度分别为N和M,请做到时间复杂度O(N+M),额外空间复杂度O(1)。

给定两个链表的头结点head1head2(注意,另外两个参数adjust0adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。

思路:

判断链表是否有环可见:链表-5.12 判断链表是否有环_Iamlzm的博客-优快云博客

对于这题来说,首先应该找到两个链表的环入口,分别记为enter1,enter2。假设enter1 is enter2,那么说明两个链处于如下状态:

 如果enter1 is not enter2,那么两个链表可能不相交,也可能处于如下状态:

 代码:

class ChkIntersection:
    def chkInter(self, head1, head2, adjust0, adjust1):
        # write code here
        enter1, enter2 = self.ringenter(head1), self.ringenter(head2)
        # print(enter1.val, enter2.val)
        if head1 is head2: #情况1:环入口相同
            return True
        cur = enter1
        while True:
            cur = cur.next
            #情况2或3:在环内绕一圈,如果回到原点,说明两环不相交;否则说明环相交
            if cur is enter1 or cur is enter2: 
                break

        return cur is enter2

    def ringenter(self, head): #寻找环入口结点
        fast, slow = head, head
        while True:
            fast = fast.next.next
            slow = slow.next
            if fast is slow:
                break

        slow = head
        while slow is not fast:
            slow = slow.next
            fast = fast.next

        return slow

题目三(两单链表是否有交点):

给定两个单链表的头节点head1和head2,如何判断两个链表是否相交?相交的话返回true,不想交的话返回false。

给定两个链表的头结点head1head2(注意,另外两个参数adjust0adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。

思路:

其实就是前面的综合。首先需要判断:

  1. 如果一个无环,一个有环,那么肯定不相交
  2. 如果都无环,那么按照判断无环单链表是否相交的方法去判断
  3. 如果都有环,那么按照判断有环单链表是否相交的方法去判断

代码:

class ChkIntersection:
    def chkInter(self, head1, head2, adjust0, adjust1):
        # write code here
        enter1, enter2 = self.ringenter(head1), self.ringenter(head2)
        # 一个有环一个无环
        if (enter1 and not enter2) or (not enter1 and enter2):
            return False
        # 都无环
        elif not enter1 and not enter2:
            curA, curB = head1, head2
            while curA:
                curA = curA.next
            while curB:
                curB = curB.next

            return  curA is curB
        # 都有环
        else:
            if head1 is head2:
                return True
            cur = enter1
            while True:
                cur = cur.next
                if cur is enter1 or cur is enter2:
                    break

            return cur is enter2

    def ringenter(self, head):
        fast, slow = head, head
        while fast and fast.next:
            fast = fast.next.next
            slow = slow.next
            if fast is slow:
                break

        if not fast.next:
            return None

        slow = head
        while slow is not fast:
            slow = slow.next
            fast = fast.next

        return slow

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值