If I have the following array
{ 1, 0, 0, 1, 2, 0, 1 }
And I want a method that will take the array and change it to
{ 1, 1, 2, 1, 0, 0, 0 }
What would be the best algorithm to do this? Is it possible to do this in O(N) time?
this question is essentially my exact question except in python not c#, in case I was not clear: (only difference is move the zeros to the right, not left) how to move all non-zero elements in a python list or numpy array to one side?
Thanks
EDIT: I've ran into another problem that I didn't consider at first. I'm actually trying to run this algorithm on a 2d array, but only on one particular dimension. how would I change to account for this?
It is possible to do it in O(n) time and O(1) space complexity.
Start with a low pointer at 0 and a high pointer at last index of the array.
Algorithm :
1. Increment low till you find 0, decrement high till you find a non-zero number.
2. Swap Array[low] and Array[high].
3. Repeat steps 1 and 2 till low is less than high.
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++;
}
}
Results:
1 0 0 1 2 0 1
1 2 1 1 0 0 0
1 0 0 1 2 0 1
A non- Linq
approach, where you swap all non-zero elements with zero elements.
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++;
}
}
Results:
1, 0, 0, 1, 2, 0, 1
1, 1, 2, 1, 0, 0, 0
1, 0, 0, 1, 2, 0, 1
Here's a way you could do it.
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();
You can just order by n == 0
.
var original = new int[] { 1, 0, 0, 1, 2, 0, 1 };
var result = original.OrderBy(n => n == 0).ToArray();
Here's a way to do it in O(n) time by creating a new array. Note that this avoids the penalty of looping through the array a second time to get the count of zeros, as in Dleh's answer.
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();
}
Not sure if O(n) can be achieved if you have to mutate the original array...
Here's an O(n) time, O(1) space algorithm for doing what you want. It will also preserve the order of the non-zero elements.
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;
}
This is how I'd approach it. Nice and simple. I didn't run performance tests but would expect it to be a little more performant than some of the suggestions that use LINQ, or create new arrays.
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;
}
}
Yes, this is possible to do in O(N) time.
Basically:
The algorithm will copy , not move , so the 3rd point above will make sure any elements we copied but did not subsequently overwrite will be zeroed out afterwards.
Here's some example code:
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;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.