【软工面试】一个文件有N个单词,每行一个,快速找出一个单词x,已知该单词出现的次数大于N/2
2016-04-20 02:44
459 查看
【软工面试】一个文件有N个单词,每行一个,快速找出一个单词x,已知该单词出现的次数大于N/2
熟悉hash运算的人可能很快能够想到应用hash映射来解决这个问题。就是建立key-value表,统计每个单词出现的次数,这样只需要遍历所有单词一遍就能够精确的统计出每个单词出现的次数。然后在遍历hash表,找到value值大于(注意不是等于)n/2的那个key值。算法的时间负责度和空间复杂度都为O(N),从不严格的意义上讲。找单词和找数字是一个道理,索性就给出了找数字的例子,因为找数字还有另外一种算法,所以应用找数字的方便进行对比。[cpp] view
plain copy
#include<stdio.h>
#include<stdlib.h>
#define HASHLEN 71
typedef struct hash_node{
int key;
int value;
struct hash_node *next;
}hash_node, *p_hash_node;
p_hash_node bin[HASHLEN] = {NULL};
unsigned int hash(int key) {
return key % HASHLEN;
}
void insert_data(int key) {
unsigned index = hash(key);
hash_node *p = bin[index];
while(p) {
if(p->key == key) {
(p->value)++;
}
p = p->next;
}
p = (hash_node*)malloc(sizeof(hash_node));
p->value = 1;
p->key = key;
p->next = bin[index];
bin[index] = p;
}
int find_num(int *a, int len) {
int i;
hash_node *p;
for(i = 0; i < len; i++) {
insert_data(a[i]);
}
i = 0;
while(i < HASHLEN) {
for(p = bin[i]; p != NULL; p = p->next) {
if(p->value >= (len / 2)) {
return p->key;
}
}
i++;
}
}
void main() {
int a[] = {0, 1, 3, 2, 1, 1, 1, 2, 3, 3, 3, 3, 3, 3};
int len = sizeof(a) / sizeof(int);
int result = find_num(a, len);
printf("%d\n", result);
}
还有第二种方法,一次在数组中取出两个数字,比较这两个数字,对他们进行操作。因为我们不知道数组中哪个数字出现的次数大于数组元素个数的一半,所以取出的这两个数字有三种情况:1,两个数字都不是要找的数字x,但是两个数字不相等,或者两个数字相等;2,两个数字一个是要找的元素,一个不是要找的元素;3, 两个数字都是要找的元素。同时,还要设定一个记录要寻找数的候选元素candidate和元素出现的次数times。我们假设数组的第一个元素为我们要找的数字,然后循环遍历数组。取数组的第二个元素,如果此元素和candidate相等,那么times++,如果不相等times--,然后把第二个数假设为candidate。有人也许会问到,如果数组中某一个元素出现很多次,但是没有达到数组的一半,怎么办呢,放心,这样的数字肯定能找到和它出现次数对等个数的数字和它不同,最终times--为0。
[cpp] view
plain copy
#include<iostream>
using namespace std;
int get_num(int *a, int len) {
int result;
int times;
int i;
if(a == NULL || len <= 0) {
return 0;
}
result = a[0];
times = 1;
for(i = 1; i < len; i++) {
if(a[i] == result) {
times++;
} else {
times--;
}
if(times == 0) {
times =1;
result = a[i];
}
}
times = 0;
for(i = 0; i < len; i++) {
if(a[i] == result) {
times++;
}
}
if(times * 2 > len) {
return result;
} else {
return 0;
}
}
void main() {
int a[] = {1, 1, 1, 1, 2, 2, 2};
int len = sizeof(a) / sizeof(int);
int result = get_num(a, len);
cout << result << endl;
}
可以自己验证次程序的正确性,但是此问题只能解决大于一半的情况。
如果想对单词统计,还有一种方法就是用trie树。花费的时间和空间大约是O(n * le),O(n), le为单词的平均长度。
相关文章推荐
- 有些工具程序员不用也要掌握(想到就写,不定期更新)
- 12 年程序员职业生涯得到的 12 个经验教训
- 【PHP】 foreach循环中变量引用的一道面试题
- 程序员你为什么迷茫?
- 生活不只有诗和远方,还有傻逼上司!
- Java面试
- 我真的稀里糊涂混成了游戏骑引擎是程序员(中间加字为避免被搜索到)
- 程序员如何在互联网的今天赚钱快速
- 程序员如何在互联网赚钱快速
- 腾讯PHP面试必备知识
- Java精度类型转换面试题
- 机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理)
- ava 面试题:编译时与运行时
- Java 面试题:编译时与运行时
- 教师面试详细流程
- SharePoint 轻量化应用之HR招聘系统之初试结果通知及复试面试通知表单
- 程序员编码大赛第三届编码大赛第三题
- Java继承、多态面试题
- 微软面试100题 - 53
- 程序员到底是一个什么职业?