careercup-高等难度 18.2
18.2 编写一个方法,洗一副牌。要求做到完美洗牌,换言之,这幅牌52!种排列组合出现的概率相同。假设给定一个完美的随机发生器。
解法:假定有个数组,含有n个元素,类似如下:
[1][2][3][4][5]
利用简单构造法,我们不妨先问自己,假定有个方法shuffle(...)对n-1个元素有效,我们可以用它来打乱n个元素的次序吗?当然可以,而且非常容易实现。我们会先打乱前n-1个元素的次序,然后,取出第n个元素,将它和数组中的元素随机交换。就这么简单!递归解法的算法如下:
//lower和highter(含)之间的随机数
int rand(int lower,int highter)
{
return lower+(int)(random()*(highter-lower+));
} void shuffleArrayRecursively(int cards[],int i)
{
if(i==)
return;
shuffleArrayRecursively(cards,i-);
int k=rand(,i);
int temp=cards[i];
cards[i]=cards[k];
cards[k]=temp;
return;
}
以迭代方式实现的话,这个算法又会是什么样?让我们先考虑,我们要做的是遍历整个数组,对每个元素i,将array[i]与0到i(含)之间的随机数交换。
void suffleArrayInteratively(int cards[],n)
{
for(int i=;i<n;i++)
{
int k=rand(,i);
int tmp=cards[k];
cards[k]=cards[i];
cards[i]=tmp;
}
}
洗牌问题(shuffle)就如随机取样(random sample)问题,在《计算机程序设计艺术》(volume 2 chapter 3)中得到了详细的讲解,关于该问题的详细探讨可以翻阅该书相应章节。
洗牌问题,顾名思义,就是给你一把牌,让你把它完全打乱,这可以归结成一个数组问题:
给你一个长度为n的数组,要求你将其完全打乱,数组中元素交换跟下标是一一对应的,所以也就可以表述为给你一个有序序列0—n-1,要你将其完全打乱,要求每个元素在任何一个位置出现的概率均为1/n。
洗牌问题是打乱一个有序序列(比如下标有序)的算法与随机取样颇有渊源,算法也与随机取样问题十分相近,如下:
void shuffle(T* arr, int len)
{
for(int i=0; i<len; i++)
{
int idx=rand()%(i+1);
swap(arr[idx], arr[i]);
}
}
算法正确性证明也可以用数学归纳法证明:
待证明问题:对于一个长度为n的数组,经过上述算法处理后,会得到一个随机数组,原数组中每一个元素在任何一个位置的概率均为1/n
证明:算法可以分为两部分:前n-1次执行+最后一次执行
1、当n=1时,idx必为0,所以元素arr[0]在任何一个位置的概率为1/1,命题成立。
2、假设当n=k时,命题成立,即n=k时,原数组中任何一个元素在任何一个位置的概率为1/k。
当n=k+1时,当算法执行完k次时,前k个元素在前k个位置的概率均为1/k,执行最后一步时,前k个元素中任何一个元素被替换到第k+1位置的概率:
(1-(1/k)*(k/k+1)) * (1/k) = 1/k+1
所以,对于前k个元素,它们在k+1的位置上概率为1/k+1,在前面k个位置任何一个位置上的概率为(1-1/(k+1)) * (1/k)=1/(k+1),对于前k个元素,其在整个数组前k+1个位置上的概率均为1/k+1,
对于第k+1个元素,其在原位置的概率为1-(k/k+1)=1/k+1,在前k个位置任何一个位置的概率为:(k/k+1) * (1/k)=1/k+1,所以对于第k+1个元素,其在整个数组前k+1个位置上的概率也均为1/k+1。
命题得证。
能让我理解的随机洗牌问题。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
问题描述:假设有一个数组,包含n个元素。现在要重新排列这些元素,要求每个元素被放到任何一个位置的概率都相等(即1/n),并且直接在数组上重排(in place),不要生成新的数组。用O(n) 时间、O(1)辅助空间。
算法是非常简单了,当然在给出算法的同时,我们也要证明概率满足题目要求。
先想想如果可以开辟另外一块长度为n的辅助空间时该怎么处理,显然只要对n个元素做n次(不放回的)随机抽取就可以了。先从n个元素中任选一个,放入新空间的第一个位置,然后再从剩下的n-1个元素中任选一个,放入第二个位置,依此类推。
按照同样的方法,但这次不开辟新的存储空间。第一次被选中的元素就要放入这个数组的第一个位置,但这个位置原来已经有别的(也可能就是这个)元素了,这时候只要把原来的元素跟被选中的元素互换一下就可以了。很容易就避免了辅助空间。
我们先假设一个5维数组:1,2,3,4,5。如果第1次随机取到的数是4, 那么我们希望参与第2次随机选取的只有1,2,3,5。既然4已经不用, 我们可以把它和1交换,第2次就只需要从后面4位(2,3,1,5)中随机选取即可。同理, 第2次随机选取的元素和数组中第2个元素交换,然后再从后面3个元素中随机选取元素, 依次类推。
C++实现:
void RandomShuffle(int a[], int n){
for(int i=; i<n; ++i){
int j = rand() % (n-i) + i;// 产生i到n-1间的随机数,依次从n个元素,n-1个元素,n-2个元素中取得一个元素。
Swap(a[i], a[j]);
}
careercup-高等难度 18.2的更多相关文章
- careercup-高等难度 18.9
18.9 随机生成一些数字并传入某个方法.编写一个程序,每当收到新字符数字时,找出并记录中位数. 类似:设计一个数据结构,包括两个函数,插入数据和获得中位数 解法: 一种解法是使用两个优先级堆:一个大 ...
- careercup-高等难度 18.7
18.7 给定一组单词,编写一个程序,找出其中的最长单词,且该单词由这组单词中的其他单词组合而成. 解法: 原题 给定字符串,以及一个字典,判断字符串是否能够拆分为字段中的单词.例如,字段为{hell ...
- careercup-高等难度 18.6
18.6 设计一个算法,给定10亿个数字,找出最小的100万个数字.假定计算机内存足以容纳全部10亿个数字. 解法: 方法1:排序 按升序排序所有的元素,然后取出前100万个数,时间复杂度为O(nlo ...
- careercup-高等难度 18.5
18.5 有个内含单词的超大文本文件,给定任意两个单词,找出在这个文件中这两个单词的最短距离(也即相隔几个单词).有办法在O(1)时间里完成搜索操作吗?解法的空间复杂度如何? 解法1:我们假设单词wo ...
- careercup-高等难度 18.1
18.1 编写一个函数,将两个数字相加,不得使用+或其他算术运算符. int add(int a,int b) { ) return a; int sum=a^b; ; return add(sum ...
- 别再埋头刷LeetCode之:北美算法面试的题目分类,按类型和规律刷题,事半功倍
算法面试过程中,题目类型多,数量大.大家都不可避免的会在LeetCode上进行训练.但问题是,题目杂,而且已经超过1300道题. 全部刷完且掌握,不是一件容易的事情.那我们应该怎么办呢?找规律,总结才 ...
- [CareerCup] 18.1 Add Two Numbers 两数相加
18.1 Write a function that adds two numbers. You should not use + or any arithmetic operators. 这道题让我 ...
- [CareerCup] 18.12 Largest Sum Submatrix 和最大的子矩阵
18.12 Given an NxN matrix of positive and negative integers, write code to find the submatrix with t ...
- [CareerCup] 18.11 Maximum Subsquare 最大子方形
18.11 Imagine you have a square matrix, where each cell (pixel) is either black or white. Design an ...
随机推荐
- MVC弹出子页面向父页面传值
实现思路是使用js在父子页面间传值 视图一代码,父页面 @{ ViewBag.Title = "Index"; } <script type="text/javas ...
- Hadoop2.2 federnation联盟的搭建
联盟实际上是一个单独的集群,集群里面包含很多的NameService共享同样的DataNode,同一份数据只上传一份,block块相同,一个集群中删除,另一个集群中还是存在的.同一份数据只是在name ...
- Who is the best at Dataset X?
推荐一个关于分类.目标检测.姿态估计的数据集收藏的网页. Did you ever want to quickly learn?which paper provides the best result ...
- EventSource (node.js 与 OC)
node.js服务器代码: var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, ...
- Xcode集成Google Test
Xcode集成Google Test 1.下载源代码https://github.com/google/googletest 2.进入下载文件目录下googletest/make中运行make gte ...
- 谈FTP服务器攻击技术及其展望 (修改中)
欢迎大家给我投票: http://2010blog.51cto.com/350944 请看下篇:谈FTP服务器攻击技术及其展望 (下) 全文完http://chengua ...
- linux 下查找大于100M的文件
命令行如下 find . -type f -size +100M Linux系统下查找大文件或目录的技巧 当硬盘空间不够时,我们就很关心哪些目录或文件比较大,看看能否干掉一些了,怎么才能知道呢?以易读 ...
- labview在线帮助网址
http://zone.ni.com/reference/zhs-XX/help/371361L-0118/ labview网络讲坛 网址 http://v.eepw.com.cn/video/com ...
- KMP应用http://acm.hdu.edu.cn/showproblem.php?pid=2594
riemann与marjorie拼接后riemannmarjorie前缀与后缀公共部分为 rie 长度为 3(即next[l] = next[14]的值,l为拼接后的长度)但:aaaa与aa拼接后aa ...
- 修改hosts文件解决OneDrive被墙的问题
增加如下内容就可以了.如果不知道修改hosts文件的具体方法请自行百度. 134.170.108.26 onedrive.live.com 134.170.108.152 skyapi.onedriv ...