繁体   English   中英

向左拉数组中的所有非零元素-C#

[英]pull all non-zero elements in an array to the left - c#

如果我有以下数组

{ 1, 0, 0, 1, 2, 0, 1 }

我想要一个方法,它将采用数组并将其更改为

{ 1, 1, 2, 1, 0, 0, 0 }

做到这一点的最佳算法是什么? 是否可以在O(N)时间执行此操作?

这个问题本质上是我的确切问题,但在python而非c#中除外,以防我不清楚:(唯一的区别是将零移动到右边,而不是左边) 如何将python列表或numpy数组中的所有非零元素移动到一边?

谢谢

编辑:我遇到了另一个我最初没有考虑的问题。 我实际上正在尝试在2d数组上运行此算法,但仅在一个特定维度上运行。 我将如何解决这个问题?

可以在O(n)时间和O(1)空间复杂度中做到这一点。
从低指针到0开始,高指针从数组的最后一个索引开始。
算法
1.递减直到找到0,递减直到找到非零数字。
2.交换Array [low]和Array [high]。
3.重复步骤1和2,直到低电平小于高电平为止。

二维阵列更新

int[,] array = 
{
    { 1, 0, 0, 1, 2, 0, 1 }, // Row 0
    { 1, 0, 0, 1, 2, 0, 1 }, // Row 1
    { 1, 0, 0, 1, 2, 0, 1 }  // Row 2
};

PullNonZerosToLeft(array, 1);

for (int row = 0; row <= array.GetUpperBound(0); row++)
{
    for (int col = 0; col <= array.GetUpperBound(1); col++)
    {
        Console.Write("{0} ", array[row,col]);
    }
    Console.WriteLine();
}

PullNonZerosToLeft()

public static void PullNonZerosToLeft(int[,] array, int row)
{
    if (row > array.GetUpperBound(0))
    {
        return;
    }

    // Used to keep track of the swap point
    int index = 0;
    for (int i = 0; i <= array.GetUpperBound(1); i++)
    {
        if (array[row, i] == 0)
        {
            continue;
        }

        int temp = array[row, i];
        array[row, i] = array[row, index];
        array[row, index] = temp;
        index++;
    }
}

结果:

1 0 0 1 2 0 1
1 2 1 1 0 0 0
1 0 0 1 2 0 1

更新了杂乱的阵列

一种非Linq方法,其中您将所有非零元素交换为零元素。

int[][] array = 
{
    new[] { 1, 0, 0, 1, 2, 0, 1 }, // Row 0
    new[] { 1, 0, 0, 1, 2, 0, 1 }, // Row 1
    new[] { 1, 0, 0, 1, 2, 0, 1 }  // Row 2
};

PullNonZerosToLeft(array, 1);

foreach (int[] row in array)
{
    Console.WriteLine(String.Join(", ", row));
}

PullNonZerosToLeft()

public static void PullNonZerosToLeft(int[][] array, int row)
{
    if (row >= array.Length)
    {
        return;
    }

    // Used to keep track of the swap point
    int index = 0;
    for (int i = 0; i < array[row].Length; i++)
    {
        if (array[row][i] == 0)
        {
            continue;
        }

        int temp = array[row][i];
        array[row][i] = array[row][index];
        array[row][index] = temp;
        index++;
    }
}

结果:

1, 0, 0, 1, 2, 0, 1
1, 1, 2, 1, 0, 0, 0
1, 0, 0, 1, 2, 0, 1

这是您可以做到的方式。

var original = new int[] { 1, 0, 0, 1, 2, 0, 1 };
var nonZeroes = original.Where(x => x != 0); //enumerate once
var numberOfZeroes = original.Count() - nonZeroes.Count(); 
return nonZeroes.Concat(Enumerable.Repeat(0, numberOfZeroes)).ToArray();

您可以按n == 0排序。

var original = new int[] { 1, 0, 0, 1, 2, 0, 1 };
var result = original.OrderBy(n => n == 0).ToArray();

这是通过创建新数组在O(n)时间内完成此操作的方法。 请注意,这避免了第二次遍历数组以获取零计数的麻烦,就像Dleh的回答一样。

public static int[] PushNonZeroToLeft(int[] aiArray)
{
    var alNew = new List<int>();
    var iZeroCount = 0;

    foreach (int i in aiArray)
        if (i > 0)
            alNew.Add(i);
        else
            iZeroCount++;

    alNew.AddRange(Enumerable.Repeat(0, iZeroCount));

    return alNew.ToArray();
}

如果必须对原始数组进行突变,则不确定是否可以实现O(n)。

这是一个O(n)时间,O(1)空间算法,可用于执行您想要的操作。 它还将保留非零元素的顺序。

var array = new []{ 1, 3, 3, 1, 2, 0, 1 };
int j = 0;
for( int i = 0; i < array.Length && j < array.Length; ++i )
{
    if( array[i] != 0 ) continue;

    if( j <= i ) j = i + 1;

    while( j < array.Length && array[j] == 0 ) ++j;

    if( j >= array.Length ) break;

    var t = array[i];
    array[i] = array[j];
    array[j] = t;
}

这就是我的处理方式。 漂亮又简单。 我没有进行性能测试,但是希望它比使用LINQ或创建新阵列的一些建议具有更高的性能。

int[] array = { 1, 0, 0, 1, 2, 0, 1 };

for (int i = 0; i < array.Length; i++)
{
    if (array[i] == 0)
    {
        int j;

        for (j = i + 1; j < array.Length; j++)
        {
            if (array[j] != 0)
                break;
        }

        if (j < array.Length)
        {
            array[i] = array[j];
            array[j] = 0;
        }
        else break;
    }
}

是的,这可以在O(N)时间内完成。

基本上:

  1. 遍历数组
  2. 对于您发现的每个非零元素,将其复制
    • 应该将第一个元素复制到位置0,然后复制到位置1,依此类推。跟踪该位置的作用。
  3. 遍历整个数组后,请遍历数组的其余部分,直到您到达末尾为止,然后将位置设置为零。

该算法将复制 ,而不是move ,因此上面的第三点将确保我们复制但随后没有覆盖的所有元素将在之后被清零。

这是一些示例代码:

int next = 0;

// copy all non-zero elements to the start
foreach (var element in collection)
    if (element != 0)
        collection[next++] = element;

// fill remainder with zeroes
while (next < collection.Count)
    collection[next++] = 0;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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