AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 14. Go题解 不修改数组找出重复的数字    原题链接    简单

作者: 作者的头像   chen-zhe ,  2020-03-06 14:45:58 ,  所有人可见 ,  阅读 1589


2


1

题目描述

给定一个长度为 $n+1$ 的数组nums,数组中所有的数均在 $1∼n$ 的范围内,其中 $n≥1$。

请找出数组中任意一个重复的数,但不能修改输入的数组。

样例

给定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。

返回 2 或 3。

算法

(分治,抽屉原理) $O(nlogn)$

这道题目主要应用了抽屉原理和分治的思想。

抽屉原理:n+1 个苹果放在 n 个抽屉里,那么至少有一个抽屉中会放两个苹果。

用在这个题目中就是,一共有 n+1 个数,每个数的取值范围是1到n,所以至少会有一个数出现两次。

然后我们采用分治的思想,将每个数的取值的区间[1, n]划分成[1, n/2]和[n/2+1, n]两个子区间,然后分别统计两个区间中数的个数。
注意这里的区间是指 数的取值范围,而不是 数组下标。

划分之后,左右两个区间里一定至少存在一个区间,区间中数的个数大于区间长度。
这个可以用反证法来说明:如果两个区间中数的个数都小于等于区间长度,那么整个区间中数的个数就小于等于n,和有n+1个数矛盾。

因此我们可以把问题划归到左右两个子区间中的一个,而且由于区间中数的个数大于区间长度,根据抽屉原理,在这个子区间中一定存在某个数出现了两次。

依次类推,每次我们可以把区间长度缩小一半,直到区间长度为1时,我们就找到了答案。

复杂度分析

  1. 时间复杂度:每次会将区间长度缩小一半,一共会缩小 $O(logn)$ 次。每次统计两个子区间中的数时需要遍历整个数组,时间复杂度是 $O(n)$。所以总时间复杂度是 $O(nlogn)$。
  2. 空间复杂度:代码中没有用到额外的数组,所以额外的空间复杂度是 $O(1)$。

参考文献

yxc大神的题解

Go 代码

func duplicateInArray(nums []int) int {
    l,r:=1,len(nums)-1
    for l<r{
        mid:=(l+r)>>1
        s:=0
        for _,x:=range nums{
            if x>=l&&x<=mid{
                s++
            }
        }
        if s>mid-l+1{
            r=mid
        }else{
            l=mid+1
        }
    }
    return r
}

1 评论


用户头像
JYellow   2020-05-04 19:26         踩      回复

还是Go的代码看着亲切, yxc大神的代码我看不太懂....


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息