当前位置: 面试刷题>> 循环数组中的环 (经典算法题500道)


完整题目描述

给定一个可能含有循环的数组(即数组中某个位置的元素指向数组中的另一个位置,形成一个环),你需要编写一个函数来检测数组中是否存在这样的环,并返回环的起始位置(即数组中第一个指向环中下一个元素的元素的位置)。如果数组中不存在环,则返回-1。

假设数组中的元素是整数,且元素的值在数组的索引范围内,即可以使用元素值作为索引来访问数组中的下一个元素。注意,数组中可能存在多个环,但只需返回第一个找到的环的起始位置即可。

示例

给定数组:[2, -1, 1, 2, 5],其中索引从0开始。

  • 元素2指向索引2(因为数组元素是2),
  • 元素-1指向自身(或理解为无效,因为索引-1越界),
  • 元素1指向索引1(形成自环),
  • 元素2(再次遇到)指向索引5(但索引5越界,实际应视为无效),
  • 元素5(假设存在,但在这个数组中不存在)如果指向数组中的某个有效位置,将形成环的一部分。

然而,根据题目描述,我们只需要关注非越界且实际能形成环的情况。在这个例子中,元素1形成了自环,所以返回1作为环的起始位置。

PHP 示例代码

function detectCycle($nums) {
    $slow = $fast = 0;
    do {
        if (!isset($nums[$fast]) || !isset($nums[$nums[$fast]])) {
            // 数组越界或无法继续追踪
            return -1;
        }
        $slow = $nums[$slow];
        $fast = $nums[$nums[$fast]];
        if ($slow == $fast) {
            break;
        }
    } while ($slow != $fast);

    if ($slow == $nums[0]) {
        // 如果快慢指针相遇在起点,说明没有环或只有一个自环的节点
        return -1;
    }

    // 找到环的起点
    $slow = 0;
    while ($slow != $fast) {
        $slow = $nums[$slow];
        $fast = $nums[$fast];
    }
    return $slow;
}

// 示例用法
$nums = [2, -1, 1, 2, 5];
echo detectCycle($nums); // 输出 1

Python 示例代码

def detectCycle(nums):
    slow, fast = 0, 0
    while True:
        if fast >= len(nums) or nums[fast] >= len(nums) or nums[nums[fast]] >= len(nums):
            return -1
        slow = nums[slow]
        fast = nums[nums[fast]]
        if slow == fast:
            break

    if slow == nums[0]:
        return -1

    slow = 0
    while slow != fast:
        slow = nums[slow]
        fast = nums[fast]
    return slow

# 示例用法
nums = [2, -1, 1, 2, 5]
print(detectCycle(nums))  # 输出 1

JavaScript 示例代码

function detectCycle(nums) {
    let slow = 0, fast = 0;
    do {
        if (fast >= nums.length || nums[fast] >= nums.length || nums[nums[fast]] >= nums.length) {
            return -1;
        }
        slow = nums[slow];
        fast = nums[nums[fast]];
        if (slow === fast) {
            break;
        }
    } while (slow !== fast);

    if (slow === nums[0]) {
        return -1;
    }

    slow = 0;
    while (slow !== fast) {
        slow = nums[slow];
        fast = nums[fast];
    }
    return slow;
}

// 示例用法
const nums = [2, -1, 1, 2, 5];
console.log(detectCycle(nums)); // 输出 1

码小课网站中有更多相关内容分享给大家学习,包括算法详解、面试技巧、编程实践等,欢迎访问。

推荐面试题