如果我有以下数组
{ 1, 0, 0, 1, 2, 0, 1 }
我想要一个采用数组并将其更改为
的方法{ 1, 1, 2, 1, 0, 0, 0 }
这样做的最佳算法是什么?是否可以在O(N)时间内完成这项工作?
这个问题基本上是我的确切问题,除了在python而不是c#中,如果我不清楚:(唯一的区别是向右移动零,而不是左边) how to move all non-zero elements in a python list or numpy array to one side?
由于
编辑:我遇到了另一个我最初没有考虑过的问题。我实际上试图在二维数组上运行此算法,但仅限于一个特定维度。我将如何更改为此?答案 0 :(得分:2)
可以在O(n)时间和O(1)空间复杂度下进行
从低指针开始,在数组的最后一个索引处有一个高指针
的算法强>:
1.递减低直到找到0,递减高,直到找到非零数字
2.交换数组[低]和数组[高]。
3.重复步骤1和2,直到低于低。
答案 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
答案 2 :(得分: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();
答案 3 :(得分:0)
您可以按n == 0
订购。
var original = new int[] { 1, 0, 0, 1, 2, 0, 1 };
var result = original.OrderBy(n => n == 0).ToArray();
答案 4 :(得分:0)
这是通过创建新数组在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)...
答案 5 :(得分:0)
这是一个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;
}
答案 6 :(得分:0)
这就是我接近它的方式。很好,很简单。我没有运行性能测试,但希望它比使用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;
}
}
答案 7 :(得分:-1)
是的,这可以在O(N)时间内完成。
基本上:
算法将复制,而不是移动,因此上面的第3点将确保我们复制但未随后覆盖的任何元素将在之后归零。
以下是一些示例代码:
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;