面试题三:数组中重复的数字

写在前面

c++的确是需要一直学习一直积累的编程语言!

1、数组初始化列表中的元素个数小于指定的数组长度时,不足的元素补以默认值。
int a[5] = { 0 };    // 全部初始化为0,等价于 int a[5] = {0,0,0,0,0}
int a[5] = {1};  //第一个元素被赋值为1,其他元素被赋值为0,等价于int a[5] = {1,0,0,0,0}
string a[5] = {"have","fun"};  //第一个元素被赋值为“have”,第二个元素被赋值为“fun”,其他元素被赋值为“”,等价于 string a[5] = {"have","fun","","",""}
2、不能对数组赋值,只能对数组元素初始化或赋值。
int a[3];
a = {10,16,8};  //将会报错:   error: assigning to an array from an initializer list
3、当数组作为函数的形参进行传递时,数组就自动退化为同类型的指针。
4、当字符数组表示字符时,若使用sizeof函数,需要将“\0”也计算进去。

说sizeof是函数不太准确,因为sizeof可以不加括号()。需要注意的是无论string里放多长的字符串,它的sizeof()都是固定的,字符串所占的空间是从堆中动态分配的,与sizeof()无关。也就是说sizeof(string)和字符串的长度是无关的,在一个系统中所有的sizeof(string)是一个固定值,这个和编译器相关(经测试,在codeblock中sizeof(string)的固定大小是24个字节),string字符串是存储在堆上,这个属于动态分配的空间,对于别的整形浮点型数据类型则没有这个问题。

题目一:

在一个长度为n的数组中存放的数字都在0~n-1的范围内。数组中某些数字是重复的,但是不知道具体哪些数字重复了,也不知道重复了几次,请找出数组中任意一个重复的数字。比如说输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出的数字为2或者3。

