【技巧】Leetcode 287. 寻找重复数【中等】

文章介绍了如何通过将数组转化为链表并利用数学函数思想找到唯一重复元素的方法。借助LeetCode142题的环形链表II思想,Java代码展示了如何在不修改数组且常量级空间复杂度下找出重复数,时间复杂度为O(n)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

寻找重复数

给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。

假设 nums 只有 一个重复的整数 ,返回 这个重复的数

你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。

示例1:

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

解题思路

如何将输入的数组看作为链表?如果能转化成链表,则可以使用 Leetcode 142. 环形链表 II的思想,找到环的起点即可。

可以使用数学函数思想,定义一个f(x)函数

输入为:

  • [1,3,4,2]
    则有函数的映射关系 x->f(x)为:
  • 0->1
  • 1->3
  • 2->4
  • 3->2
  • 我们从下标为 0 出发,根据 f(x)计算结果值为(类似高中函数定义,令发y=f(x),有x值和y值对应,这里就是x从0开始,数组元素作为y和x组成对应关系,即函数):
  • 0->1->3->2->4->null

那如果数组有重复元素,假设数组为:

  • [1,3,4,2,2]

对应f(x)函数一定会产生多对一的映射(即有2个即以上的x对应一个y值)
对应到链表上,则如下:
其映射关系 x->f(x) 为:

  • 0->1
  • 1->3
  • 2->4
  • 3->2
  • 4->2
    同样的,我们从下标为 x= 0 出发,根据 f(x) 计算出一个值,以这个值为新的下标,再用这个函数计算,以此类推产生一个类似链表一样的序列。
    0->1->3->2->4->2->4->2->……
    在这里插入图片描述
    可以发现,环的起点4即为重复元素。使用Leetcode 142. 环形链表 II思想即可解题。

java实现

public class FindDuplicate {
    public int findDuplicate(int[] nums) {
        int slow = nums[0];
        int fast = nums[0];

        // Phase 1: 检测是否存在循环,可能在环中的某个点相遇
        //有重复元素一定存在环
        do {
            //对应f(x)的函数关系,相当于链表的slow = slow.next
            slow = nums[slow];
            //对应f(x)的函数关系 相当于链表fast = fast.next.next
            fast = nums[nums[fast]];
        } while (slow != fast);

        // Phase 2: 找到循环的入口
        //因为相遇点到环的入口的距离与数组起点到环的入口的距离相等
        //数组起点到环的入口的距离a 一个一步a+b,一个两步,
        // a+c=2(a+b) 因为相遇a=c-2b 即两步走的那个距离环的入口一定多走了a
        // 即slow再走a就能到环口,而数组起点到环的入口的距离a
        // 那另fast=nums[0],快慢每次一步一起走,相遇了则是走完了a,相遇点就是环的起点
        fast = nums[0];
        while (slow != fast) {
            slow = nums[slow];
            fast = nums[fast];
        }

        return slow;
    }

    public static void main(String[] args) {
        FindDuplicate solution = new FindDuplicate();
        //0->1->4->2->3
        //      ^     |
        //      |     |
        //      ------
        int[] nums = {1, 4, 3, 4, 2,5};
        int result = solution.findDuplicate(nums);
        System.out.println("The duplicate number is: " + result);
    }
}

时间空间复杂度

  • 时间复杂度为O(n)。
  • 空间复杂度为O(1)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值