在Microsoft采访中已经问过这个问题。非常好奇地知道为什么这些人对概率提出如此奇怪的问题?
给定rand(N),一个随机生成器,生成从0到N-1的随机数。
int A[N]; // An array of size N
for(i = 0; i < N; i++)
{
int m = rand(N);
int n = rand(N);
swap(A[m],A[n]);
}
编辑:请注意种子是不固定的。
数组A保持不变的概率是多少?
假设数组包含唯一元素。
在Microsoft采访中已经问过这个问题。非常好奇地知道为什么这些人对概率提出如此奇怪的问题?
给定rand(N),一个随机生成器,生成从0到N-1的随机数。
int A[N]; // An array of size N
for(i = 0; i < N; i++)
{
int m = rand(N);
int n = rand(N);
swap(A[m],A[n]);
}
编辑:请注意种子是不固定的。
数组A保持不变的概率是多少?
假设数组包含唯一元素。
swap函数不可能更改的内容A。\ edit:嗯,swap也可以是一个宏……让我们希望它不是:)
Answers:
好吧,我对此玩得很开心。当我第一次阅读该问题时,我想到的第一件事就是群论(尤其是对称群S n)。for循环通过在每次迭代中组成换位(即交换)来简单地在S n中建立一个置换σ 。我的数学并不是那么出色,我有些生疏,所以如果我的记法不适合我。
让我们假设A数组在置换后保持不变。我们最终要求找出事件的概率A,Pr(A)。
我的解决方案尝试遵循以下过程:
请注意,for循环的每次迭代都会创建一个交换(或transposition),该交换将导致以下两种情况之一(但不会同时发生):
我们标记第二种情况。让我们定义一个身份转置如下:
一个身份换位当一个号码与自己交换发生。也就是说,在上述for循环中,当n == m时。
对于所列代码的任何给定运行,我们都组成N换位。有可能0, 1, 2, ... , N出现在这个“产业链”的身份换位。
例如,考虑一种N = 3情况:
Given our input [0, 1, 2].
Swap (0 1) and get [1, 0, 2].
Swap (1 1) and get [1, 0, 2]. ** Here is an identity **
Swap (2 2) and get [1, 0, 2]. ** And another **
请注意,存在奇数个非同一性换位(1),并且更改了数组。
让我们K_i以i身份置换出现在给定排列中的事件为例。请注意,这形成了所有可能结果的详尽划分:
0和N换位之间。因此我们可以应用总概率定律:
现在,我们终于可以利用分区了。请注意,当非同一性换位的数目为奇数时,数组将无法保持不变*。从而:
*从群体理论来看,排列是偶数或奇数,但不会两者都。因此,奇数置换不能是身份置换(因为身份置换是偶数)。
因此,我们现在必须确定两个概率N-i:


