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?
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();
UPDATED FOR 2D ARRAY
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
UPDATED FOR JAGGED ARRAY
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
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.
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:
Loop through the array
For every element you find that is non-zero, copy it
First element should be copied to position 0, next to position 1, etc. Keep track of how far you get with this position.
When you've looped through it, iterate the position you kept track of through the rest of the array until you reach the end, and keep setting elements to zero as you go.
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;
Related
Let's say i have an array of 6 elements of int type.
It looks like this
var array = new int [] { 0, 1, 2, 3, 4, 5 };
How can I randomly shuffle my array ensuring every index have a new value.
// Bad
// The number at index 3 did not change and still has a value of 3
new int [] { 1, 0, 5, 3, 2, 4 }
// Good:
// All the index have a new value
new int [] { 4, 2, 0, 5, 3, 1 }
I've tried to Shuffle, but sometimes some values will have the same index position
You could iterate over the array and always swap with a randomly choosen index which is bigger than the current one. That way the numbers get shuffled, but no element can be shuffled back.
Edit: This acutally works, try it:
using System;
class Program {
private static Random rnd = new Random();
public static void Main() {
for (var i = 0; i < 10000; i++) {
int[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Shuffle(array);
Console.WriteLine(String.Join(", ", array));
}
}
public static void Shuffle(int[] array) {
for (var i = 0; i + 1 < array.Length; i++) {
// generate j so that i < j < length
int j = rnd.Next(i + 1, array.Length);
// swap elements at i and j
var tmp = array[j];
array[j] = array[i];
array[i] = tmp;
// check
if (array[i] == i) {
throw new Exception(":(");
}
}
}
}
Also its very similar to Sattolo's algorithm, which would also work.
The wished output is a lot of array that looks like this:
public decimal [] array 1 = {1, 1, 0, 0, 0};
public decimal [] array 2 = {0, 1, 1, 0, 0};
public decimal [] array 3 = {0, 0, 1, 1, 0};
public decimal [] array 4 = {0, 0, 0, 1, 1};
The dimension does not fit my problem, because the problem demands a array of 14 elements, but the idear is the same. The question is how do I create this in a smart way. I tried a "for loop" creating array 1, but as the loop carried on it overwrote array 1 with array 2:
class Program
{
public decimal[] array_1 = { 0, 0, 0, 0, 0 };
public void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
if (i == 0)
{
array_1 [i] = 1;
array_1 [i + 1] = 1;
}
else if (i == 1)
{
array_1[i] = 1;
array_1[i + 1] = 1;
}
else if (i == 2)
{
array_1[i] = 1;
array_1[i + 1] = 1;
}
else if (i == 3)
{
array_1[i] = 1;
array_1[i + 1] = 1;
}
else if (i == 4)
{
array_1[i] = 1;
array_1[i + 1] = 1;
}
}
}
}
The output of the above is a array with only ones and not four different arrays as firstly wished.
decimal[][] arrays = { array_1, array_2, array_3, array_4 };
for (int a = 0; a < arrays.Length; a++) {
for (int i = 0; i < arrays[a].Length; i++) {
arrays[a][i] = i == a || i == a+1 ? 1 : 0;
}
}
Or, you can create one two-dimensional array:
decimal[,] array = new decimal[4, 5];
for (int row = 0; row < array.GetLength(0); row++) {
for (int column = 0; column < array.GetLength(1); column++) {
array[row, column] = column == row || column == row+1 ? 1 : 0;
}
}
Use multidimensional array:
class Program
{
public decimal[,] arrayObj = new decimal[5, 5];
public void Main(string[] args)
{
for (int i = 0; i < 4; i++)
{
arrayObj[i][i] = 1;
arrayObj[i+1] = 1;
}
}
If you want a collection (say, decimal[][] - jagged array) of arrays, I suggest using Linq:
int n = 4;
decimal[][] arrays = Enumerable.Range(1, n)
.Select(index => Enumerable
.Range(1, n + 1)
.Select(x => (decimal) (x == index || x == index + 1 ? 1 : 0))
.ToArray())
.ToArray();
and then use the collection
decimal array1 = arrays[0];
Test
string report = string.Join(Environment.NewLine, arrays
.Select(array => string.Join(" ", array)));
Outcome:
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
If you insist on 2d array:
int n = 4;
decimal[,] arrays = new decimal[n, n + 1];
for (int i = 0; i < arrays.GetLength(0); ++i) {
arrays[i, i] = 1;
arrays[i, i + 1] = 1;
}
I have the following solution for 3-sum. I use bin search to find all unique triplets in the array which gives the sum of zero.
public List<List<int>> ThreeSum(int[] nums)
{
Array.Sort(nums);
var res = new List<List<int>>();
for(int i = 0; i < nums.Length; ++i)
{
for(int j = i+1; j < nums.Length; ++j)
{
if(nums[i] == nums[j]) { ++i; }
int c = Array.BinarySearch(nums, -nums[i] - nums[j]);
if(c > j)
{
res.Add(new List<int> { nums[i], nums[j], nums[c] });
}
}
}
return res;
}
It works fine, but I don't know how to fix bugs when input is:
[0,0,0] or [0,0,0,0]
Input:
[0,0,0]
Output:
[]
Expected:
[[0,0,0]]
Updated
Try overloaded version of Array.BinarySearch that takes index of start element and length of elements in the interested range. I.e. you need to find such element in array nums wich located after j-th element only
Remove if(nums[i] == nums[j]) { ++i; } line. It do almost nothing at corner cases
Update i and j to next non-equal variant of element in corresponding loop.
public class Program
{
static public List<List<int>> ThreeSum(int[] nums)
{
Array.Sort(nums);
var res = new List<List<int>>();
for (int i = 0; i < nums.Length; ++i)
{
for (int j = i + 1; j < nums.Length; ++j)
{
int c = Array.BinarySearch(nums, j + 1, nums.Length - j - 1, -nums[i] - nums[j]);
if (c > j)
{
res.Add(new List<int> { nums[i], nums[j], nums[c] });
}
while (j < nums.Length - 1 && nums[j] == nums[j + 1])
j++;
}
while (i < nums.Length - 1 && nums[i] == nums[i + 1])
i++;
}
return res;
}
static public void printThreeSum(List<List<int>> list)
{
foreach (var item in list)
{
foreach (var t in item)
{
Console.Write(t.ToString() + " ");
}
Console.Write("\n");
}
Console.Write("\n");
}
static void Main(string[] args)
{
printThreeSum(ThreeSum(new int[] { 0, 0, 0 }));
printThreeSum(ThreeSum(new int[] { 0, 0, 0, 0 }));
printThreeSum(ThreeSum(new int[] { 0, 0, 0, 0, 0 }));
printThreeSum(ThreeSum(new int[] { -1, -1, 2 }));
printThreeSum(ThreeSum(new int[] { -1, -1, -1, -1, 2, 2, 2 }));
printThreeSum(ThreeSum(new int[] { -2, -1, -1, 1, 1, 1, 1 }));
printThreeSum(ThreeSum(new int[] { -2, -1, 0, 1, 2 }));
}
}
Output:
0 0 0
0 0 0
0 0 0
-1 -1 2
-1 -1 2
-2 1 1
-2 0 2
-1 0 1
P.S. I am not fan of this solution because it is O(N^2 * log(N)) where this task can be solved in O(N^2). I only wanted to correct your code as little as possible
I seem to have trouble converting a character array to a 2D integer array. The specifics are as follows:
I want to convert a character array that contains a specific delimiter to a multidimensional array in which the end of each row is specified by the delimiter found inside the character array ( I have already made sure in a different method that every row has the same length).
The array contains only 0s and 1s.
The problem is that when testing the method it appears that it (the method) skips a row - reads the first row, the next row is 0s, reads the third row, the fourth is 0s.
These are the methods (the method in question and the testing method):
/// <summary>
/// Converts a character array to 2D int array, where each character is a digit and only the digits of 1 and 0 are
/// allowed.
/// </summary>
/// <returns>The 2D int array.</returns>
/// <param name="charArray">Character array.</param>
/// <param name="delimiter">Delimiter.</param>
public int[,] ConvertCharArrayTo2DIntArray(char[] charArray, char delimiter){
int columnCounter = 0;
//count how many rows
while (charArray [columnCounter] != delimiter) {
columnCounter++;
}
//count how many lines taking into account the delimiter
int rows = charArray.Length/(columnCounter+1);
int[,] twoDimArray = new int[rows, columnCounter];
//count
int h = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columnCounter; j++) {
if (charArray [h] != '\n') {
twoDimArray [i, j] = (int)Char.GetNumericValue(charArray [h]);
//throw exception if the array contains numbers other than 1 or 0
if (twoDimArray [i, j] != 1 && twoDimArray [i, j] != 0)
throw new ArgumentException ();
h++;
} else {
h++;
break;
}
}
}
return twoDimArray;
}
This is the testing method:
[Test()]
public void TestConvertCharArrayTo2DIntArray(){
HelperClass hc = new HelperClass ();
int[,] twoDimArrayExpected = new int[,]{
{ 0, 1, 0, 1, 0 },
{ 0, 1, 0, 1, 0 },
{ 0, 1, 0, 1, 0 },
{ 0, 1, 0, 1, 0 } };
char[] charArray = new char[] {'0','1','0','1','1','\n','1','1','1','1','1','\n','0','1','1','1','0','\n','0','1','0','1','0','\n'};
int[,] twoDimArrayActual = hc.ConvertCharArrayTo2DIntArray (charArray, '\n');
for (int i = 0; i < twoDimArrayExpected.GetLength (0); i++) {
for (int j = 0; j < twoDimArrayExpected.GetLength (1); j++) {
Console.Write (twoDimArrayActual [i,j]);
//Commented out because it throws exceptions
//Assert.AreEqual(twoDimArrayExpected[i,j],
//twoDimArrayActual[i,j]);
if (j == twoDimArrayExpected.GetLength (1) - 1) {
Console.Write ("\n");
}
}
}
}
The output is this:
01011
00000
11111
00000
I may simply be stuck, but right now I really can't figure this out.
When the inner loop ends, you are positioned on the delimiter. This is the point where you need to skip the character delimiter incrementing the control variable h
As you do now, you increment the control variable but then you break out of the inner loop. Just removing the break instructon however doesn't work because exiting the inner loop increments the control variable iof the outer loop leaving every even row empty and unprocessed
You could try to fix your code with
int h = 0;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columnCounter; j++)
{
twoDimArray[i, j] = (int)Char.GetNumericValue(charArray[h]);
//throw exception if the array contains numbers other than 1 or 0
if (twoDimArray[i, j] != 1 && twoDimArray[i, j] != 0)
throw new ArgumentException();
h++;
}
h++;
}
Real easy if you use a list object
List<List<int>> twoDimArrayExpected = new List<List<int>>() {
new List<int>() { 0, 1, 0, 1, 0 },
new List<int>(){ 0, 1, 0, 1, 0 },
new List<int>(){ 0, 1, 0, 1, 0 },
new List<int>(){ 0, 1, 0, 1, 0 } };
string resutls = string.Join("\n", twoDimArrayExpected.Select(x => string.Join("", x)));
Say I have a jagged array, and position 2,3 is taken by int 3. Every other spot is filled with int 0. How would I fill all the positions behind 2,3 with a 4?
0 0 0 0 0 0
0 0 0 0
0 0 0 3 0 0
0 0 0 0 0
to this:
4 4 4 4 4 4
4 4 4 4
4 4 4 3 0 0
0 0 0 0 0
Ive tried variations of this:
int a = 2;
int b = 3;
for (int x = 0; x < a; x++)
{
for (int y = 0; y < board.space[b].Length; y++)
{
board.space[x][y] = 4;
}
}
Try this.
private static void ReplaceElements(int[][] array, int x, int y, int newValue)
{
for (int i = 0; i <= x && i < array.Length; i++)
{
for (int j = 0; j < array[i].Length; j++)
{
if (j < y || i < x)
array[i][j] = newValue;
}
}
}
Demo:
int[][] array = new int[4][];
array[0] = new int[] { 0, 0, 0, 0, 0, 0 };
array[1] = new int[] { 0, 0, 0, 0};
array[2] = new int[] { 0, 0, 0, 3, 0, 0};
array[3] = new int[] { 0, 0, 0, 0, 0 };
int x = 2;
int y = 3;
int newValue = 4;
ReplaceElements(array, x, y, newValue);
foreach (int[] inner in array)
{
Console.WriteLine(string.Join(" ", inner));
}
The easiest way would be to have it check if the current element it is on is equal to 3. If it is, stop by altering some control variable, otherwise change the value to 4.
bool done = false;
for (int y = 0; y < board.Size && !done; ++y)
{
for (int x = 0; x < board.space[y].Length && !done; ++y)
{
if (board.space[y][x] == 3) done = true;
else board.space[y][x] = 4;
}
}