l1l1llll1 php,php判断单链表是否有环和相交

前言

前面几个文章讲了单链表和快慢指针的用法, 这里再延伸一下快慢指针的用法

本文讲解三个例子:

给定一个单链表,判断是否有环(链表后部分存在循环,或者就是一个循环链表)

如果有环,找到环的入口

判断两个单链表是否相交

1.判断单链表是否有环

如果一个链表存在循环, 则代表该链表有环,其中,可能是部分循环, 也可能是首尾相接的循环链表, 如下图

在后面形成环的单链表

dd31599b58d02fdb57a6d49150e9dc9d.png

首尾相接的循环单链表

487d235da7dcf0341e407caf9593d30b.png

解析

这里我们还需要用到快慢指针, 快慢指针同时从链表头出发, 快指针每次走2步,慢指针每次走1步,当快指针走到了末尾时, 代表该链表不是环形链表

反之,当快指针追上了慢指针,则代表该链表是环形链表

理解这个就好像我们在操场跑步一样, 跑道是环形的, 两个人赛跑,一个跑的快, 一个跑的慢,如果我们不让他停下来,跑的快的人总会'追'上跑的慢的人

比如第一张图片,我们可以推导出:

fast->2->4->6->3->5

slow->1->2->3->4->5

当慢指针走到5时, 快慢指针相遇,则这个链表是环形链表

下面我们就使用代码来实现验证是否为有环的单链表

代码实现,完整代码在最下面

/**

* 判断链表是否有环

* @param $head

* @return bool

*/

public function isCycleLinkedList($head)

{

$fast = $head;

$slow = $head;

while ($fast !== null && $fast->next !== null) {

$fast = $fast->next->next;

$slow = $slow->next;

if ($fast === $slow) {

return true;

}

}

return false;

}

2. 如果有环, 找到环的入口

分析

由上题可知,按照快指针每次走2步,慢指针每次走1步的方式,发现快指针和慢指针重合,确定了单向链表有环路了。接下来,让快指针回到链表的头部,重新走,每次步长不是走2了,而是走1,那么当快指针和慢指针再次相遇的时候,就是环路的入口了。

代码实现

/**

* 判断链表是否有环, 并找到环的入口

* @param $head

* @return bool

*/

public function findLoopEntrance($head)

{

$fast = $head;

$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) {

return false;

}

$fast = $head;

while ($fast !== $slow) {

$fast = $fast->next;

$slow = $slow->next;

}

return $fast->data;

}

3. 判断两个单链表是否相交

这里我们就不考虑链表有环的问题了(其实是我不想去研究了,下次有时间了再画图补上)

假设两个单链表都没有环,如果他们相交, 则他们的尾指针一定是相同的,我们只要比较两个链表的尾结点即可,如下图:

120b064466abc8b1ede240a628e549e1.png

代码实现

/**

* 判断两个链表是否相交

* @param $l1

* @param $l2

* @return bool

*/

public function isIntersect($l1, $l2)

{

if ($l1 == null || $l2 == null) {

return false;

}

while ($l1->next !== null) {

$l1 = $l1->next;

}

while ($l2->next !== null) {

$l2 = $l2->next;

}

return $l1 === $l2;

}

假如链表有环,判断是否相交

。。。。

完整代码

/**

* Created by PhpStorm.

* Author: Xu shantong

* Date: 19-8-10

* Time: 下午3:09

*/

class Node {

/**

* @var mixed data

*/

public $data;

/**

* @var self $next

*/

public $next = null;

public function __construct($data, $next = null)

{

$this->data = $data;

$this->next = $next;

}

}

class IsCycleSingleLinkedList {

/**

* 判断链表是否有环

* @param $head

* @return bool

*/

public function isCycleLinkedList($head)

{

$fast = $head;

$slow = $head;

while ($fast !== null && $fast->next !== null) {

$fast = $fast->next->next;

$slow = $slow->next;

if ($fast === $slow) {

return true;

}

}

return false;

}

/**

* 判断链表是否有环, 并找到环的入口

* @param $head

* @return bool

*/

public function findLoopEntrance($head)

{

$fast = $head;

$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) {

return false;

}

$fast = $head;

while ($fast !== $slow) {

$fast = $fast->next;

$slow = $slow->next;

}

return $fast->data;

}

/**

* 判断两个链表是否相交

* @param $l1

* @param $l2

* @return bool

*/

public function isIntersect($l1, $l2)

{

if ($l1 == null || $l2 == null) {

return false;

}

while ($l1->next !== null) {

$l1 = $l1->next;

}

while ($l2->next !== null) {

$l2 = $l2->next;

}

return $l1 === $l2;

}

//Todo 判断有环链表是否相交

}

$node1 = new Node(1);

$node2 = new Node(2);

$node3 = new Node(3);

$node4 = new Node(4);

$node5 = new Node(5);

$node6 = new Node(6);

$node1->next = $node2;

$node2->next = $node3;

$node3->next = $node4;

$node4->next = $node5;

$node5->next = $node6;

// 第6个节点指向了第三个节点, 形成了循环

$node6->next = $node3;

$linkedList = new IsCycleSingleLinkedList();

// 判断链表是否有环

var_dump($linkedList->isCycleLinkedList($node1)); // true

// 找出环的入口

var_dump($linkedList->findLoopEntrance($node1)); // 3

// 判断两个链表是否相交

$node6->next = null; // 重置node6的指针, 使链表没有环

var_dump($linkedList->isIntersect($node3, $node1)); // true

var_dump($linkedList->isIntersect($node3, new Node(0))); // false

var_dump($linkedList->isIntersect($node3, new Node('head', $node1))); // true

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值