当前位置: 首页 > 面试题库 >

当某些卡片不可用时,从卡组中随机挑选一张卡片的最有效方法是什么?

邹铭
2023-03-14
问题内容

我有一个数组,告诉是否正在使用卡:

int used[52];

如果我有很多用过的卡,这是一种随机选择卡的糟糕方法:

do {
  card = rand() % 52;
} while (used[card]);

因为如果我只有3-4张未使用的卡片,那么将需要永远找到它们。

我想出了这个:

 int card;
 int k = 0;
 int numUsed = 0;
 for (k=0; k < 52; ++k) {
   if (used[k]) numUsed += 1;
 }
 if (numUsed == 52) return -1;
 card = rand() % (52 - numUsed);

 for (k=0; k < 52; ++k) {
   if (used[k]) continue;
   if (card == 0) return k;
   card -= 1;
 }

我想如果卡座已满,效果会更好,但是当卡座为空时,效果会更好,因为我必须经历两个for循环。

最有效的方法是什么?


问题答案:

我认为您的两遍算法可能是您最好的选择,因为您在注释中添加了约束,而您事先并不知道哪些卡适合进行给定抽奖。

您可以尝试狡猾的“单次通过从未知大小的列表中随机选择”算法:

int sofar = 0;
int selected = -1;
for (i = 0; i < 52; ++i) {
    if (used[i]) continue;
    ++sofar;
    if ((rand() % sofar) == 0) selected = i;
}
if (selected == -1) panic; // there were no usable cards 
else used[selected] = 1;   // we have selected a card

然后,如果(如您在评论中所述)不同的抽奖具有不同的条件,则可以用used[i]实际的条件代替。

它的工作方式是选择第一张卡。然后用概率为1/2的第二张牌替换它。用概率为1/3等的第三张卡替换结果。通过归纳很容易证明,经过n步,前面每张卡被选中的概率为1
/ n。

此方法使用大量随机数,因此它可能比两次通过的版本慢,除非获取每个项目的速度很慢或评估标准的速度很慢。它通常用于例如从文件中选择随机行,而您实际上不想在数据上运行两次。对随机数的偏差也很敏感。

既好又简单。

[编辑:证明

令p(j,k)为卡号j为步骤k之后当前选择的卡的概率。

需要证明:对于所有n,对于所有1 <= j <= n,p(j,n)= 1 / n

对于n = 1,显然p(1,1)= 1,因为在第一步以概率1/1 = 1选择了第一张牌。

假设所有1 <= j <= k的p(j,k)= 1 / k。

然后,我们在步骤(k + 1)选择第(k + 1)张卡,概率为(1 / k + 1),即p(k + 1,k + 1)= 1 /(k + 1)。

我们以概率k /(k + 1)保留现有选择,因此对于任何j <k + 1:

p(j,k+1) = p(j,k) * k/(k+1)
         = 1/k    * k/(k+1)   // by the inductive hypothesis
         = 1/(k+1)

所以对于所有1 <= k <= k + 1,p(j,k + 1)= 1 /(k + 1)

因此,通过归纳,对于所有n:对于所有1 <= j <= n],p(j,n)= 1 / n



 类似资料:
  • 卡片是包含一组特定数据集的纸片,数据集含有各种相关信息,例如,关于单一主题的照片,文本,和链接。卡片通常是通往更详细复杂信息的入口。卡片有固定的宽度和可变的高度。最大高度限制于可适应平台上单一视图的内容,但如果需要它可以临时扩展(例如,显示评论栏)。卡片不会翻转以展示其背后的信息。 用途 卡片是用来显示由不同种类对象组成的内容的便捷途径。它们也适用于展示尺寸或操作相当不同的相似对象,像带有不同长度

  • 在此模板中,卡片组件是使用最广泛的。你可以将其用于显示图表、文本块等。有许多不同的样式,我们将在下面进行介绍。 默认卡片标记 <div class="card"> <div class="card-header"> <h3 class="card-title">默认卡片示例</h3> <div class="card-tools"> <!-- 按钮,标签和其

  • 卡片用于展示不同类型的内容是很方便的,它适合用于展示具有相似的对象但是行为差异大的内容,如具有可变长度的标题的照片。 基本卡片 <div class="row"> <div class="col s12 m6"> <div class="card blue-grey darken-1"> <div class="card-content white-text">

  • 定义 司机卡片。 图片展示 代码演示 import Driver from 'pile/dist/components/driver' <Driver avatarUrl="" carColor="白" carType="大众速腾" card="京FA7318" cntOrder={174} company="车主之家-车主俱乐部望京店" isMaster={fals

  • 我正在尝试改变当前可见的卡片布局与幻灯片效果。但我在幻灯片的开始看到一个我无法调试/解决的闪烁。我怎么才能避开那部电影呢? 下面是再现错误的示例代码: 这里首先显示(“Harry Joy”)。然后我使(“Harsh Raval”)可见,并尝试更改两者的位置以提供幻灯片效果。但这里发生的是第一次两个标签显示在彼此的顶部,然后它开始滑动。我的意思是把两个标签都显示在对方的上面,我怎么才能停止呢?如果你

  • 本文向大家介绍PHP随机生成信用卡卡号的方法,包括了PHP随机生成信用卡卡号的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了PHP随机生成信用卡卡号的方法。分享给大家供大家参考。具体分析如下: 这段PHP代码根据信用卡卡号产生规则随机生成信用卡卡号,是可以通过验证的,仅供学习参考,请不要用于非法用途,否则后果自负。 希望本文所述对大家的php程序设计有所帮助。

  • 我一直在寻找一个解决办法,现在,尽管所有类似的问题和答案,但没有找到任何似乎工作。我想让用户能够通过卡片布局中设置的各种面板进行操作。然而,我希望用来在这些卡片之间切换的按钮在卡片本身,而不是一组单独的按钮,它不会在程序中改变。下面是创建框架的主文件: 编辑:我向MainMenu JPanel的按钮添加了一个自动生成的操作监听器,如下所示: 在主文件(主文件为BattleGraphs_V1)中添加

  • 问题内容: 我一直在尝试使用角材料制作一张网格的卡片。所以我正在使用指令md-grid-list和md-card。但是结果非常丑陋,我不确定要了解md-row- heigh(ratio)的工作原理,但我有文档说明,但说明并不多。 到目前为止,这是我一直在做的事情:http : //codepen.io/stunaz/pen/qdQwbq,我正在尝试构建一个响应式卡网格,甚至不确定md- grid-