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
Related
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;
}
Let's say I have an array like this :
9 1 2 0
1 5 2 5
7 1 6 3
4 3 2 7
I want to be able to create a loop that goes through the array vertically and horizontally to see if there's any duplicates.
For example, it will first check 9 1 7 4 to see if there's a dups. Then 1 5 1 3 and so on.
After that, it'll do 9 1 2 0 (which will tell me there's a dup), then 1 5 2 5 7, etc etc.
How can I do that?
While possible, a nested loops solution may not be the more straightforward way of solving it. In this case, using LINQ is must easier :
var matrix = new int[4, 4]
{
{ 9, 1, 2, 0 },
{ 1, 5, 2, 5 },
{ 7, 1, 6, 3 },
{ 4, 3, 2, 7 }
};
for (int i = 0; i < 4; i++)
{
var row = Enumerable.Range(0, 4).Select(x => matrix[i, x]);
if (row.Distinct().Count() != 4)
Console.WriteLine("Duplicated value in row {0} : {1}",
i + 1, string.Join(", ", row));
}
for (int i = 0; i < 4; i++)
{
var column = Enumerable.Range(0, 4).Select(x => matrix[x, i]);
if (column.Distinct().Count() != 4)
Console.WriteLine("Duplicated value in column {0} : {1}",
i + 1, string.Join(", ", column));
}
Output :
Duplicated value in row 2 : 1, 5, 2, 5
Duplicated value in column 2 : 1, 5, 1, 3
Duplicated value in column 3 : 2, 2, 6, 2
I have gotten a working solution using nested For Loops. This will write "Nothing" to the console when the index used to check(horizontal or vertical) is zero to avoid an ArrayIndexOutOfBoundsException. It writes "Duplicate No." and then the number that was duplicate to the console. I have posted my full working example below along with the output from console:
For horizontal:
int[,] array = new int[5, 4] { { 1, 2, 3, 4 }, { 5, 5, 5, 5 }, { 9, 5, 11, 12 }, { 13, 14, 15, 16 }, { 17, 18, 19, 20 } } ;
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
if (j == 0)
{
Console.WriteLine("Nothing");
}
else if (array[i, j] == array[i, j - 1])
{
Console.WriteLine("Duplicate No." + array[i, j].ToString());
}
}
}
For vertical:
for (int i = 0; i < array.GetLength(1); i++)
{
for (int j = 0; j < array.GetLength(0); j++)
{
if (j == 0)
{
Console.WriteLine("Nothing");
}
else if (array[j, i] == array[j - 1, i])
{
Console.WriteLine("Duplicate No." + array[i, j].ToString());
}
}
}
Output from both horizontal and vertical:
Nothing
Nothing
Duplicate No. 5
Duplicate No. 5
Duplicate No. 5
Nothing
Nothing
Nothing
Nothing
Nothing
Duplicate No. 5
Nothing
Nothing
I create a class that allow you to enumerate through the array
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication88
{
class Program
{
static void Main(string[] args)
{
EnumerateArray eArray = new EnumerateArray() {
new List<int>() {1,2,3,4},
new List<int>() {5,6,7,8},
new List<int>() {9,10,11,12},
new List<int>() {13,14,15,16},
new List<int>() {17,18,19,20}
};
foreach (List<int> x in eArray)
{
Console.WriteLine(string.Join(",", x.Select(y => y.ToString()).ToArray()));
}
Console.ReadLine();
}
}
public class EnumerateArray : IEnumerator, IEnumerable
{
public List<List<int>> myArray { get; set;}
int row = 0;
int col = 0;
int numCols = 0;
int numRows = 0;
public int Count { get; set; }
public int[] current = null;
Boolean finishedCol = false;
public EnumerateArray()
{
myArray = new List<List<int>>();
}
public EnumerateArray(List<List<int>> array)
{
myArray = array;
Reset();
numRows = array.Count;
numCols = array[0].Count;
Count = numCols + numRows;
}
public void Add(List<int> array)
{
myArray.Add(array);
numRows = myArray.Count;
numCols = array.Count;
Count = numCols + numRows;
}
public void Add(List<List<int>> array)
{
myArray = array;
Reset();
numRows = array.Count;
numCols = array[0].Count;
Count = numCols + numRows;
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
public EnumerateArray GetEnumerator()
{
return new EnumerateArray(myArray);
}
public bool MoveNext()
{
Boolean done = true;
if (finishedCol == false)
{
if (col < numCols - 1)
{
col++;
}
else
{
finishedCol = true;
row = 0;
}
}
else
{
if (row < numRows - 1)
{
row++;
}
else
{
done = false;
}
}
return done;
}
public void Reset()
{
row = -1;
col = -1;
finishedCol = false;
Count = numCols + numRows;
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public List<int> Current
{
get
{
try
{
List<int> _array = new List<int>();
if (finishedCol == false)
{
for (int _row = 0; _row < numRows; _row++)
{
_array.Add(myArray[_row][ col]);
}
}
else
{
_array.AddRange(myArray[row]);
}
return _array;
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
}
}
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;
I am trying to solve my task using a List and I know I am very close to solving it but I am stuck now. Something is not ok in the code and I can not figure out what it is. Could you please take a look and help:
/*
Write a program that reads an array of integers and removes from it a minimal number of elements in such way that the
remaining array is sorted in increasing order. Print the remaining sorted array.
Example: {6, 1, 4, 3, 0, 3, 6, 4, 5} {1, 3, 3, 4, 5}
*/
using System;
using System.Collections.Generic;
class RemoveMinimalElements
{
static void Main()
{
int n;
n = int.Parse(Console.ReadLine());
List<int> arr = new List<int>();
List<int> sorted = new List<int>();
int maxSubsetLenght = 0;
for (int i = 0; i < n; i++)
{
arr.Add(int.Parse(Console.ReadLine()));
}
for (int i = 1; i <= (int)Math.Pow(2, n) - 1; i++)
{
int tempSubsetLenght = 0;
string tempString = "";
List<int> temp = new List<int>();
for (int j = 1; j <= n; j++)
{
int andMask = i & (1 << j);
int bit = andMask >> j;
if (bit == 1)
{
temp.Add(arr[n - 1 - j]);
tempSubsetLenght++;
}
if (tempSubsetLenght > maxSubsetLenght)
{
maxSubsetLenght = tempSubsetLenght;
for(int k =1; k < temp.Count; k ++)
{
if (temp[k] >= temp[k - 1])
{
sorted = temp;
}
}
}
}
}
for (int i = sorted.Count - 1; i > 0; i--)
{
Console.WriteLine(sorted[i]);
}
}
}
I didn't follow the code, I just tested your app.
This is my first input: 5.
Then I entered these 5 inputs 2,4,6,8,10 so
arr = {2,4,6,8,10};
And when it came to the last lines it gave me the ArguementOutOfRangeException (Index was out of range. Must be non-negative and less than the size of the collection.) because it was trying to fetch arr[item] and item is 6 so it's trying to fetch arr[6] which does not exist.
I don't know if an exhaustive search is suitable for your case, but will this work for you?
static void Main(string[] args)
{
int[] input = new[] { 6, 1, 4, 3, 0, 3, 6, 4, 5 };
int[] expectedOutput = new[] { 1, 3, 3, 4, 5 };
int[] solution = TryGetSolution(input);
Console.WriteLine("Input: " + FormatNumbers(input));
Console.WriteLine("Expected Output: " + FormatNumbers(expectedOutput));
Console.WriteLine("Output: " + FormatNumbers(solution));
Console.ReadLine();
}
private static string FormatNumbers(int[] numbers)
{
return string.Join(", ", numbers);
}
private static int[] TryGetSolution(int[] input)
{
return TryWithoutAnyItem(input);
}
private static int[] TryWithoutAnyItem(int[] items)
{
return Enumerable.Range(0, items.Length)
.Select(i => TryWithoutItem(items, i))
.Where(solution => solution != null)
.OrderByDescending(solution => solution.Length)
.FirstOrDefault();
}
private static int[] TryWithoutItem(int[] items, int withoutIndex)
{
if (IsSorted(items)) return items;
var removed = items.Take(withoutIndex).Concat(items.Skip(withoutIndex + 1));
return TryWithoutAnyItem(removed.ToArray());
}
private static bool IsSorted(IEnumerable<int> items)
{
return items.Zip(items.Skip(1), (a, b) => a.CompareTo(b)).All(c => c <= 0);
}
}
I solved it! Thank you very much for your support. I am a beginer and I am not able to use and understand more difficult stuff yet so here is what I did whit the things I already know:
/*
Write a program that reads an array of integers and removes from it a minimal number of elements in such way that the
remaining array is sorted in increasing order. Print the remaining sorted array.
Example: {6, 1, 4, 3, 0, 3, 6, 4, 5} {1, 3, 3, 4, 5}
*/
using System;
using System.Collections.Generic;
class RemoveMinimalElements
{
static bool CheckAscending(List<int> list)
{
bool ascending = true;
for (int i = 0; i < list.Count - 1; i++)
{
if (list[i] > list[i + 1])
{
ascending = false;
}
}
return ascending;
}
static void Main()
{
int n;
n = int.Parse(Console.ReadLine());
List<int> arr = new List<int>();
List<int> sorted = new List<int>();
int maxSubsetLenght = 0;
for (int i = 0; i < n; i++)
{
arr.Add(int.Parse(Console.ReadLine()));
}
for (int i = 1; i <= (int)Math.Pow(2, n) - 1; i++)
{
int tempSubsetLenght = 0;
List<int> temp = new List<int>();
for (int j = 1; j <= n; j++)
{
if (((i >> (j - 1)) & 1) == 1)
{
temp.Add(arr[j - 1]);
tempSubsetLenght++;
}
}
if ((tempSubsetLenght > maxSubsetLenght) && (CheckAscending(temp)))
{
sorted = temp;
maxSubsetLenght = tempSubsetLenght;
}
}
for (int i = 0; i < sorted.Count; i++)
{
Console.WriteLine(sorted[i]);
}
}
}
This works for me
private static void FindLongestRisingSequence(int[] inputArray)
{
int[] array = inputArray;
List<int> list = new List<int>();
List<int> longestList = new List<int>();
int highestCount = 1;
for (int i = 0; i < array.Length; i++)
{
list.Add(array[i]);
for (int j = i+1; j < array.Length; j++)
{
if (array[i] < array[j])
{
list.Add(array[j]);
i++;
}
else
{
break;
}
i = j;
}
// Compare with in previous lists
if (highestCount < list.Count)
{
highestCount = list.Count;
longestList = new List<int>(list);
}
list.Clear();
}
Console.WriteLine();
// Print list
Console.WriteLine("The longest subsequence");
foreach (int iterator in longestList)
{
Console.Write(iterator + " ");
}
Console.WriteLine();
}
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;
}
}