swift算法:环形链表II

1、描述

给定一个链表,返回链表开始入环的第一个节点,如果链表无环,则返回null。

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

说明:不允许修改给定的链表

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

          输出:true

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

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

          输出:true

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

 

2、算法

1)哈希表

思想:我们分配一个 Set 去保存所有的列表节点。我们逐一遍历列表,检查当前节点是否出现过,如果节点已经出现过,那么一定形成了环且它是环的入口。否则如果有其他点是环的入口,我们应该先访问到其他节点而不是这个节点。其他情况,没有成环则直接返回 nil

时间复杂度:O(n)

func detectCycle(_ head:ListNode?)->ListNode?{
        /*
         哈希表
         
         */
        var head = head
        var nodeSeen : [Int:ListNode?] = [:]
        while head != nil {
            if nodeSeen[(head?.val)!] != nil {
                return head
            }else{
                nodeSeen[(head?.val)!] = head
            }
            head = head?.next
        }
        return nil
    }

2)双指针

思想:双指针
            算法被划分成两个不同的 阶段 :

在第一阶段,找出列表中是否有环,如果没有环,可以直接返回 null 并退出。

否则,用 相遇节点 来找到环的入口。

时间复杂度:O(n)

func detectCycle2(_ head:ListNode?)->ListNode?{
        /*
         双指针
         
         */
        if head == nil || head?.next == nil {
            return nil
        }
        //如果这里有一个环,快/慢指针就会有一个相遇节点,反之,返回nil
        let intersect = getIntersect(head)
        if intersect == nil {
            return nil
        }
        
        //用两个相同速度的指针,一个从链表头开始,一个从相遇节点开始,当它们指向同一个节点时,这个结点就是环的入口
        var ptr1 = head
        var ptr2 = intersect
        while ptr1?.val != ptr2?.val {
            ptr1 = ptr1?.next
            ptr2 = ptr2?.next
        }
        return ptr1
    }
    private class func getIntersect(_ head:ListNode?)->ListNode?{
        var tortoise = head
        var hare = head
        //快指针会遍历一圈环去遇见慢指针
        //如果没有环,则返回空
        while hare != nil && hare?.next != nil {
            tortoise = tortoise?.next
            hare = hare?.next?.next
            if tortoise?.val == hare?.val{
                return tortoise
            }
            
        }
        return nil
    }

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值