免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4797 | 回复: 8
打印 上一主题 下一主题

[C] 一道看似不起眼的小题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-10-17 13:27 |只看该作者 |倒序浏览
本帖最后由 zhendehaoren 于 2014-10-17 18:56 编辑

面试的时候最怕遇到“小题”

这次栽在了这样的一道题上面:
a[1000]数组, 用随机函数随机生成1000填充,不允许重复,也就是说不止1000次,复杂度最低实现

以下三个方法已经确认不是最优解(也就是说和没答一样,“小题”就是如此残酷)
1 另外存放一个二叉排序树,每次插入时遍历二叉树。

2 另外存放一个排序数组,每次插入时二分查找。

3 另外存放一个数组或bitmap,每次产生一个数字对应的下标置1,快速查看是否已存在。

经过查资料,貌似需要洗牌算法。
我的理解,洗牌算法就是将一堆数字打乱,这样的话,和这道题有什么联系?

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
2 [报告]
发表于 2014-10-17 14:15 |只看该作者
你将要求说清楚点

若“a[1000]数组, 用随机函数随机生成1000次填充”,就直接for循环啦
若再加上“不允许重复”,用 set 或 unordered_set 之类
若再加上“填充0到999,不允许重复”,看 std::random_shuffle

论坛徽章:
0
3 [报告]
发表于 2014-10-17 14:29 |只看该作者
本帖最后由 317358117 于 2014-10-17 14:37 编辑

如果是0~999打乱的话可以这样

  1. for(i = 0; i < 1000; i++) { a[i] = i; }

  2. for(i = 0; i < 999; i++) {
  3.     k = rand() % (1000-i);
  4.     swap(a[i], a[i+k]);
  5. }
复制代码
如果是值是随机的,可以随机一个数a作为起始,每次随机增量与起始相加得到b,然后再a=b,可以得到升序的随机序列

论坛徽章:
0
4 [报告]
发表于 2014-10-17 14:42 |只看该作者
多谢ls,完全看不懂,不过即使这样,复杂度也得是o(2n)

如果采用第三种方法,o(n)就行了

论坛徽章:
2
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:56:11
5 [报告]
发表于 2014-10-17 14:47 来自手机 |只看该作者
又没说数的范围。若范围是32位整数,则可以将这个区间1000等分,每个区间取个随机数填充即可,复杂度o(n)

论坛徽章:
3
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:032015年亚洲杯之中国
日期:2015-04-22 15:52:45
6 [报告]
发表于 2014-10-17 16:34 |只看该作者
zhendehaoren 发表于 2014-10-17 14:42
多谢ls,完全看不懂,不过即使这样,复杂度也得是o(2n)

如果采用第三种方法,o(n)就行了


这楼可是标准的洗牌算法哦, 先得初始化一遍, 总得先有1000张牌么不是.

另外, 题目说是"随机生成1000次填充", 如果出现重复就不满足"1000次"这个硬性需求了.
没有指明数值范围, 那灵活性太大了, 自己想办法不让它重复罢了.

感觉题目出得不好.

论坛徽章:
1
巨蟹座
日期:2014-03-18 23:44:30
7 [报告]
发表于 2014-10-19 00:22 |只看该作者
5楼 区间等分  给个赞

论坛徽章:
11
2015年迎新春徽章
日期:2015-03-04 09:55:282017金鸡报晓
日期:2017-02-08 10:39:4215-16赛季CBA联赛之辽宁
日期:2016-12-15 10:24:1715-16赛季CBA联赛之佛山
日期:2016-11-30 09:04:2015-16赛季CBA联赛之江苏
日期:2016-04-29 15:56:1215-16赛季CBA联赛之同曦
日期:2016-04-12 13:21:182016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之山东
日期:2016-02-16 11:37:52每日论坛发贴之星
日期:2016-02-07 06:20:00程序设计版块每日发帖之星
日期:2016-02-07 06:20:0015-16赛季CBA联赛之新疆
日期:2018-01-09 16:25:37
8 [报告]
发表于 2014-10-22 14:57 |只看该作者
本帖最后由 bskay 于 2014-10-22 15:03 编辑

等分还不如这样呢:
for (i = 0; i < 1000; i++)
{
     a = i*1000+(rand()%1000);
}


上面看起来不太像随机数,哪能相隔那么多啊,其实只要考虑到i作为一个因素就可以了,但是不能让它过大的影响数的分布
要降低它的"贡献值",可以参考取hash值的函数那样移位啊与啊和啊的..就能保证唯一,也不需要查有序表

论坛徽章:
13
CU大牛徽章
日期:2013-04-17 11:20:3615-16赛季CBA联赛之吉林
日期:2017-05-25 16:45:4715-16赛季CBA联赛之福建
日期:2017-03-13 11:33:442017金鸡报晓
日期:2017-02-08 10:39:422017金鸡报晓
日期:2017-01-10 15:13:29IT运维版块每日发帖之星
日期:2016-03-15 06:20:01IT运维版块每日发帖之星
日期:2015-10-02 06:20:00CU十二周年纪念徽章
日期:2013-10-24 15:41:34CU大牛徽章
日期:2013-09-18 15:15:45CU大牛徽章
日期:2013-09-18 15:15:15CU大牛徽章
日期:2013-04-17 11:46:39CU大牛徽章
日期:2013-04-17 11:46:28
9 [报告]
发表于 2014-10-22 21:42 |只看该作者
本帖最后由 xdsnet 于 2014-10-22 21:46 编辑

如果要真正的随机数,则不能洗牌算法吧
应该是类似楼主3的算法,不过这个算法存在不能结束收敛的可能,所以不是复杂度最低的算法,这时如果单纯考虑降低复杂度,其实可以考虑一个移位+后续位算法,绝对不存在重复(纯理论,在支持大数乘法——长整数的条件下),可以实现O(1),rand()表示取一个随机整数。
步进一个计数器n
填充到数组中的过程
for (n=0;n<1000;n++){
a[n]=rand()*1000+n;
}
因为后3个十进制位肯定不同,所以这个算法填充的随机数不会重复的。

其实和楼上的差不多效果(我开始是没有看见楼上的),但性质不同,楼上的随机数范围要小很多的,这个理论取值范围是[0,max(rand())*1000+999],楼上的取值范围是[0,999999],而且填充是肯定的升序,我的排序是不固定的。可以通过rand()的设计控制范围(比如用不到长整数)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP