我和我的朋友进行了这次讨论,他在面试中向他询问了这个问题。问题是这样的。写一个函数,它接受一个字节数组(2维)作为输入和一个整数n,初始假设是M * N字节数组的所有元素都是零,问题是用值填充'n'字节数组元素1,例如,如果M = 5且N = 5且n值为10,则字节数组应为10/25个元素为1,其余15个值为0.填充值应为随机且一个单元格在字节数组中应该只填充一次。我很着迷尝试自己解决这个问题。我附上了迄今为止我提出的代码。
public Boolean ByteArrayFiller(int a,int b, int n)
{
int count = n;
int iLocalCount = 0;
byte[,] bArray= new byte[a,b];
for (int i = 0; i <a; i++)
for (int j = 1; j <b; j++)
bArray[i, j] = 0;
Random randa= new Random();
int iRandA = randa.Next(a);
int iRandB = randa.Next(b);
while (iLocalCount < n)
{
if (bArray[iRandA, iRandB] == 0)
{
bArray[iRandA, iRandB] = 1;
iLocalCount++;
}
iRandA = randa.Next(a);
iRandB = randa.Next(b);
continue;
}
//do
//{
// //iRandA = randa.Next(a);
// //iRandB = randa.Next(b);
// bArray[iRandA,iRandB]=1;
// iLocalCount++;
//} while (iLocalCount<=count && bArray[iRandA,iRandB]==0);
return true;
}
我写的代码是在C#中,但它很容易理解。它能够完成问题的目的(我做了一些试运行并且结果正确地完成了)但我在C#中使用了Random对象(相当于Java中的Math.Rand)来填充字节数组,我一直在想Rand为a和b返回相同的值。这是一个很好的机会无限期地去。这是问题的目的吗?或者我为这个问题提出的解决方案是否足够好!
我很想知道这里的专家如何解决这个问题?我只是在寻找新的想法来拓展我的视野。任何指针都将非常感激。感谢您抽出宝贵时间阅读这篇文章!
答案 0 :(得分:3)
尝试随机位置的while循环直到找到一个好位置通常是一种非常糟糕的方法。如果n = M * N,则最后一个将具有找到匹配的1 /(M * N)的概率。如果M * N足够大,则效率极低。
如果M * N不是太大,我会创建一个M * N大小的临时数组,用数字0到(M * N)-1填充它,然后置换它 - 即你走过它并且将当前值与随机其他值交换。
然后转到数组中的前n个元素并设置适当的单元格。 (row = value / columns,col = value%columns)。
答案 1 :(得分:2)
我会将逻辑上的数组视为一维数组。用规定的值填充前n
个位置,然后将阵列洗牌。
给定一个字节数组,以及数组中的行数和列数,并假设该数组已经用0填充:
int NumElements = NumRows * NumCols;
for (int i = 0; i < NumElementsToFill; ++i)
{
int row = i / NumRows;
int col = i % NumCols;
array[row, col] = 1;
}
// Now shuffle the array
Random rnd = new Random();
for (int i = 0; i < NumElements; ++i)
{
int irow = i / NumRows;
int icol = i % NumCols;
int swapWith = rnd.Next(i+1);
int swapRow = swapWith / NumRows;
int swapCol = swapWith % NumCols;
byte temp = array[irow, icol];
array[irow, icol] = array[swapRow, swapCol];
array[swapRow, swapCol] = temp;
}
这里的关键是将一维索引转换为行/列值。我使用了/
和%
。您也可以使用Math.DivRem
。或者创建为您设置get和set的Action
方法。
答案 2 :(得分:0)
选择一个数字,该数字大于N和M并且是素数(或者是N和M的共同素数)。我们将此号码称为p
。
循环,直到您设置x
个数字:
这种方法的缺点是如果阵列填满,你将会有更多的碰撞。
答案 3 :(得分:0)
基本上,您需要从范围[0,p)(其中p = M * N)中选择n个唯一的随机数,并将它们映射到二维数组的位置。
天真的方法是1)通过重试生成非唯一数字2)用0到p-1之间的数字填充数组,将其洗牌并取前n个数字(需要O(p)时间,O(p)内存)
另一种方法是使用以下算法(O(n 2 )时间,O(n)内存,Java代码)选择它们:
public Set<Integer> chooseUniqueRandomNumbers(int n, int p) {
Set<Integer> choosen = new TreeSet<Integer>();
Random rnd = new Random();
for (int i = 0; i < n; i++) {
// Generate random number from range [0, p - i)
int c = rnd.nextInt(p - i);
// Adjust it as it was choosen from range [0, p) excluding already choosen numbers
Iterator<Integer> it = choosen.iterator();
while (it.hasNext() && it.next() <= c) c++;
choosen.add(c);
}
return choosen;
}
将生成的数字映射到二维数组的位置是微不足道的。