【Leetcode】287. Find the Duplicate Number

题目地址:

https://leetcode.com/problems/find-the-duplicate-number/

有个长为 n + 1 n+1 n+1的数组,设为 ( x 0 , x 1 , x 2 , . . . , x n ) (x_0,x_1,x_2,...,x_n) (x0,x1,x2,...,xn)其中的数字都属于 1 ∼ n 1\sim n 1n,已知只有一个数字发生了重复,问那个数字是几。

思路是静态链表。想象一个静态链表,它的值是 ( 0 , 1 , 2 , 3 , . . . , n ) (0,1,2,3,...,n) (0,1,2,3,...,n),对应的next数组是 ( x 0 , x 1 , x 2 , . . . , x n ) (x_0,x_1,x_2,...,x_n) (x0,x1,x2,...,xn),由于所有的 x i x_i xi都在 1 1 1 n n n之间,所以这个next数组是定义合理的。假设对于某两个不同的数 i i i j j j,有 x i = x j x_i=x_j xi=xj,那么这个静态链表就存在环,所以直接用链表求环的方法找出环的入口即可。链表求环的算法可以参照https://blog.csdn.net/qq_46105170/article/details/104015181。详细的解释与证明在代码后面。代码如下:

class Solution {
 public:
  int findDuplicate(vector<int>& a) {
    int slow = 0, fast = 0;
    do {
      slow = a[slow];
      fast = a[a[fast]];
    } while (slow != fast);
    int cur = 0;
    while (cur != slow) cur = a[cur], slow = a[slow];
    return cur;
  }
};

时间复杂度 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)

算法正确性证明:
沿袭前面的符号,设一个静态链表,它的值是 ( 0 , 1 , 2 , 3 , . . . , n ) (0,1,2,3,...,n) (0,1,2,3,...,n),对应的next数组是 ( x 0 , x 1 , x 2 , . . . , x n ) (x_0,x_1,x_2,...,x_n) (x0,x1,x2,...,xn) 0 0 0是这个链表的第一个节点。其实这个next数组就指的是nums这个数组。由于所有的 x i x_i xi都在 1 1 1 n n n之间,这个next数组是定义合理的。不妨设值 i i i的next为 f ( i ) f(i) f(i),也就是 f ( i ) = x i f(i)=x_i f(i)=xi。那么这个链表链式表示实际上就是: 0 → x 0 → f ( x 0 ) → f 2 ( x 0 ) → . . . 0\rightarrow x_0 \rightarrow f(x_0)\rightarrow f^2(x_0)\rightarrow ... 0x0f(x0)f2(x0)...首先,对于任意的 k ≥ 0 k\ge0 k0,都有 f k ( x 0 ) ! = 0 f^k(x_0)!=0 fk(x0)!=0(定义 f 0 ( x 0 ) = x 0 f^0(x_0)=x_0 f0(x0)=x0),这是因为 x 0 x_0 x0 x n x_n xn都属于 1 ∼ n 1\sim n 1n,而这个序列的取值只能取有限个不同值,所以一定存在重复,由抽屉原理,存在某两个不同的数 i i i j j j,满足 1 ≤ i < j ≤ n + 1 1\le i<j\le n+1 1i<jn+1,并且 f i ( x 0 ) = f j ( x 0 ) ≠ 0 f^i(x_0)=f^j(x_0)\ne0 fi(x0)=fj(x0)=0。不妨设 i i i j j j是最小的一对这样的数。所以有 f ( f i − 1 ( x 0 ) ) = f ( f j − 1 ( x 0 ) ) f(f^{i-1}(x_0))=f(f^{j-1}(x_0)) f(fi1(x0))=f(fj1(x0))并且 f i − 1 ( x 0 ) ≠ f j − 1 ( x 0 ) f^{i-1}(x_0)\ne f^{j-1}(x_0) fi1(x0)=fj1(x0)也就是说, f i − 1 ( x 0 ) f^{i-1}(x_0) fi1(x0) f j − 1 ( x 0 ) f^{j-1}(x_0) fj1(x0)这两个node对应的next是同一个值,这“同一个值”就是要找的那个重复的数。用链表的语言来说,就是环的入口。所以只需要找这个静态链表环的入口就行了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值