第一项,,
表示获得具有i身份置换的置换的概率。事实证明这是二项式的,因为对于for循环的每次迭代:
1/N。因此,对于N试验而言,获得i身份易位的可能性为:
所以,如果你走到今天这一步,我们已经将问题归结为寻找
为N - i偶数。这代表在给定i换位为身份的情况下获得身份置换的可能性。我使用一种幼稚的计数方法来确定实现身份置换的方法数量超过可能的置换数量。
首先考虑排列(n, m)和(m, n)等效项。然后,将M可能的非身份置换数目设为。我们将经常使用此数量。
这里的目标是确定可以组合换位的集合以形成标识置换的方式的数量。我将尝试在的示例旁边构造一般的解决方案N = 4。
让我们考虑N = 4所有身份换位(即 i = N = 4)的情况。让X代表身份转置。对于每种X,都有N可能(它们是:)n = m = 0, 1, 2, ... , N - 1。因此,存在N^i = 4^4实现身份置换的可能性。为了完整起见,我们添加了二项式系数C(N, i)来考虑身份换位的顺序(此处等于1)。我试图用上面元素的物理布局和下面可能性的数量来描述这个问题:
I = _X_ _X_ _X_ _X_
N * N * N * N * C(4, 4) => N^N * C(N, N) possibilities
现在,无需显式替换N = 4and i = 4,我们可以查看一般情况。将以上内容与先前找到的分母结合起来,我们会发现:
这很直观。实际上,除此以外的任何其他值1都可能会警告您。想想看:我们被认为所有的N换位都是身份。在这种情况下,数组可能保持不变?显然,1。
现在,再次针对N = 4,让我们考虑2个身份换位(即 i = N - 2 = 2)。按照惯例,我们将两个身份放在最后(并在以后订购)。现在我们知道,我们需要选择两个换位,当组成时,它们将成为身份置换。让我们将任何元素放在第一个位置,称为t1。如上所述,有M可能假设t1不是身份(不可能,因为我们已经放置了两个身份)。
I = _t1_ ___ _X_ _X_
M * ? * N * N
剩下的唯一可能出现在第二个位置的元素是的逆t1,这实际上是t1(并且这是唯一的具有逆唯一性的元素)。我们再次包含二项式系数:在这种情况下,我们有4个开放位置,并且我们打算放置2个身份置换。我们有多少种方法可以做到这一点?4选择2。
I = _t1_ _t1_ _X_ _X_
M * 1 * N * N * C(4, 2) => C(N, N-2) * M * N^(N-2) possibilities
再次查看一般情况,这全部对应于:
最后,我们在N = 4没有身份换位的情况下(即 i = N - 4 = 0)进行处理。由于存在很多可能性,因此开始变得棘手,我们必须注意不要重复计算。类似地,我们从将单个元素放在第一位开始并找出可能的组合。首先采取最简单的方法:相同的换位4次。
I = _t1_ _t1_ _t1_ _t1_
M * 1 * 1 * 1 => M possibilities
现在让我们考虑两个独特的元素t1和t2。(因为不能等于),所以存在M可能性t1,只有M-1可能性。如果我们用尽所有安排,我们将获得以下模式:t2t2t1
I = _t1_ _t1_ _t2_ _t2_
M * 1 * M-1 * 1 => M * (M - 1) possibilities (1)st
= _t1_ _t2_ _t1_ _t2_
M * M-1 * 1 * 1 => M * (M - 1) possibilities (2)nd
= _t1_ _t2_ _t2_ _t1_
M * M-1 * 1 * 1 => M * (M - 1) possibilities (3)rd
现在,让我们考虑三个独特的元素,t1,t2,t3。t1首先放置,然后放置t2。和往常一样,我们有:
I = _t1_ _t2_ ___ ___
M * ? * ? * ?
我们还不能说可能t2有多少个,我们将在一分钟内看到原因。
现在t1,我们排名第三。注意,t1必须走到那里,因为如果要走到最后一个位置,我们将只是重新创建(3)rd上面的安排。重复计算是不好的!这将第三个唯一元素保留t3到最终位置。
I = _t1_ _t2_ _t1_ _t3_
M * ? * 1 * ?
那么,为什么我们需要花一点时间t2仔细考虑s的数量呢?该换位t1而t2 不能是不相交的置换(即他们必须分享他们的一个(且只有一个,因为他们也不能等于)n或m)。这样做的原因是因为如果它们不相交,我们可以交换排列顺序。这意味着我们将重复计算该(1)st安排。
说t1 = (n, m)。t2必须是以下形式的(n, x)或(y, m)为一些x与y以是非不相交的。请注意,x可能不是n或,m而y很多不是n或m。因此,t2实际上可能存在的可能排列数2 * (N - 2)。
因此,回到我们的布局:
I = _t1_ _t2_ _t1_ _t3_
M * 2(N-2) * 1 * ?
现在t3必须是的反函数t1 t2 t1。让我们手动完成:
(n, m)(n, x)(n, m) = (m, x)
因此t3必须(m, x)。请注意,这并非不相交t1且不等于t1或不相等,t2因此在这种情况下没有重复计数。
I = _t1_ _t2_ _t1_ _t3_
M * 2(N-2) * 1 * 1 => M * 2(N - 2) possibilities
最后,将所有这些放在一起:
就是这样了。向后工作,将我们发现的结果代入步骤2中给出的原始求和中。我计算出N = 4以下情况的答案。它非常接近另一个答案中找到的经验值!
N = 4
M = 6 _________ ______________ _________
| Pr(K_i)| Pr(A | K_i)| 产品展示
_________ | _________ | _____________ | _________ |
| | | | |
| i = 0 | 0.316 | 120/1296 | 0.029 |
| _________ | _________ | _____________ | _________ |
| | | | |
| i = 2 | 0.211 | 6/36 | 0.035 |
| _________ | _________ | _____________ | _________ |
| | | | |
| i = 4 | 0.004 | 1/1 | 0.004 |
| _________ | _________ | _____________ | _________ |
| | |
| 总和:0.068 |
| _____________ | __________ |
如果在小组理论中有结果可以在这里应用,那就太酷了,也许还有!当然,这将使所有繁琐的计数工作完全消失(并将问题简化为更优雅的方法)。我停止在上班了N = 4。对于N > 5,给出的仅是一个近似值(我不确定该如何好)。很清楚为什么要考虑这一点:例如,给定N = 8换位,显然有一些方法可以用四个独特的元素来创建身份,而这在上面并没有说明。随着置换的时间变长(据我所知...),方法的数量似乎变得难以计数。
无论如何,在面试范围内,我绝对不能做这样的事情。如果幸运的话,我将达到分母步骤。除此之外,它看起来还很讨厌。
非常好奇地知道为什么这些人对概率提出如此奇怪的问题?
之所以问这样的问题,是因为它们使访问者可以深入了解访问者的
... 等等。揭露被访者这些属性的问题的关键是拥有一段看似简单的代码。这摆脱了非编码器卡住的冒名顶替者;傲慢的人得出错误的结论;懒惰或低于标准的计算机科学家找到了一个简单的解决方案,并停止寻找。正如他们所说,通常,不是您是否获得正确答案,而是您是否对自己的思维过程印象深刻。
我也会尝试回答这个问题。在面试中,我会解释自己而不是提供单行书面答案-这是因为即使我的“答案”是错误的,我也能够证明逻辑思维。
A将保持相同-即元素位于相同位置-
m == n在每次迭代中(以便每个元素仅与自身交换);要么第一种情况是duedl0r给出的“简单”情况,即数组未更改的情况。这可能是答案,因为
数组A保持不变的概率是多少?
如果数组在处更改,i = 1然后又在处恢复i = 2,则该数组处于原始状态,但不是“保持不变”-已更改,然后又更改回。那可能是一个聪明的技术。
然后考虑元素被交换和交换回去的可能性-我认为在一次采访中,计算超出了我的能力。显而易见的考虑是,不必进行更改-换回交换,可以很容易地在三个元素之间进行交换,交换1和2,然后交换2和3、1和3,最后交换2和3。继续,可能会有4、5或更多这样的“循环”项目之间的交换。
事实上,而不是考虑的情况下,该阵列是不变的,它可能是简单考虑它的情况下被改变。考虑是否可以将此问题映射到Pascal三角形等已知结构上。
这是一个难题。我同意,在面试中很难解决,但这并不意味着在面试中很难提出。较差的候选人将没有答案,普通候选人将猜出最明显的答案,而好的候选人将解释为什么问题很难回答。
我认为这是一个“不限成员名额”的问题,可让面试官深入了解候选人。因此,即使在面试中很难解决,在面试中也要问一个好问题。问一个问题不仅仅是检查答案是对还是错。
以下是C代码,用于计算rand可以产生的2N元组的值的数量并计算概率。从N = 0开始,它显示计数为1、1、8、135、4480、189125和12450816,概率为1,1,.5,.185185,.0683594,.0193664和.00571983。计数没有出现在“整数序列百科全书”中,因此我的程序有错误或者这是一个非常晦涩的问题。如果是这样,这个问题并不是求职者要解决的,而是要揭露他们的一些思维过程以及他们如何处理挫败感。我不会认为这是一个很好的面试问题。
#include <inttypes.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define swap(a, b) do { int t = (a); (a) = (b); (b) = t; } while (0)
static uint64_t count(int n)
{
// Initialize count of how many times the original order is the result.
uint64_t c = 0;
// Allocate space for selectors and initialize them to zero.
int *r = calloc(2*n, sizeof *r);
// Allocate space for array to be swapped.
int *A = malloc(n * sizeof *A);
if (!A || !r)
{
fprintf(stderr, "Out of memory.\n");
exit(EXIT_FAILURE);
}
// Iterate through all values of selectors.
while (1)
{
// Initialize A to show original order.
for (int i = 0; i < n; ++i)
A[i] = i;
// Test current selector values by executing the swap sequence.
for (int i = 0; i < 2*n; i += 2)
{
int m = r[i+0];
int n = r[i+1];
swap(A[m], A[n]);
}
// If array is in original order, increment counter.
++c; // Assume all elements are in place.
for (int i = 0; i < n; ++i)
if (A[i] != i)
{
// If any element is out of place, cancel assumption and exit.
--c;
break;
}
// Increment the selectors, odometer style.
int i;
for (i = 0; i < 2*n; ++i)
// Stop when a selector increases without wrapping.
if (++r[i] < n)
break;
else
// Wrap this selector to zero and continue.
r[i] = 0;
// Exit the routine when the last selector wraps.
if (2*n <= i)
{
free(A);
free(r);
return c;
}
}
}
int main(void)
{
for (int n = 0; n < 7; ++n)
{
uint64_t c = count(n);
printf("N = %d: %" PRId64 " times, %g probabilty.\n",
n, c, c/pow(n, 2*n));
}
return 0;
}
该算法的行为可以被建模为一个Markov链在对称群 小号Ñ。
的 数组N个元素A可以按N个排列!不同的排列。让我们对这些排列从1到N!进行编号,例如按字典顺序。因此,A算法中任何时候的数组状态都可以通过排列数来充分表征。
例如,对于N = 3,所有3个可能的编号之一!= 6个排列可能是:
在算法的每个步骤中,状态A要么保持不变,要么从这些排列中的一个过渡到另一个。现在,我们对这些状态更改的可能性感兴趣。让我们称Pr(i → j)状态从排列i变为排列j的概率在单循环迭代中。
当我们从[0,N -1]范围内均匀且独立地选择m和n时,有N ²可能的结果,其中的每一个是同样可能。
对于这些结果中的N个,m = n成立,因此排列没有变化。因此,
。
剩余Ñ ² - ñ例是换位,即两个元件交换它们的位置,因此,置换的变化。假设这些换位之一交换位置x和y处的元素。有两种情况可以通过算法生成此转置:m = x,n = y或m = y,n = x。因此,每个换位的概率为2 / N ²。
这与我们的排列有何关系?让我们把两个置换我和Ĵ 邻居当且仅当有哪些转变换位我到Ĵ(反之亦然)。然后我们可以得出结论:
我们可以安排的概率PR(我→ Ĵ在过渡矩阵)P ∈[0,1] Ñ!× Ñ!。我们定义
p ij = Pr(i → j),
其中p ij是P的第i行和第j列中的条目。注意
Pr(i → j)= Pr(j → i),
这意味着P是对称的。
现在的关键是观察将P自身相乘会发生什么。采取任何元素p (2)IJ的P ²:
乘积Pr(i → k)·Pr(k → j)是这样的概率,即从排列i开始,我们一步就过渡到排列k,而在下一个后续步骤中过渡到排列j。因此,对所有介于中间的置换k求和,就得出了从i到j分两步过渡的总概率。
这个论点可以扩展到P的高次幂。特殊的后果如下:
假设我们从置换i开始,p (N)ii是在N步之后返回置换i的概率。
让我们通过N = 3进行测试。我们已经为排列编号了。相应的转换矩阵如下:
P与自身相乘得到:
另一个乘法产生:
主对角线中的任何元素给我们想要的概率,这是15 / 81或5 / 27。
尽管此方法在数学上是合理的,并且可以应用于N的任何值,但这种形式并不实用。转换矩阵P有N!2项,这很快变得非常大。即使对于N = 10,矩阵的大小也已经超过13万亿个条目。因此,天真地实现该算法似乎是不可行的。
但是,与其他建议相比,此方法结构非常结构化,不需要弄清楚哪些排列是邻居,不需要复杂的推导。我希望可以利用这种结构性来找到更简单的计算。
例如,可以利用以下事实:P的任何幂的所有对角元素都是相等的。假设我们可以轻松地计算出P N的踪迹,则解就是tr(P N)/ N!。P N的迹线等于其特征值的N次方之和。因此,如果我们有一个有效的算法来计算P的特征值,就可以成立了。但是,除了计算最多N = 5的特征值之外,我没有对此进行进一步的探讨。
很容易观察边界1 / n n <= p <= 1 / n。
这是显示反指数上限的不完整想法。
您正在从{1,2,..,n}绘制2n次数字。如果它们中的任何一个是唯一的(恰好发生一次),则该数组肯定会更改,因为该元素已消失并且无法返回其原始位置。
固定数唯一的概率为2n * 1 / n *(1-1 / n)^(2n-1)= 2 *(1-1 / n)^(2n-1),渐近地为2 / e 2,它从0出发。[2n因为您选择在哪个尝试上获得它,所以1 / n表示您尝试获得它,(1-1 / n)^(2n-1)您没有获得它。其他尝试]
如果事件是独立的,您将有机会所有数字都是非唯一的(2 / e 2)^ n,这意味着p <= O((2 / e 2)^ n)。不幸的是,他们不是独立的。我认为可以通过更复杂的分析来显示界限。关键字是“球和垃圾箱问题”。
一种简单的解决方案是
p> = 1 / N N
由于数组保持不变的一种可能方式是m = n每次迭代。并且m等于n可能性1 / N。
肯定比那高。问题是多少。
再想一想:人们还可能争辩说,如果您随机地对数组进行混洗,则每个排列都有相等的概率。由于存在n!排列,仅得到一个(我们一开始就有一个)的可能性是
p = 1 / N!
这比以前的结果好一点。
如上所述,该算法是有偏见的。这意味着并非每个排列都有相同的概率。所以1 / N!不是很准确。您必须找出排列的分布方式。
n!并不总是划分n^n,只考虑其中的情况n是素大于2
仅供参考,不确定上面(1 / n ^ 2)的范围是否成立:
N=5 -> 0.019648 < 1/25
N=6 -> 0.005716 < 1/36
采样代码:
import random
def sample(times,n):
count = 0;
for i in range(times):
count += p(n)
return count*1.0/times;
def p(n):
perm = range(n);
for i in range(n):
a = random.randrange(n)
b = random.randrange(n)
perm[a],perm[b]=perm[b],perm[a];
return perm==range(n)
print sample(500000,5)
每个人都假定A[i] == i没有明确声明。我也将做这个假设,但请注意,概率取决于内容。例如,如果A[i]=0,则所有N的概率= 1。
这是操作方法。假设P(n,i)结果数组与原始数组相差i个换位的概率。
我们想知道P(n,0)。确实是这样:
P(n,0) =
1/n * P(n-1,0) + 1/n^2 * P(n-1,1) =
1/n * P(n-1,0) + 1/n^2 * (1-1/(n-1)) * P(n-2,0)
说明:我们可以通过两种方式获得原始数组,要么在已经良好的数组中进行“中性”转置,要么通过还原唯一的“不良”转置。为了获得只有一个“坏”转置的数组,我们可以将一个带有0个坏转置的数组制成一个非中立的转置。
编辑:在P(n-1,0)中用-2代替-1
A[i] == i。2)我认为通常没有找到简单的方法P(n,i)。这是很容易的P(n,0),但是对于较大的i来说,尚不清楚有多少个换位是“好”和有多少个“坏”。
P(n,0)但这正是问题所在。如果您不同意这种推理,请举一个例子,说明失败的原因或原因。
P(n-1,1) = (1-1/(n-1)) * P(n-2,0)。如果您处于中间位置,则可以添加另一个不良步骤,以后将撤消该步骤。例如,考虑(1234)=>(2134)=>(2143)=>(1243)=>(1234)。分母中的数字n-1也值得怀疑,因为随机函数允许重复。
有趣的问题。
我认为答案是1 / N,但是我没有任何证据。找到证明后,我将编辑答案。
到现在为止我得到了什么:
如果m == n,则不会更改数组。m == n的概率为1 / N,因为有N ^ 2个选项,并且只有N个是适合的(每0 <= i <= N-1的((i,i))。
因此,我们得到N / N ^ 2 = 1 / N。
表示Pk,在进行k次交换互换之后,大小为N的数组将保持不变的概率。
P1 = 1 / N。(如下所示)
P2 =(1 / N)P1 +(N-1 / N)(2 / N ^ 2)= 1 / N ^ 2 + 2(N-1)/ N ^ 3。
Explanation for P2:
We want to calculate the probability that after 2 iterations, the array with
N elements won't change. We have 2 options :
- in the 2 iteration we got m == n (Probability of 1/N)
- in the 2 iteration we got m != n (Probability of N-1/N)
If m == n, we need that the array will remain after the 1 iteration = P1.
If m != n, we need that in the 1 iteration to choose the same n and m
(order is not important). So we get 2/N^2.
Because those events are independent we get - P2 = (1/N)*P1 + (N-1/N)*(2/N^2).
Pk =(1 / N)* Pk-1 +(N-1 / N)* X。(第一个用于m == n,第二个用于m!= n)
我必须多考虑X等于什么。(X只是真实公式的替代,不是常数或其他任何值)
Example for N = 2.
All possible swaps:
(1 1 | 1 1),(1 1 | 1 2),(1 1 | 2 1),(1 1 | 2 2),(1 2 | 1 1),(1 2 | 1 2)
(1 2 | 2 1),(1 2 | 2 2),(2 1 | 1 1),(2 1 | 1 2),(2 1 | 2 1),(2 1 | 2 2)
(2 2 | 1 1),(2 2 | 1 2),(2 2 | 2 1),(2 1 | 1 1).
Total = 16. Exactly 8 of them remain the array the same.
Thus, for N = 2, the answer is 1/2.
编辑: 我想介绍另一种方法:
我们可以将掉期分为三类:建设性掉期,破坏性掉期和无害掉期。
构造性交换定义为导致至少一个元素移动到正确位置的交换。
破坏性交换定义为导致至少一个元素从其正确位置移动的交换。
无害交换定义为不属于其他组的交换。
显而易见,这是所有可能交换的分区。(交集=空集)。
现在我要证明的主张:
The array will remain the same if and only if
the number of Destructive swap == Constructive swap in the iterations.
如果有人有反例,请写下来作为评论。
如果这个主张是正确的,我们可以将所有组合求和-0个无害掉期,1个无害掉期,..,N个无害掉期。
对于每个可能的k次无害交换,我们检查Nk是否为偶数,如果不是,则跳过。如果是,我们将(Nk)/ 2设为破坏性,将(Nk)设为建设性。只看所有可能性。
从数学的角度来看:
要使数组元素每次都在同一位置交换,则Rand(N)函数必须为int m和int n两次生成相同的数字。因此,Rand(N)函数两次生成相同数字的概率为1 / N。并且在for循环中有N次调用Rand(N),因此我们的概率为1 /(N ^ 2)
C#中的天真的实现。这个想法是创建初始数组的所有可能排列并枚举它们。然后,我们建立状态可能变化的矩阵。将矩阵本身乘以N倍,我们将得到矩阵,该矩阵显示存在从N步到置换#i到置换#j的几种方式。Elemet [0,0]将显示将导致相同初始状态的几种方法。第0行的元素总和将显示不同方式的总数。通过将前者除以后者,我们得到了概率。
实际上,排列的总数为N ^(2N)。
Output:
For N=1 probability is 1 (1 / 1)
For N=2 probability is 0.5 (8 / 16)
For N=3 probability is 0.1851851851851851851851851852 (135 / 729)
For N=4 probability is 0.068359375 (4480 / 65536)
For N=5 probability is 0.0193664 (189125 / 9765625)
For N=6 probability is 0.0057198259072973293366526105 (12450816 / 2176782336)
class Program
{
static void Main(string[] args)
{
for (int i = 1; i < 7; i++)
{
MainClass mc = new MainClass(i);
mc.Run();
}
}
}
class MainClass
{
int N;
int M;
List<int> comb;
List<int> lastItemIdx;
public List<List<int>> combinations;
int[,] matrix;
public MainClass(int n)
{
N = n;
comb = new List<int>();
lastItemIdx = new List<int>();
for (int i = 0; i < n; i++)
{
comb.Add(-1);
lastItemIdx.Add(-1);
}
combinations = new List<List<int>>();
}
public void Run()
{
GenerateAllCombinations();
GenerateMatrix();
int[,] m2 = matrix;
for (int i = 0; i < N - 1; i++)
{
m2 = Multiply(m2, matrix);
}
decimal same = m2[0, 0];
decimal total = 0;
for (int i = 0; i < M; i++)
{
total += m2[0, i];
}
Console.WriteLine("For N={0} probability is {1} ({2} / {3})", N, same / total, same, total);
}
private int[,] Multiply(int[,] m2, int[,] m1)
{
int[,] ret = new int[M, M];
for (int ii = 0; ii < M; ii++)
{
for (int jj = 0; jj < M; jj++)
{
int sum = 0;
for (int k = 0; k < M; k++)
{
sum += m2[ii, k] * m1[k, jj];
}
ret[ii, jj] = sum;
}
}
return ret;
}
private void GenerateMatrix()
{
M = combinations.Count;
matrix = new int[M, M];
for (int i = 0; i < M; i++)
{
matrix[i, i] = N;
for (int j = i + 1; j < M; j++)
{
if (2 == Difference(i, j))
{
matrix[i, j] = 2;
matrix[j, i] = 2;
}
else
{
matrix[i, j] = 0;
}
}
}
}
private int Difference(int x, int y)
{
int ret = 0;
for (int i = 0; i < N; i++)
{
if (combinations[x][i] != combinations[y][i])
{
ret++;
}
if (ret > 2)
{
return int.MaxValue;
}
}
return ret;
}
private void GenerateAllCombinations()
{
int placeAt = 0;
bool doRun = true;
while (doRun)
{
doRun = false;
bool created = false;
for (int i = placeAt; i < N; i++)
{
for (int j = lastItemIdx[i] + 1; j < N; j++)
{
lastItemIdx[i] = j; // remember the test
if (comb.Contains(j))
{
continue; // tail items should be nulled && their lastItemIdx set to -1
}
// success
placeAt = i;
comb[i] = j;
created = true;
break;
}
if (comb[i] == -1)
{
created = false;
break;
}
}
if (created)
{
combinations.Add(new List<int>(comb));
}
// rollback
bool canGenerate = false;
for (int k = placeAt + 1; k < N; k++)
{
lastItemIdx[k] = -1;
}
for (int k = placeAt; k >= 0; k--)
{
placeAt = k;
comb[k] = -1;
if (lastItemIdx[k] == N - 1)
{
lastItemIdx[k] = -1;
continue;
}
canGenerate = true;
break;
}
doRun = canGenerate;
}
}
}
问题:数组A保持不变的概率是多少?条件:假设数组包含唯一元素。
尝试使用Java解决方案。
随机交换发生在原始int数组上。在java方法中,参数始终按值传递,因此在swap方法中发生的情况无关紧要,因为数组的a [m]和a [n]元素(从下面的代码swap(a [m],a [n]))是传递的数组不完整。
答案是数组将保持不变。尽管有上述条件。参见下面的Java代码示例:
import java.util.Random;
public class ArrayTrick {
int a[] = new int[10];
Random random = new Random();
public void swap(int i, int j) {
int temp = i;
i = j;
j = temp;
}
public void fillArray() {
System.out.println("Filling array: ");
for (int index = 0; index < a.length; index++) {
a[index] = random.nextInt(a.length);
}
}
public void swapArray() {
System.out.println("Swapping array: ");
for (int index = 0; index < a.length; index++) {
int m = random.nextInt(a.length);
int n = random.nextInt(a.length);
swap(a[m], a[n]);
}
}
public void printArray() {
System.out.println("Printing array: ");
for (int index = 0; index < a.length; index++) {
System.out.print(" " + a[index]);
}
System.out.println();
}
public static void main(String[] args) {
ArrayTrick at = new ArrayTrick();
at.fillArray();
at.printArray();
at.swapArray();
at.printArray();
}
}
样本输出:
填充阵列:打印阵列:3 1 1 4 9 7 9 5 9 5交换阵列:打印阵列:3 1 1 4 9 7 9 5 9 5
swap
N固定种子和固定种子,概率为0或,1因为它根本不是随机的。