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

    寻找重复数

    描述

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

    示例 1:

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

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

    不能更改原数组(假设数组是只读的)。
    只能使用额外的 O(1) 的空间。
    时间复杂度小于 O(n2) 。
    数组中只有一个重复的数字,但它可能不止重复出现一次。

    解析

    若可以移动元素

    如果数组可以移动元素,解法很多。比如,

    先排序再比较;

    hash;

    抽屉原理

    链表有环双指针

    使用环形链表II的方法解题(142.环形链表II),使用142题的思想来解决此题的关键是要理解如何将输入的数组看作为链表。
    首先明确前提,整数的数组 nums中的数字范围是[1,n]。考虑一下两种情况:

    如果数组中没有重复的数,以数组[1,3,4,2]为例,我们将数组下标n和数nums[n]建立一个映射关系f(n),
    其映射关系n->f(n)为:
    0->1
    1->3
    2->4
    3->2
    我们从下标为0出发,根据f(n)计算出一个值,以这个值为新的下标,再用这个函数计算,以此类推,直到下标超界。这样可以产生一个类似链表一样的序列。
    0->1->3->2->4->null

    如果数组中有重复的数,以数组[1,3,4,2,2]为例,我们将数组下标n和数nums[n]建立一个映射关系f(n),
    其映射关系n->f(n)为:
    0->1
    1->3
    2->4
    3->2
    4->2
    同样的,我们从下标为0出发,根据f(n)计算出一个值,以这个值为新的下标,再用这个函数计算,以此类推产生一个类似链表一样的序列。
    0->1->3->2->4->2->4->2->……

    综上
    1.数组中有一个重复的整数 <==> 链表中存在环
    2.找到数组中的重复整数 <==> 找到链表的环入口

    至此,问题转换为142题。那么针对此题,快、慢指针该如何走呢。根据上述数组转链表的映射关系,可推出
    142题中慢指针走一步slow = slow.next ==> 本题 slow = nums[slow]
    142题中快指针走两步fast = fast.next.next ==> 本题 fast = nums[nums[fast]]

    代码

    类似抽屉原理

    public int findDuplicate(int[] nums) {
            for (int i = 0; i < nums.length; i++) {
                if (nums[i] != i + 1) {
                    if (nums[nums[i] - 1] == nums[i]) {
                        return nums[i];
                    }
                    swap(nums, i, nums[i] - 1);
                    
                     if (nums[i] != i + 1) {
                        if (nums[nums[i] - 1] == nums[i]) {
                            return nums[i];
                        }
                        swap(nums, i, nums[i] - 1);
                    }
                }
            }
            for (int i = 0; i < nums.length; i++) {
                if (nums[i] != i + 1) {
                    return nums[i];
                }
            }
            return -1;
        }
        
        public void swap(int[] nums, int a, int b) {
            if (a == b) {
                return;
            }
            nums[a] = nums[a] ^ nums[b];
            nums[b] = nums[a] ^ nums[b];
            nums[a] = nums[a] ^ nums[b];
        }

    链表有环双指针

    public int findDuplicate(int[] nums) {
            int slow = 0;
            int fast = 0;
            slow = nums[slow];
            fast = nums[nums[fast]];
            while(slow != fast){
                slow = nums[slow];
                fast = nums[nums[fast]];
            }
            int pre1 = 0;
            int pre2 = slow;
            while(pre1 != pre2){
                pre1 = nums[pre1];
                pre2 = nums[pre2];
            }
            return pre1;
        }
  • 相关阅读:
    专业的户外直播视频传输系统是如何搭建起来的?通过GB28181协议建立的户外直播方案
    Go-注释
    语言的动态性和静态性
    程序&命名-执行环境
    Go-错误栈信息
    Mongo-文档主键-ObjectId
    Mongo-关系型VS非关系型
    数据-CRUD
    Mongo基本操作
    mongo环境搭建
  • 原文地址:https://www.cnblogs.com/fanguangdexiaoyuer/p/12084487.html
Copyright © 2011-2022 走看看