zoukankan      html  css  js  c++  java
  • LeetCode 287. 寻找重复数

    我的LeetCode:https://leetcode-cn.com/u/ituring/

    我的LeetCode刷题源码[GitHub]:https://github.com/izhoujie/Algorithmcii

    LeetCode 287. 寻找重复数

    题目

    给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。

    示例 1:

    输入: [1,3,4,2,2]
    输出: 2
    

    示例 2:

    输入: [3,1,3,4,2]
    输出: 3
    

    说明:

    • 不能更改原数组(假设数组是只读的)。
    • 只能使用额外的 $ {color{Magenta}{Omicronleft(1 ight)}} $ 的空间。
    • 时间复杂度小于 $ {color{Magenta}{Omicronleft(n^{2} ight)}} $) 。
    • 数组中只有一个重复的数字,但它可能不止重复出现一次。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/find-the-duplicate-number
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    解题思路

    思路1-把数组看成有环的链表,寻找环的入口

    如果把链表看做是有环的链表,那么环的入口就是重复的那个数;
    根据题意,数组的值范围为[1, n],而数组的长度为n+1,所以用任意数组的值作为下标都不存在越界的问题;
    寻找环可以用快慢指针来进行,图解如下:


    图中有几个关键信息:

    • 快慢指针的起始位置:头节点;
    • 快慢指针的相遇位置:相遇点;
    • 环的入口即重复的数位置:环入口;

    步骤:

    1. 快慢指针,慢指针每次走1步,快指针每次走2步;
    2. 两指针相遇后,将快指针重置为头结点,然后两指针同步每次均移动1步直至相遇,此时的节点即为环的入口(重复的数);

    解析:
    快慢指针首次相遇的点必在环中(任意一点),假设快指针在环中转了n圈(很显然,n至少为1,不然无法相遇)再加a部分,根据运动长度,快指针是慢指针的两倍,则有:

    [2(F + a) = F + n(a + b) + a ]

    即:

    [F = (n - 1) * (a + b) + b ]

    忽略掉((n - 1) * (a + b))的部分,重复的整个环不影响分析,那么就可以得到:

    [F = b ]

    所以,在相遇后,重置其中一个指针为头结点,两个指针一个走F部分长度,一个走b部分长度,最终必会在环的入口节点相遇,也就找到了重复的数;

    算法复杂度:

    • 时间复杂度: $ {color{Magenta}{Omicronleft(n ight)}} $ 对数组进行了少量遍历
    • 空间复杂度: $ {color{Magenta}{Omicronleft(1 ight)}} $

    算法源码示例

    package leetcode;
    
    /**
     * @author ZhouJie
     * @date 2020年5月31日 下午2:58:54 
     * @Description: 287. 寻找重复数
     *
     */
    public class LeetCode_0287 {
    
    }
    
    class Solution_0287 {
    	/**
    	 * @author: ZhouJie
    	 * @date: 2020年5月31日 下午2:59:24 
    	 * @param: @param nums
    	 * @param: @return
    	 * @return: int
    	 * @Description: 1-将数组看作有环链表,使用快慢指针寻找环入口;
    	 *
    	 */
    	public int findDuplicate_1(int[] nums) {
    		int fast = 0, slow = 0;
    		while (true) {
    			fast = nums[nums[fast]];
    			slow = nums[slow];
    			// 此时找到了环内的一个同步节点,然后重置其中一个指针为头节点,开始寻找环入口
    			if (fast == slow) {
    				fast = 0;
    				while (nums[fast] != nums[slow]) {
    					fast = nums[fast];
    					slow = nums[slow];
    				}
    				return nums[fast];
    			}
    		}
    	}
    }
    
    
  • 相关阅读:
    tip6: 程序不工作就是最大的异常
    简单实用的Code Review工具
    HDU4008 Parent and son [树形DP]
    HDU4004 The Frog's Games [二分]
    HDU4006 The kth great number [堆]
    HDU4024 Dwarven Sniper’s hunting [二分]
    HDU4005 The war [树形DP]
    HDU4009 Transfer water [最小树形图]
    HDU4023 Game [贪心+博弈]
    HDU4007 Dave [杂题]
  • 原文地址:https://www.cnblogs.com/izhoujie/p/13019476.html
Copyright © 2011-2022 走看看