为什么在链表中查找循环时将指针增加 2,而不是 3、4、5?

2023-12-20

我看了一下question https://stackoverflow.com/questions/2663115/interview-question-how-to-detect-a-loop-in-a-linked-list已经讨论了在链表中查找循环的算法。我读过了Floyd 的环路查找算法 http://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare解决方案,在很多地方提到我们必须采用两个指针。一个指针(slower/tortoise)加1,另一个指针(faster/hare)加2。当它们相等时,我们发现循环,如果faster指针达到空,则链表中没有循环。

现在我的问题是为什么我们将更快的指针增加 2。为什么不做其他的事情呢?需要增加 2,或者我们可以将其增加 X 以获得结果。如果我们将 Faster 指针增加 2,是否有必要找到循环,或者可能存在需要增加 3、5 或 x 的情况。


从正确性的角度来看,没有理由需要使用数字 2。任何步长的选择都可以(当然,除了一个)。然而,选择大小为 2 的步长可以最大限度地提高效率。

To see this, let's take a look at why Floyd's algorithm works in the first place. The idea is to think about the sequence x0, x1, x2, ..., xn, ... of the elements of the linked list that you'll visit if you start at the beginning of the list and then keep on walking down it until you reach the end. If the list does not contain a cycle, then all these values are distinct. If it does contain a cycle, though, then this sequence will repeat endlessly.

以下是弗洛伊德算法发挥作用的定理:

The linked list contains a cycle if and only if there is a positive integer j such that for any positive integer k, xj = xjk.

Let's go prove this; it's not that hard. For the "if" case, if such a j exists, pick k = 2. Then we have that for some positive j, xj = x2j and j ≠ 2j, and so the list contains a cycle.

For the other direction, assume that the list contains a cycle of length l starting at position s. Let j be the smallest multiple of l greater than s. Then for any k, if we consider xj and xjk, since j is a multiple of the loop length, we can think of xjk as the element formed by starting at position j in the list, then taking j steps k-1 times. But each of these times you take j steps, you end up right back where you started in the list because j is a multiple of the loop length. Consequently, xj = xjk.

This proof guarantees you that if you take any constant number of steps on each iteration, you will indeed hit the slow pointer. More precisely, if you're taking k steps on each iteration, then you will eventually find the points xj and xkj and will detect the cycle. Intuitively, people tend to pick k = 2 to minimize the runtime, since you take the fewest number of steps on each iteration.

我们可以更正式地分析运行时,如下所示。如果列表不包含循环,则快速指针将在 n 步后到达列表末尾,时间复杂度为 O(n),其中 n 是列表中元素的数量。否则,当慢指针走了j步后,两个指针就会相遇。请记住,j 是 l 大于 s 的最小倍数。如果 s ≤ l,则 j = l;否则,如果 s > l,则 j 最多为 2s,因此 j 的值为 O(s + l)。由于 l 和 s 不能大于列表中的元素数量,这意味着 j = O(n)。然而,在慢速指针走了 j 步之后,对于慢速指针所采取的 j 步,快指针将采取 k 步,因此它将采取 O(kj) 步。由于 j = O(n),因此净运行时间至多为 O(nk)。请注意,这表示我们使用快速指针执行的步骤越多,算法完成所需的时间就越长(尽管只是成比例)。因此选择 k = 2 可以最大限度地减少算法的整体运行时间。

