面试题3:找到数组中重复的数字

题目1:在一个长度为N的数组里,所有数字都在[0, N-1]的范围内。数组中某些数字是重复的,但是不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组的任意一个重复的数字。

解析:在这道题的背景下,如果把数字放到他的下标对应的位置,也就是把一个数组还原成一个递增数列,只不过每一个下标对应的数字就是下标本身的话,如果这个数组里面没有重复数字,那么还原可以完美的完成。但是由于数组内有重复数字,那么在还原的过程中,就会发现当需要把它放在合适的位置的时候,这个位置上已经有一个相同的数字了。例如 {0,1,2,2,4,5,6},下标为 3 的 2 应该放在下标为 2 的位置上,但是这个地方已经有一个 2 了。遇到这种情况,我们就立即可以返回这个数字。

使用这个思路,我们就可以写出算法了。只要当前位置上的数字和下标不相等,那就看看这个数字应该去的地方有没有同样的数字。如果发现那个地方的数字和下标是相同的,那就说明这个地方的数字是重复的,就可以返回了。如果那边的也不对的话,就把当前位置上的数字放到它应该的位置,把那个位置上的数字交换过来。然后继续比较当前位置上的数字和下标,直到当前位置上的数字和下标相等。接着对下一个位置进行同样的处理。如果每一位都是合适的,那就说明这个数组没有重复数字。

上面的算法是没有问题的,但是你可能有疑问:如果这个位置永远都换不来那个合适的数字呢?例如,{1,3,2,4,3} 没有 0 这个数字,那么怎么办呢?答案是不影响。检查第 0 位的时候,会把第 0 位的 1 和第 1 位的 3 互换。这个时候第 1 位就是 1,没毛病。接着会把第 0 位的 3 和第 3 位的 4 互换,这个时候第 3 位也是 3,没毛病。接着会把第 0 位的 4 和第 4 位的 3 互换,发现第 3 位已经是 3 了,此时返回 3。看到没有?即便换不到该有的数字,在交换的过程中也是可以找到重复的数字的。

答案:

// 时间复杂度 O(N),空间复杂度 O(1)
int findDuplicate(int array[], int length)
{
    if (nullptr == array || length <= 0)
        return -1;

    for (int i=0; i<length; ++i)
    {
        if (array[i]<0 || array[i]>length-1)
            return -1;
    }

    for (int i=0; i<length; ++i)
    {
        while (array[i] != i)
        {
            if (array[i] == array[array[i]])
            {
                return array[i];
            }
            else
            {
                int temp = array[i];
                array[i] = array[array[i]];
                array[temp] = temp;
            }
        }
    }

    return -1;
}


题目2:不修改数组的情况下找出重复的数字。在一个长度为N+1的数组里,所有的数字都在[1,N]的范围内。请找出数组中任意一个重复的数字,但不能修改输入的数组。

解析:上面的那个算法会修改原有的数组。如果要求不修改原有数组,也不能使用 O(n) 的空间来复制一份,可以牺牲一点时间复杂度,那就用下面这个算法。

首先我们考虑一个事实:如果统计数组里面的数字,在区间 [1,N] 的范围内如果出现超过了N个数,那就说明一定至少有一个数字重复了。就像一年有 365 天 (不考虑平闰年),那么 366 个人中一定至少有两个人的生日重复了。

我们可以使用这个方法来二分的统计数字的出现个数。题目说所有的数字都在 [1,N] 的范围内,那么我就统计 [1,N/2] 和 [N/2+1,N] 的数字出现次数,哪一个次数超过 N/2,哪一个就一定有重复的数字。接下来在重复的那个区间内继续二分统计,直到区间退化为一个数字,而且这个数字出现的次数大于1,那么就找到了这个数字。每统计一次出现次数会占用 O(N) 的时间。二分的统计最多有 log(N) 次统计。所以时间复杂度为 O(NlogN)。

举个例子。{1,2,3,3,4,5,6,7},长度为 8,每个数字都在 [1,7] 的范围内。先统计 [1,3] 的,有四次,[4,7] 的,也有四次。那么继续统计 [1,3]。1 出现了一次,[2,3] 出现了三次。继续统计 [2,3]。2 出现了一次,3 出现了两次,BOOM,返回 3。

答案:

//时间复杂度为 O(NlogN),空间复杂度为 O(1)
int count(const int array[], int length, int beg, int end)
{
    if (nullptr==array || length<=0)
        return -1;

    int cnt = 0;
    for (int i=0; i<length; ++i)
    {
        if (array[i]>=beg && array[i]<=end)
            ++cnt;
    }
    return cnt;
}

int findDuplicate(const int array[], int length)
{
    if (nullptr==array || length<=0)
        return -1;
    for (int i=0; i<length; ++i)
    {
        if (array[i]<1 || array[i]>length)
        {
            return -1;
        }
    }

    int beg = 1, end = length-1;
    while (beg<=end)
    {
        int mid = ((end-beg)>>1) + beg;
        int cnt = count(array, length, beg, mid);
        if (beg==end)
        {
            if (cnt>1) return beg;
            else return -1;
        }

        if (cnt>(mid-beg+1)) end = mid;
        else beg = mid+1;
    }

    return -1;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • 描述: 在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道有几个...
    要记录的Ivan阅读 223评论 0 0
  • 哭声,生命降临。你,从此又多了一个 身份,我的奶奶。 你说,一岁的时候就和你睡在一起了。 柔嫩的小...
    没名字了是吧阅读 331评论 0 1
  • 打开电视 随意调电视频道 突然间换到了 央视的《朗读者》的节目 还好节目还未开始 节目开始 那个我们熟悉的央...
    Joe_太君阅读 245评论 0 1
  • 最近广州阴雨连绵,斩不断的愁绪,硬是要人的情绪也一带感染。我最不喜的,是每逢这个时候,走路就得小心翼翼,生怕一不小...
    pinnocchio阅读 201评论 0 0