一道面试题想到的
两道题目,1、有一堆的数,其中所以的数都出现了两次,只有一个出现了一次,找出那个只出现一次的数。
2、有一堆的数,其中所以的数都出现了三次,只有一个出现了一次,找出那个只出现一次的数。
对于这种题目,我们可能首先想到是排序。当然,排序可以解决问题,但是排序的复杂度实在是太高了,至少也得O(nlogn)吧。
那么有没有什么方式可以使得其复杂度下降呢?
对于第一道题,我们可能会想到很多种方式,最简单的就是异或运算了,最终得到的结果肯定是只出现一次的那个数。
那么对于第二道题,我们应该怎么解呢?我想了很久,好像只能通过排序来解。因为似乎第一道题的方法都不行。后来我想到,也许可以建立哈希表,同时保留出现的次数,那么他的复杂度就是O(n).相比O(nlogn)方式快不少吧。
我这里哈希表冲突处理方式是链接法:
下面是数据结构的定义
1 #define Count 100
2 typedef int ElemType;
3 typedef int Times;
4 using namespace std;
5 struct Elem{
6 ElemType data;
7 Times time;
8 };
9 struct HashTable{
10 Elem elem; //元素信息
11 int len; //长度
12 HashTable *next; //冲突处理
13 };
14 typedef HashTable HT;
15 HT ht[Count];
下面是主要函数方法:
1 Elem& createElem(ElemType data,Elem &x);//生成元素信息
2 HT* createHTNode(Elem x);//生成一个冲突处理节点
3 int pushHash(ElemType data);//增加一个元素到哈希表中
4 int popHash(ElemType data);//查找一个元素,并返回出现的次数
5 void InitHash();//初始化哈希函数
1 //生成元素信息
2 Elem& createElem(ElemType data,Elem &x){
3 x.data=data;
4 x.time=1;
5 return x;
6 }
7 //冲突后生成节点
8 HT* createHTNode(Elem x){
9 HT* h=(HT*)malloc(sizeof(HT));
10 (*h).elem=x;
11 (*h).next=NULL;
12 return h;
13 }
1 //初始化哈希表
2 void InitHash(){
3 for(int i=0;i<Count;i++){
4 ht[i].len=0;
5 ht[i].next=NULL;
6 }
7 }
8 //把数字不断增加进哈希表中,代码感觉很累赘,希望高手指点下。
9 int pushHash(ElemType data){
10 int k=data%Count;
11 Elem x;
12 createElem(data,x);
13 //长度为1直接加入
14 if(ht[k].len==0){
15 ht[k].elem=x;
16 ht[k].len++;
17 return 1;
18 }
19 //是否是第一个节点,若是直接增加次数
20 if(ht[k].elem.data==data){
21 ht[k].elem.time++;
22 return 1;
23 }
24 HT *point=createHTNode(x);
25 //判断是否没有next节点
26 if(ht[k].len==1){
27 ht[k].next=point;
28 ht[k].len++;
29 return 1;
30 }
31 HT *p=ht[k].next;
32 while((*p).next!=NULL){
33 if((*p).elem.data==data){
34 (*p).elem.time++;
35 return 1;
36 }else
37 p=(*p).next;
38 }
39 if((*p).elem.data==data)
40 (*p).elem.time++;
41 else{
42 (*p).next=point;
43 ht[k].len++;
44 }
45 return 0;
46 }
1 //返回出现的次数
2 int popHash(ElemType data){
3 int k=data%Count;
4 if(ht[k].len==0)
5 return 0;
6 if(ht[k].elem.data==data)
7 return ht[k].elem.time;
8 HT* p=ht[k].next;
9 while(p!=NULL)
10 if((*p).elem.data==data)
11 return (*p).elem.time;
12 else
13 p=(*p).next;
14 return 0;
15 }
感觉代码还是有些累赘,希望后面自己再改进。
留言中有位仁兄提到了别人的一种方法,觉得非常好。主要是利用出现三次的话,各个位肯定是3的整数倍,那么各位取余就得到了只出现一次的数。方法连接如下: