繁体   English   中英

字节数组操作-面试问题

[英]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数字:

  1. 生成小于N * M的随机数。 将此号码称为“ l”。
  2. 如果尚未设置该位置,则下一个放置数字的位置将是“ p * l%(N * M)”。

这种方法的缺点是,如果数组已满,则将发生更多冲突。

基本上,您需要从[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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM