一道面试题想到的

        两道题目,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的整数倍,那么各位取余就得到了只出现一次的数。方法连接如下:

 新方法

原文地址:https://www.cnblogs.com/xiaoyi115/p/3621768.html