一个简单的数组面试题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xe2vherd
V2EX    C

一个简单的数组面试题

  •  1
     
  •   xe2vherd 2018 年 8 月 17 日 5963 次点击
    这是一个创建于 2790 天前的主题,其中的信息可能已经有所发展或是发生改变。

    今天晚上面试,有一个数组的题。 一个大小为 n 的数组,数组的内容为 1~n 的任意数,这些数中有一个数出现了 1 次,其他数出现 0 次或多次,怎么在 O(n)时间复杂度,O(1)空间复杂度内找到这个出现 1 次的数? 有没有大佬来解释一下?

    41 条回复    2018-08-20 11:19:14 +08:00
    feather12315
        1
    feather12315  
       2018 年 8 月 17 日 via Android
    刚刚牛客网上面看到了类似的题目,不过有个限制:数的大小限制在 0-n-1,这题目名称为:数组中重复的数字
    xe2vherd
        2
    xe2vherd  
    OP
       2018 年 8 月 17 日
    @feather12315 方便给个链接吗
    slowman
        3
    slowman  
       2018 年 8 月 17 日
    其他数出现 0 次或多次?不是偶数次?
    qiuqiuer
        4
    qiuqiuer  
       2018 年 8 月 17 日 via Android
    每个出现了 1 次?
    benson458
        5
    benson458  
       2018 年 8 月 17 日
    如果其他数是 0 次或偶数次的话,就全部异或一遍,剩下的那个
    xe2vherd
        6
    xe2vherd  
    OP
       2018 年 8 月 17 日
    @1423 对的 不是偶数次
    dtgio
        7
    dtgio  
       2018 年 8 月 17 日 via iPhone
    用 unordered_map 记录每个数出现的次数?
    rabbbit
        8
    rabbbit  
       2018 年 8 月 17 日
    数组是有序的吗?
    crayygy
        9
    crayygy  
       2018 年 8 月 17 日 via iPhone
    异或
    ppyybb
        11
    ppyybb  
       2018 年 8 月 17 日 via iPhone   3
    这样做,从头扫描数组
    对于 a[i] = x,
    如果 i==x,那么直接下一个
    否则,和 a[x]的绝对值比较,如果不等,就进行交换。
    如果相等,就代表找到一个重复出现的数字,这时候把数字取反得到负数。
    然后继续当前位置,如果数字是 n,就记录到一个单独变量里面(额外的一个空间)。
    最后这个数组里面的唯一正数就是答案。

    时间复杂度很容易说明,每一次要不前进,要不就交换,而每次交换都会将一个数字放到原本的位置上,所以是 o ( n )
    innoink
        12
    innoink  
       2018 年 8 月 18 日 via Android
    这就是数据可以当下标用的一个地方
    xe2vherd
        13
    xe2vherd  
    OP
       2018 年 8 月 18 日 via Android
    @ppyybb 好像可以 明天试一下
    ppyybb
        14
    ppyybb  
       2018 年 8 月 18 日 via iPhone
    @zmxnv123 有些细节没写全哦,但是大概思路应该可以
    TheGonG
        15
    TheGonG  
       2018 年 8 月 18 日 via Android
    堆排序了解一下
    Mirana
        16
    Mirana  
       2018 年 8 月 18 日
    把数字 N 放在数组对应的下标上 Array[N-1]
    zheyu
        17
    zheyu  
       2018 年 8 月 18 日 via Android   1
    第一遍遍历把数字 i 放在 a[i-1]上,第二遍遍历对 a[i-1]!=i 的地方,令 a[a[i-1]]=0,第三遍遍历找到 a[i-1]==i 的值。这个 i 应该就是只出现一次的数字了
    wenzhoou
        18
    wenzhoou  
       2018 年 8 月 18 日 via Android
    简单的再开一个数组,记录每个数字出现的次数。然后再遍历一遍,找到次数为 1 的数字。
    l30n
        19
    l30n  
       2018 年 8 月 18 日 via Android   1
    利用原来数组的空间
    daozhihun
        20
    daozhihun  
       2018 年 8 月 18 日 via Android
    @wenzhoou 空间要求为 1,不能开数组
    snail1988
        21
    snail1988  
       2018 年 8 月 18 日
    @ppyybb 你这样有个前提是必须有序,否则就是 log 级别的时间复杂度
    smdbh
        22
    smdbh  
       2018 年 8 月 18 日
    @ppyybb ,1 2 2 ?
    XxxxD
        23
    XxxxD  
       2018 年 8 月 18 日
    python 里面有个 count ()的函数,for in 一遍,找出属于 1 的?
    snail1988
        24
    snail1988  
       2018 年 8 月 18 日
    利用固定偏移可以时间复杂度 O(n),空间 O(1) 下面贴一段 demo,没处理 数组 size 接近 int 极限的情况

    int unique_number(int arr[], int n) {
    for (int idx = 0; idx < n; ++idx) {
    int i = (abs(arr[idx])%n?:n)-1;
    if (arr[i] > 0) {
    arr[i] = -arr[i];
    }
    else if (arr[i] < 0) {
    arr[i] = arr[i] - n;
    }
    }
    for (int idx = 0; idx < n; ++idx) {
    if (arr[idx] < 0 && arr[idx] > -n) {
    return idx+1;
    }
    }
    return 0;
    }
    wenzhoou
        25
    wenzhoou  
       2018 年 8 月 18 日 via Android
    不能开数组那就是上面说的异或了。
    baelish
        26
    baelish  
       2018 年 8 月 18 日
    遍历第 1 次,A[A[i]] *= n
    遍历第 2 次,if(A[i] > n && A[i] < n*n) return A[i]/n
    baelish
        27
    baelish  
       2018 年 8 月 18 日
    * 换成 +
    snail1988
        28
    snail1988  
       2018 年 8 月 18 日
    sorry,少写了一等号

    int unique_number(int arr[], int n) {
    for (int idx = 0; idx < n; ++idx) {
    int i = (abs(arr[idx])%n?:n)-1;
    if (arr[i] > 0) {
    arr[i] = -arr[i];
    }
    else if (arr[i] < 0) {
    arr[i] = arr[i] - n;
    }
    }
    for (int idx = 0; idx < n; ++idx) {
    if (arr[idx] < 0 && arr[idx] >= -n) {
    return idx+1;
    }
    }
    return 0;
    }
    baelish
        29
    baelish  
       2018 年 8 月 18 日   1
    遍历第 1 次,A[A[i]] += n
    遍历第 2 次,if(A[i] > n && A[i] < 2*n) return A[i]-n

    这回就对了
    ppyybb
        30
    ppyybb  
       2018 年 8 月 18 日 via iPhone
    @snail1988 显然不用,这题我做过....
    ppyybb
        31
    ppyybb  
       2018 年 8 月 18 日 via iPhone
    @smdbh 真巧,这是我校验的第一个 case。按我的做法最后状态变成-2 1 -2,所以 1 是唯一的。
    likers
        32
    likers  
       2018 年 8 月 18 日
    @wenzhoou 其他数字是出现 0 或多次,不是偶数次,不能异或
    sikariba
        33
    sikariba  
       2018 年 8 月 18 日
    主楼跟你回复里贴的链接完全就是 2 道题啊。。
    wenzhoou
        34
    wenzhoou  
       2018 年 8 月 18 日 via Android
    @likers 你说的正确。
    thedog
        35
    thedog  
       2018 年 8 月 18 日 via Android
    异或一把
    snail1988
        36
    snail1988  
       2018 年 8 月 18 日
    @ppyybb 如果最坏情况 你相当于要把一半的元素进行交换排序
    snail1988
        37
    snail1988  
       2018 年 8 月 18 日
    @ppyybb 又想了一下,这个排序相当于桶排序,是 O(n)的 那总体复杂度确实还是 O(n)
    vandort
        38
    vandort  
       2018 年 8 月 18 日
    我有个正确却没什么意义的答案:用睡排序对数组进行排序,然后就很好找那个出现了一次的数了
    xe2vherd
        39
    xe2vherd  
    OP
       2018 年 8 月 18 日 via Android
    @所有人 LZ 已经知道正确方法了 感谢各位
    waytoexplorewhat
        41
    waytoexplorewhat  
       2018 年 8 月 20 日 via Android
    看了评论感觉很乱(楼主也太不负责了,知道答案就跑路了)。说一下自己的思路。如果可以修改原数组的内容,可以在原数组上做统计,m 这个数未出现过记 arr[m]为 0,出现 x 次值则为-x,这样可以通过一次遍历完成统计,再一次遍历找出值为-1 的那个数
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     940 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 21:07 PVG 05:07 LAX 14:07 JFK 17:07
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86