[LeetCode]287. Find the Duplicate Number 图解Floyd判圈(龟兔赛跑)算法

题目描述

Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive.

There is only one repeated number in nums, return this repeated number.

You must solve the problem without modifying the array nums and uses only constant extra space.

Example 1:

Input: nums = [1,3,4,2,2]
Output: 2

Example 2:

Input: nums = [3,1,3,4,2]
Output: 3

Example 3:

Input: nums = [1,1]
Output: 1

Example 4:

Input: nums = [1,1,2]
Output: 1

Constraints:

  • 1 <= n <= 105
  • nums.length == n + 1
  • 1 <= nums[i] <= n
  • All the integers in nums appear only once except for precisely one integer which appears two or more times.

解法:快慢指针(c++版)

 1 class Solution {
 2 public:
 3     int findDuplicate(vector<int>& nums) {
 4         int fast = 0, slow = 0;
 5         while(true) {
 6             slow = nums[slow];
 7             fast = nums[nums[fast]];
 8             if(slow == fast) break;
 9         }
10         fast = 0;
11         while(true) {
12             slow = nums[slow];
13             fast = nums[fast];
14             if(slow == fast) break;
15         }
16         return slow;
17     }
18 };

先上代码,这个精简的解法相信大家在各种解析评论里已经见烂了。其核心是使用Floyd判圈算法(Floyd Cycle Detection Algorithm),又称龟兔赛跑算法(Tortoise and Hare Algorithm)来找到环的入口,即那个重复的数。网友 在线疯狂 的 参考解法 里的解析已经比较详细了,但是理解起来还是稍微有点难度的(起码对于我是这样TAT...看了好几遍才看懂)。下面给出一个带图的详细解析作为补充,希望能让大家更好理解Floyd判圈算法背后的逻辑原理以及这道题目是如何和该算法挂钩的。不得不感慨一下这道题的设计,真是无巧不成题呀!

题干分析

题目告诉我们,数组中的元素范围是 [1, n] ,在该范围内如果没有重复,那应当有 n 个元素;但是给定的数组却有 n+1 个元素,这很明显说明在这些数中有且仅有一个数是重复的,即数组中的元素是由1到n范围内的所有正整数和重复的那个数构成的。对于一个有 n+1 个元素的数组,它的下标取值范围是 [0, n],等等!这里是不是觉得有点意思:给定数组下标范围是[0, n],数组中元素取值范围是[1, n] 。什么意思呢?我们可以巧妙地运用下标和元素的值来访问数组。具体来说,我们可以把数组的每一项看作是一个“任意门”,把当前位置的元素值当作是下一个要传送到的位置的下标值,比如 nums[3] = 4 就表示我们将要被传送到下标为4的位置,然后再根据 nums[4] 中存储的值决定下一次被传送的位置;进一步思考,倘若数组中有重复的元素,假设为k,那么将会有两个“任意门”可以到达 nums[k] ;把这两扇“任意门”合并成一个,是不是就能形成一个环路了呢?nums[k] 就是这个环路的入口。而对于 nums[0] 这个位置,因为数组中的元素都是 >= 1的数,因此没有任何一个“任意门”可以到达 nums[0] 位置,也就是说 nums[0] 到 nums[k] 之间是一个直线型链条,nums[0] 位置就是这个链条的起点。

把数组变成环

话不多说直接举个栗子

上一篇:mysql慢日志详解和分析


下一篇:python实现删除链表倒数第n个节点