思路一:把数组中的所有元素从小到大排序。以此扫描排序后的数组,很容易就能找出重复的数字了。排序一个长度为n的数组的时间复杂度为O(nlogn),不需要额外的空间。
//c++实现
#include <iostream>
#include "stdio.h"
#include<cstring>
using namespace std;
int main()
{

    int arr[7] = {2,3,1,0,2,5,3};
    int length = sizeof(arr)/sizeof(arr[0]);
    int temp;
    //选择排序
    for(int i = 0;i < length-1;i++){
        for(int j=i+1;j<length;j++){
            if(arr[i]>arr[j]){
                temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
    //找出所有的重复的数字并输出
    for(int i = 0;i<length-1;i++){
        if(arr[i]==arr[i+1]){
            printf("%d ",arr[i]);
        }
    }
    return 0;
}
思路二:额外定义一个哈希表,从头到尾遍历原数组。若元素不在哈希表中则添加并从原数组中移除;若在哈希表中则说明找到了重复的数字。若只需找一个重复的元素可省去在原数组中移除这一步操作,立即结束程序返回结果;若需要找到所有的重复数字,返回最后的原数组即可。此时遍历数组的时间复杂度为O(n),额外申请的数组的空间复杂度O(n),由此可见,这个方法是以空间换时间!

水平有限,正在重拾c++,就只用Python随便写了下,将就着看吧。

//python实现
def find(arr):
    return set([arr[x] for x in range(len(arr)-1) if arr[x]  in arr[x+1:]])
print find([2,3,1,0,5,2,3])
思路三:从头到尾扫描数组,当扫描到下标为i的数字m时,判断下标i与下标i所对应的数字m是否相等,若相等继续扫描下一个元素;判断下标为i的数字即m与下标为m的数字即n是否相等,若相等则说明找到了重复的数字,若不相等就把下标为i的数字m与下标为m的数字n交换位置,继续判断新一轮小标为i的数字n是否与下标i相等。。。如此进行下去,直到找到重复的数字为止。

此法我个人认为对于这道特定的题目来说很有效,但是并不是所有数组的元素都是小于其长度的数字,若有数字大小超过其长度程序就会崩溃,所以没有很好地扩展性。

#include <iostream>
#include "stdio.h"
#include<cstring>
using namespace std;
int main()
{
    int arr[7] = {2,3,1,0,2,5,3};
    int length = sizeof(arr)/sizeof(arr[0]);
    int temp;
    for(int i=0;i<length;i++){
        while(arr[i]!=i){                //如果下标与下标所对应的数字不相等,就一直交换比较。
            if(arr[i]!=arr[arr[i]]){     //下标为i的数字即m与下标为m的数字即n不相等,则把下标为i的数字m与下标为m的数字n交换位置
                temp = arr[arr[i]];
                arr[arr[i]]=arr[i];
                arr[i] = temp;
            }
            else{
                printf("%d ",arr[i]);
                break;
            }
        }
    }
}

题目二:

在一个长度为n的数组中存放的数字都在1~n的范围内。数组中某些数字是重复的,所以数组中至少存在一个数字是重复的,请找出数组中任意一个重复的数字,但不能修改输入的数组。比如说输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出的数字为2或者3。也就是说在题目一的基础上增加了一个条件:不能修改数组!!!

思路一:由于不能修改原数组,所以很容易想到的是定义一个长度为n+1的数组,从头到尾遍历原来数组中的数字并判断辅助数组中下标为m的位置上的数字是否为0,若不是则把该数字m存放到这个位置上,若不是为0,则找到了重复的数字。

这个方法呢也是对这道特定的题目有效,虽说时间复杂度为O(n),但是也有O(n)的空间复杂度。而且如果换一个存放较大数字但自身长度很小的数组,该方法就失效了。虽说如此还是用c++实现一下。

#include <iostream>
#include "stdio.h"
#include<cstring>
using namespace std;
int main()
{
    int arr[7] = {2,3,1,0,2,5,3};
    int length = sizeof(arr)/sizeof(arr[0]);
    int help[length+1] = {0};  //数组初始化列表中的元素个数小于指定的数组长度时,不足的元素补以默认值。辅助数组的类型为整型,所以自动补0。
    for(int i=0;i<length;i++){
        if(help[arr[i]]==0){
            help[arr[i]] = arr[i];
        }
        else{
            printf("%d ",arr[i]);
        }
    }
}
思路二:利用二分查找的算法思想,加一个统计区间内数字数目的步骤。把1-n的数字从中间的数字m分为两部分,前面一半为1-m,后面一半为m+1-n。如果1-m的数字的数目超过m,那么这一半的区间里面一定包含重复的数字,否则重复的数字在另一半区间内。继续把重复数字所在的区间一分为二,一样的方法判断、分割,直到找到重复的数字。
#include <iostream>
#include "stdio.h"
#include<cstring>
using namespace std;
int countRange(int* arr,int length,int star,int middle){
    if((sizeof(arr)/sizeof(arr[0]))==0){
        return 0;
    }
    int countsOfnumbers = 0;
    for(int i=0;i<length;i++){
        if(arr[i] >= star && arr[i]<=middle){
            countsOfnumbers += 1;
        }
    return countsOfnumbers;
    }
}
int main(){
    int arr[] = {2,3,1,0,2,5,3,3};
    int length = sizeof(arr)/sizeof(arr[0]);
    int star = 1;
    int tail = length-1;
    while(tail>=star){
        int middle = ((tail-star)>>1)+star;
        int countsOfnumbers = countRange(arr,length,star,middle);
        if(tail==star){
            if(countsOfnumbers>1){
                printf("%d ",star);
            }
            else{
                break;
            }
        }
        if(countsOfnumbers>(middle-star+1)){
            tail = middle;
        }
        else{
            star = middle + 1;
        }
    }
}

这个思路存在同样的问题就不累赘了,只适合这道题。

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

推荐阅读更多精彩内容