[英]Byte Array Manipulation - Interview Question
我正在和我的朋友讨论,他在面试中问了这个问题。 问题是这样的。 编写一个函数,该函数将一个字节数组(二维)与一个整数n一起作为输入,初始假设是M * N字节数组的所有元素均为零,而问题是用值填充'n'个字节数组元素1,例如,如果M = 5和N = 5,并且n值为10,则Byte数组应将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)来填充字节数组,因此我一直在思考是否兰德对于a和b返回相同的值。 这很有可能无限期地进行下去。 这是问题的目的吗? 或我针对这个问题提出的解决方案是否足够好!
我很好奇,这里的专家如何解决这个问题? 我只是在寻找新的想法来扩大我的视野。 任何指针将不胜感激。 感谢您抽出宝贵的时间阅读这篇文章!
一个while循环尝试随机的位置,直到找到一个好的位置,通常是一个非常糟糕的方法。 如果n = M * N,则最后一个找到匹配项的概率为((M * N))。 如果M * N足够大,则效率极低。
如果M * N不太大,我将创建一个M * N大小的临时数组,用数字0到(M * N)-1进行填充,然后对其进行置换-即遍历它并交换当前值与其他随机值。
然后,转到数组中的前n个元素并设置适当的单元格。 (行=值/列,列=值%列)。
从逻辑上讲,我会将数组视为一维数组。 用指定的值填充前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
。 或创建为您进行获取和设置的Action
方法。
选择一个大于N和M且为素数(或对N和M均为互质数)的数字。 我们称这个数字为p
。
循环直到您设置了x
数字:
这种方法的缺点是,如果数组已满,则将发生更多冲突。
基本上,您需要从[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;
}
将生成的数字映射到二维数组的位置很简单。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.