希望这可以帮助!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么在链表中查找循环时将指针增加 2,而不是 3、4、5? 的相关文章

  • 另一个生命游戏问题(无限网格)?

    我一直在玩 Conway 的生命游戏 最近发现了一些令人惊讶的快速实现 例如 Hashlife 和 Golly 在这里下载Golly http golly sourceforge net http golly sourceforge net
  • 查找top-k元素的平均时间复杂度

    考虑在一组 N 个独立且同分布的浮点值中查找前 k 个元素的任务 通过使用优先级队列 堆 我们可以对所有 N 个元素进行一次迭代 并通过以下操作维护一个 top k 集合 如果元素 x 比堆头 更差 丢弃 x 复杂度 O 1 如果元素 x
  • Python 中聚类相似字符串的算法?

    我正在编写一个脚本 该脚本当前包含多个 DNA 序列列表 每个列表都有不同数量的 DNA 序列 并且我需要根据汉明距离相似性对每个列表中的序列进行聚类 我当前的实现 目前非常粗糙 提取列表中的第一个序列并计算每个后续序列的汉明距离 如果它在
  • 查找邻接表中所有连接的节点

    我有一个 DAG 的邻接列表 我需要从所有节点中找到所有连接的节点 例如 对于下面的 DAG 1 gt 3 gt 4 2 gt 4 3 gt 2 4 gt 5 5 gt NULL 我需要这个 1 gt 2 3 4 5 2 gt 4 5 3
  • 计算排列中“反转”的数量

    设 A 为一个大小的数组N 我们称之为几个索引 i j 一个 逆 如果i lt j and A i gt A j 我需要找到一种接收大小数组的算法N 具有唯一的数字 并返回时间的倒数数O n log n 您可以使用归并排序 http en
  • 匈牙利算法 - 系统分配

    我正在一个项目中实现匈牙利算法 我设法让它工作 直到所谓的步骤 4维基百科 http en wikipedia org wiki Hungarian algorithm Matrix 5Finterpretation 我确实设法让计算机创建
  • 如果我在计算强连通分量时不使用 G 转置会怎样?

    我正在阅读算法导论 在 22 5 强连通分量中 算法 STRONGLY CONNECTED COMPONENT G 定义为 调用 DFS G 计算每个顶点 u 的完成时间 u f 计算 G 转置 调用 DFS G transpose 但在
  • 将曲线图案与图像边缘匹配

    我有一个要搜索沿其边缘的曲线的目标图像和一个包含该曲线的模板图像 我需要实现的是在目标图像中找到模板图像中的曲线的最佳匹配 并根据分数来判断是否匹配 这还包括曲线的旋转和大小调整 目标图像可以是 Canny Edge 检测器的输出 如果这能
  • 单链表的时间复杂度

    我正在研究数据结构 单链表 该网站称单链表的插入和删除时间复杂度为O 1 我错过了什么吗 网站链接 http bigocheatsheet com 我用 C 做这个 而且我只有一个root pointer 如果我想插入到最后 那么我必须一直
  • 无限循环:确定并打破无限循环

    你如何判断一个循环是无限循环并且会跳出它 有没有人有算法或者可以帮助我解决这个问题 Thanks 没有通用的算法可以确定程序是否处于无限循环中图灵完备 http en wikipedia org wiki Turing completene
  • 计算序列 1,3,8,22,60,164,448,1224... 的第 n 项? [复制]

    这个问题在这里已经有答案了 可能的重复 我想以 Order 1 或 nlogn 的顺序生成序列 1 3 8 22 60 164 的第 n 项 https stackoverflow com questions 11301992 i want
  • 准备与大数据相关的设计和架构问题的最佳方法[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 哪种算法可以解决我的婚礼餐桌问题?

    我的婚礼有 x 位客人 有 y 张桌子 有 z 个座位 客人A可以与客人B同桌 客人C不能与客人D同桌 给定所有客人之间所有连接的数据集 是否有已知的算法可以解决此类问题 我确信这种问题有一个抽象的父问题 称为 问题 x 或其他问题 或者它
  • 根据 cron 规范计算下一个计划时间

    在给定当前时间和 cron 规范的情况下 计算事件下一次运行时间的有效方法是什么 我正在寻找 每分钟循环检查是否符合规范 以外的东西 规格示例可能是 每月1日 15日15 01 每小时整点的 10 20 30 40 50 分钟 Python
  • 如何使用 C 中的 Banker's Rounding 将 double 舍入为 int

    我想编写一个函数 使用银行家的舍入方法将双精度数舍入为整数 将一半舍入为偶数 http en wikipedia org wiki Rounding Round half to even http en wikipedia org wiki
  • 高效找到圆和网格的交点

    找到由圆心和半径定义的圆与任意网格的交点的好方法是什么 An illustration of the points I am trying to find 到目前为止我想到的可能的解决方案 找到位于中心 半径之间的所有线 对于每条线计算交点
  • LRU、FIFO、随机

    当出现页面错误或缓存未命中时 我们可以使用最近最少使用 LRU 先入先出 FIFO 或随机替换算法 我想知道 哪一个提供了最好的性能 也称为未来缓存丢失 页面错误最少的可能性 架构 Coldfire 处理器 没有愚蠢的问题 这句话非常适合这
  • 聚类算法采用哪种编程结构

    我正在尝试实现以下 分裂 聚类算法 下面是该算法的简短形式 完整的描述可用here https dl dropboxusercontent com u 540963 diana pdf 从样本 x i 1 n 开始 将其视为由 n 个数据点
  • 查找预排序数组中给定值的最低索引

    嘿 我在采访中遇到了这个问题 想知道解决它的最佳方法是什么 假设给定一个已经排序的数组 并且您想要找到某个值 x 的最低索引 这是我想出的 python 伪代码 我只是想知道是否有更好的方法来实现它 def findLowestIndex
  • STL 哈希函数

    STL 是否有公开公开的可用哈希函数 我知道有一些使用哈希值的非标准实现 例如boost hash map 并且MSVC8实现了hash map hash set 等的版本 但有没有哈希函数C 98 STL 中定义的 如果不是 可靠哈希函数

随机推荐