今天去面了一家不大不小的公司,面试题应该说不算难,唯一一道编程题是要求随机输出[1-10000]中的数字,不能重复,要考虑效率。
一看要求不能重复脑门一下闪到哈希表,于是啪啦啪啦写道建立一个10001大小的int数组做哈希表用值做下标用rand函数什么的,恩没错写的是文字不是代码。。。脑袋抽了。。。交卷后等了几分钟前台MM走过来很礼貌的说“对不起先生您的成绩离我们的要求有点大不好意思”,“有点大”这三个字如果是MM在其他场合对我说我会很高兴,但这让我有点不爽。
回来上网搜了下相关题目资料总结下,觉得虽然题目难度不大,但要答全有难度;另一个编程题我竟然用文字叙述,伪码都不是,可能也是一个重要原因,而且可能算法也不是甲方想要的;最后一题竟然是数据库,不算难的一题但自己实在很久不弄数据库了只能凭大学映象瞎编,至少对了一半。
发完牢骚开始正题。该题自己写的时候也发现如果n很大的话在随机最后几个数的时候效率会很低,但当时确实也没想到优化的方法。现在查了下有个算法是设定一个左右区间,每次将有效区间最后一个有效数字赋值到被rand的数,然后有效区间-1,相当于去除了被rand的数,于是此算法循环n次肯定完事,要是哈希表的话肯定会多循环m次。
将两种代码贴上来:
哈希:
void oneTo1W(int nummm[], int n) {
int num[n];
for (int i = 0; i < n + 1; i++)
num[i] = i;
int hashtable[n + 1];
memset(hashtable, 0, sizeof(int) * (n + 1));
int count = 0;
int random = 0;
srand((unsigned)time(NULL));
while (count < n) {
random = rand() % n + 1;
if (hashtable[random] == 0) {
hashtable[random] = random;
count++;
printf("%d ", random);
}
}
printf("\n%d\n", count);
}
左右区间替代法:
void fix_oneTo1W(int n) {
int table[n];
for (int i = 0; i < n + 1; i++)
table[i] = i;
int end = n;
srand((unsigned)time(NULL));
int ran = 0;
int count = 0;
while (end > 0) {
ran = rand() % end + 1;
// printf("ran-->%d, table[ran]-->%d-->", ran, table[ran]);
printf("%d ", table[ran]);
table[ran] = table[end];
end--;
count++;
}
printf("count-->%d\n", count);
}
最后,两种方法我都跑了一下,n等于1w、10w时时间都差不多,哈希表也没见得慢多少,100w时两种都要长时间运行(也可能我写得不对),也就是说算法这东西确实有优劣之分,但有时候实际效果却不见得有鸿沟。