I have a one-dimensional array, and I need to run operations on it based on the adjacents cells of every cell.
For instance:
To run the operations on the first cell, I'll need to access the last cell and the second.
The second cell, I'll need to access the first cell and the third cell.
The last cell, I'll need to access the first cell and the one before the last cell.
My code so far is:
public static int[] firstRule(int[] numberArray)
{
for (int i = 0; i < numberArray.Length; i++)
{
if (numberArray[numberArray.Length - 1 - i] == numberArray[i] + 1
&& numberArray[i + 1] == numberArray[i] + 1)
{
numberArray[i] = numberArray[i] - 1;
}
}
return numberArray;
}
But the problem with my approach is that it would only work for the first cell, as it would take the last cell and the second cell correctly, but after that, everything would fall apart. I don't like posting without a lot of code but I have no clue how to follow this up.
I am trying to achieve the following:
Those values are numbers ranging from 0 to 3. If both the cell before and the cell after is the same number, I want to change it to x + 1
For instance: suppose I have 1 0 1 2 2. I would want to change 0 to 1. As the neighbor cells are both 0.
Just keep it simple and use variables to calculate the left and right cell indices. Inside your for loop you can do this...
var leftCell = i - 1;
if (leftCell < 0)
{
leftCell = numberArray.Length - 1; // Wrap around to the end...
}
var rightCell = i + 1;
if (rightCell > numberArray.Length - 1)
{
rightCell = 0; // Wrap back around to the beginning...
}
// Now you can update your original code to use these computed indices...
if (numberArray[leftCell] == numberArray[i] + 1
&& numberArray[rightCell] == numberArray[i] + 1)
{
numberArray[i] = numberArray[i] - 1;
}
Try this out:
var len = numberArray.Length;
for (int i = 0; i < len; i++)
{
var leftIndex = (i - 1 + len) % len;
var rightIndex = (i + 1) % len;
// do your stuff with numberArray[leftIndex] and numberArray[rightIndex]
}
% is mod operator. % len allows you to stay in range 0..len-1, so you can walk through array as if it has become 'cyclic'
From your comments.
Those values are numbers ranging from 0 to 3. If both the cell before and the cell after is the same number, I want to change it to x + 1
For instance: suppose I have 1 0 1 2 2. I would want to change 0 to 1. As the neighbor cells are both 0.
I would create a new array, populate it with the values of the existing array and then change the values of the new array according to the results of the value in the existing array.
Edit as Op is getting wrong values
I suspect you may not be copying the array correctly instead:
Existing Array array // The array you are passing in as parameter.
Declare a new empty array:
int[] newArray;
int size = array.length;
for(int i =1; i<size-1;i++){
if(array[i-1]==array[i+1])){
newArray[i]=array[i]+1;
}
else{
newArray[i]=array[i];
}
}
if(array[size-1]==array[0]){
newArray[size]= array[size]+1;
}
else{
newArray[i]=array[i];
}
if(array [size]==array[1]){
newArray[0]= array[0]+1;
}
else{
newArray[i]=array[i];
}
if there is a limit to the number and it reverts to zero after 2, then just do a simple if test for that.
int[] arr = new int[] { 1, 2, 3, 4, 5 };
var triples = arr.Select((n, i) =>
{
if (i == 0)
return Tuple.Create(arr[arr.Length - 1], arr[0], arr[1]);
else if (i == arr.Length - 1)
return Tuple.Create(arr[i - 1], arr[i], arr[0]);
else
return Tuple.Create(arr[i - 1], arr[i], arr[i + 1]);
});
foreach (var triple in triples)
{
Console.WriteLine(triple.Item1 + " " + triple.Item2 + " " + triple.Item3);
}
public static void firstRule(int[] numberArray)
{
for (int i = 0; i < numberArray.Length; i++)
{
int? prevElement = i == 0
? numberArray[numberArray.Length-1]
: numberArray[i - 1];
int? nextElement = i == numberArray.Length -1
? numberArray[0]
: numberArray[i + 1];
Console.WriteLine(
String.Format("Prev: {0}; Current: {1}; Next: {2}",
prevElement,
numberArray[i],
nextElement)
);
}
}
And then calling firstRule(new int[]{ 1, 2, 3 }); prints:
Prev: 3; Current: 1; Next: 2
Prev: 1; Current: 2; Next: 3
Prev: 2; Current: 3; Next: 1
OPTION 1
assign regardless
public static int[] firstRule(int[] numberArray)
{
int left,right;
for (int i = 0, max = numberArray.Length - 1; i <= max; i++)
{
left = (i == 0) ? max : i - 1;
right = (i == max) ? 0 : i + 1;
numberArray[i] = (numberArray[left] == numberArray[right]) ? numberArray[i] + 1 : numberArray[i]; //always peforms an assignment;
}
return numberArray;
}
OPTION 2
conditionally assign
public static int[] secondRule(int[] numberArray)
{
int left,right;
for (int i = 0, max = numberArray.Length - 1; i <= max; i++)
{
left = (i == 0) ? max : i - 1;
right = (i == max) ? 0 : i + 1;
if (numberArray[left] == numberArray[right])
{
numberArray[i]++;
}
}
return numberArray;
}
OPTION 3
left and right are only used 1 time in each iteration.. so why bother assigning them to a variable???...
public static int[] thirdRule(int[] numberArray)
{
for (int i = 0, max = numberArray.Length - 1; i <= max; i++)
{
if (numberArray[(i == 0) ? max : i - 1] == numberArray[(i == max) ? 0 : i + 1])
{
numberArray[i]++; // what happens if numberArray[i] is 3, should it become 4 or 0?
}
}
return numberArray;
}
OPTION 4 (UNSAFE)
unsafe - fixed - pointers
public static int[] fourthRule(int[] numberArray)
{
unsafe {
int* pointer, right, left;
for (int i = 0, max = numberArray.Length - 1; i <= max; i++)
{
fixed (int* p1 = &numberArray[0], p2 = &numberArray[i], p3 = &numberArray[max])
{
pointer = p2;
if (i == 0)
{
left = p3;
right = pointer;
right++;
}
else if (i == max)
{
left = pointer;
left--;
right = p1;
}
else
{
left = pointer;
left--;
right = pointer;
right++;
}
if (*right == *left) {
*pointer = *pointer + 1;
}
}
}
}
return numberArray;
}
Recently came up against this myself and found this to be a solid method.
`
int length = numberArray.Length;
for (int i = 0; i < length; ++i)
{
int iMinus = (((i - 1) % length) + length) % length;
int iPlus = (((i + 1) % length) + length) % length;
}`
Something like this should work. It determines the appropriate cells for the operation in each loop and executes the operation. You didn't state what that operation was so you need to fill in the DoYourOperation method.
public static int[] processArray(int[] numberArray)
{
for (int i= 0; i < numberArray.Length; i++)
{
int firstCell;
int secondCell;
//Check if first cell
if(i == 0)
{
firstCell = numberArray[numberArray.length-1]; //Last cell
secondCell = numberArray[i++]; //Next cell
}
//Check if last cell
else if(i == numberArray.Length - 1)
{
firstCell = numberArray[i--]; //Cell before last one
secondCell = numberArray[0]; //First cell
}
else
{
firstCell = numberArray[i--];
secondCell = numberArray[i++];
}
DoYourOperation(firstCell, secondCell);
}
}
Related
so i have this function:
static int[] AddArrays(int[] a, int[] b)
{
int length1 = a.Length;
int length2 = b.Length;
int carry = 0;
int max_length = Math.Max(length1, length2) + 1;
int[] minimum_arr = new int[max_length - length1].Concat(a).ToArray();
int[] maximum_arr = new int[max_length - length2].Concat(b).ToArray();
int[] new_arr = new int[max_length];
for (int i = max_length - 1; i >= 0; i--)
{
int first_digit = maximum_arr[i];
int second_digit = i - (max_length - minimum_arr.Length) >= 0 ? minimum_arr[i - (max_length - minimum_arr.Length)] : 0;
if (second_digit + first_digit + carry > 9)
{
new_arr[i] = (second_digit + first_digit + carry) % 10;
carry = 1;
}
else
{
new_arr[i] = second_digit + first_digit + carry;
carry = 0;
}
}
if (carry == 1)
{
int[] result = new int[max_length + 1];
result[0] = 1;
Array.Copy(new_arr, 0, result, 1, max_length);
return result;
}
else
{
return new_arr;
}
}
it basically takes 2 lists of digits and adds them together. the point of this is that each array of digits represent a number that is bigger then the integer limits. now this function is close to working the results get innacurate at certein places and i honestly have no idea why. for example if the function is given these inputs:
"1481298410984109284109481491284901249018490849081048914820948019" and
"3475893498573573849739857349873498739487598" (both of these are being turned into a array of integers before being sent to the function)
the expected output is:
1,481,298,410,984,109,284,112,957,384,783,474,822,868,230,706,430,922,413,560,435,617
and what i get is:
1,481,298,410,984,109,284,457,070,841,142,258,634,158,894,233,092,241,356,043,561,7
i would very much appreciate some help with this ive been trying to figure it out for hours and i cant seem to get it to work perfectly.
I suggest Reverse arrays a and b and use good old school algorithm:
static int[] AddArrays(int[] a, int[] b) {
Array.Reverse(a);
Array.Reverse(b);
int[] result = new int[Math.Max(a.Length, b.Length) + 1];
int carry = 0;
int value = 0;
for (int i = 0; i < Math.Max(a.Length, b.Length); ++i) {
value = (i < a.Length ? a[i] : 0) + (i < b.Length ? b[i] : 0) + carry;
result[i] = value % 10;
carry = value / 10;
}
if (carry > 0)
result[result.Length - 1] = carry;
else
Array.Resize(ref result, result.Length - 1);
// Let's restore a and b
Array.Reverse(a);
Array.Reverse(b);
Array.Reverse(result);
return result;
}
Demo:
string a = "1481298410984109284109481491284901249018490849081048914820948019";
string b = "3475893498573573849739857349873498739487598";
string c = string.Concat(AddArrays(
a.Select(d => d - '0').ToArray(),
b.Select(d => d - '0').ToArray()));
Console.Write(c);
Output:
1481298410984109284112957384783474822868230706430922413560435617
I've got a 2 Dimensional array, which stores fields of a chessboard..
private field[,] board = new field[boardsize,boardsize];
..now when I initialize them I want to reference to the neighbours of every field, which are partly not initilized yet.
At the moment a use a work-around like this:
for(int x = 0; x < boardsize ; x++)
{
for(int y = 0; y < boardsize ; y++)
{
board[x,y] = new field();
}
}
for(int x = 0; x < boardsize ; x++)
{
for(int y = 0; y < boardsize ; y++)
{
board[x,y].setNeighbours(x, y, board);
}
}
This works fine but I'm interested if its possible to set the neighbours before or at time of the initialisation.
setNeighbour - Method:
setNeighbour(int x, int y, field[,])
{
if(field[x-1,y] != null)
this.neighbour[0] = field[x-1,y];
if(field[x-1,y+1] != null)
this.neighbour[0] = field[x-1,y+1];
if(field[x,y+1] != null)
this.neighbour[0] = field[x,y+1];
if(field[x+1,y+1] != null)
this.neighbour[0] = field[x+1,y+1];
if(field[x+1,y] != null)
this.neighbour[0] = field[x+1,y];
if(field[x+1,y-1] != null)
this.neighbour[0] = field[x+1,y-1];
if(field[x,y-1] != null)
this.neighbour[0] = field[x,y-1];
if(field[x-1,y-1] != null)
this.neighbour[0] = field[x-1,y-1];
}
You could do this:
private field[,] board = new field[boardsize,boardsize];
for(int x = 0; x < boardsize ; x++)
{
for(int y = 0; y < boardsize ; y++)
{
if(board[x,y] == null)
board[x,y] = new field();
board[x,y].setNeighbours(x, y, board);
}
}
and check initialization of the neighbour in the setNeighbours() method the same way:
private void setNeighbours(int x, int y, field[,] board)
{
//Initialize neighbour if not already initialized
if(board[x+1,y] == null)
board[x+1,y] = new field();
//DO SOMETHING...
}
I don't Believe it's possible to reference the neighbours since they aren't created yet. You could however add the board as a parameter to the constructor of field and use a property to look up the neighbours when needed later.
This is a classical problem... Sadly C# doesn't have continuations... They can be simulated (very slowly) through the use of Threads... Yes, it is overkill, and it is only an exercise in programming:
public sealed class WaitForReady<T> : IDisposable
{
public readonly ManualResetEvent mre = new ManualResetEvent(false);
public T Value
{
get
{
mre.WaitOne();
return this.value;
}
set
{
this.value = value;
mre.Set();
}
}
private T value;
#region IDisposable Members
public void Dispose()
{
mre.Dispose();
}
#endregion
}
public class Field
{
public Field[] Neighbours;
public Field(WaitForReady<Field> me, WaitForReady<Field>[] neighbours)
{
me.Value = this;
Neighbours = new Field[neighbours.Length];
for (int i = 0; i < neighbours.Length; i++)
{
Neighbours[i] = neighbours[i] != null ? neighbours[i].Value : null;
}
}
}
public static void Main(string[] args)
{
int boardsize = 8;
Field[,] board = new Field[boardsize, boardsize];
WaitForReady<Field>[,] boardTemp = null;
try
{
boardTemp = new WaitForReady<Field>[boardsize, boardsize];
var threads = new Thread[boardsize * boardsize];
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
boardTemp[i, j] = new WaitForReady<Field>();
}
}
int k = 0;
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
var neighbours = new WaitForReady<Field>[8];
neighbours[0] = i > 0 && j > 0 ? boardTemp[i - 1, j - 1] : null;
neighbours[1] = i > 0 ? boardTemp[i - 1, j] : null;
neighbours[2] = i > 0 && j + 1 < boardsize ? boardTemp[i - 1, j + 1] : null;
neighbours[3] = j > 0 ? boardTemp[i, j - 1] : null;
neighbours[4] = j + 1 < boardsize ? boardTemp[i, j + 1] : null;
neighbours[5] = i + 1 < boardsize && j > 0 ? boardTemp[i + 1, j - 1] : null;
neighbours[6] = i + 1 < boardsize ? boardTemp[i + 1, j] : null;
neighbours[7] = i + 1 < boardsize && j + 1 < boardsize ? boardTemp[i + 1, j + 1] : null;
int i1 = i, j1 = j;
threads[k] = new Thread(() => board[i1, j1] = new Field(boardTemp[i1, j1], neighbours));
threads[k].Start();
k++;
}
}
// Wait for all the threads
for (int i = 0; i < threads.Length; i++)
{
threads[i].Join();
}
}
finally
{
// Dispose the WaitForReady
if (boardTemp != null)
{
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
if (boardTemp[i, j] != null)
{
boardTemp[i, j].Dispose();
}
}
}
}
}
}
The "trick" here is to create the Fields in 64 separate threads. When initialized first a Field "announce" itself to everyone (by setting its corresponding WaitForReady<> object), then it asks its neighbours for their this reference. It does this through the WaitForReady<> objects it receives as a parameters. The WaitForReady<> is a "special" container that can contain a single value (Value). If Value isn't set, then asking for it will put the thread in wait, until someone sets the value through the set.
For small sizes it is possible to build everything using recursion to simulate continuations. For a board size of 64 it is normally possible. This is faster.
public class Field
{
public Field[] Neighbours;
public Field(int i, int j, int boardsize, Func<Field>[,] getters)
{
Console.WriteLine("Building [{0},{1}]", i, j);
getters[i, j] = () => this;
Neighbours = new Field[8];
Neighbours[0] = i > 0 && j > 0 ? getters[i - 1, j - 1]() : null;
Neighbours[1] = i > 0 ? getters[i - 1, j]() : null;
Neighbours[2] = i > 0 && j + 1 < boardsize ? getters[i - 1, j + 1]() : null;
Neighbours[3] = j > 0 ? getters[i, j - 1]() : null;
Neighbours[4] = j + 1 < boardsize ? getters[i, j + 1]() : null;
Neighbours[5] = i + 1 < boardsize && j > 0 ? getters[i + 1, j - 1]() : null;
Neighbours[6] = i + 1 < boardsize ? getters[i + 1, j]() : null;
Neighbours[7] = i + 1 < boardsize && j + 1 < boardsize ? getters[i + 1, j + 1]() : null;
Console.WriteLine("Builded [{0},{1}]", i, j);
}
}
public static void Main(string[] args)
{
int boardsize = 8;
Field[,] board = new Field[boardsize, boardsize];
Func<Field>[,] getters = new Func<Field>[boardsize, boardsize];
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
int i1 = i, j1 = j;
getters[i, j] = () => board[i1, j1] = new Field(i1, j1, boardsize, getters);
}
}
for (int i = 0; i < boardsize; i++)
{
for (int j = 0; j < boardsize; j++)
{
getters[i, j]();
}
}
}
Another way is to let the Fields handle creation of the other fields.
It's gonna be a lot more work to write all the code, but it should be more processor efficient.
Turns out you can't do it in the constructor because you'll get into an infinite loop of fields trying to create each other (because they can't find each other yet).
I like doing things like aggressive inlining even though it only makes a tiny difference in Release mode and actually slows the code down in Debug mode. On my machine it was about .1 sec for 10k executions. Would be interested to know if that's any faster than #xanatos's answer. It's certainly a lot more code :P
using System.Runtime.CompilerServices;
namespace Algorithms
{
public class Board
{
public Field[,] fields = new Field[8, 8];
}
public class Field
{
// Neighbor positions
// 701 +1-1 +10 +1+1
// 6 2 0-1 00 0+1
// 543 -1-1 -10, -1+1
private Field[] neighbors = new Field[8];
public void FindNeighbors(Board board, int rank, int file)
{
if (rank > 0)
{
// Not on bottom
createNeighbor(board, rank - 1, file, 4);
if (file > 0)
{
// Not in bottom-left corner, so adding it
//createNeighbor(board, rank - 1, file, 4);
createNeighbor(board, rank - 1, file - 1, 5);
createNeighbor(board, rank, file - 1, 6);
if (rank < 7)
{
// Not on top corner, so adding above and left-above
createNeighbor(board, rank + 1, file - 1, 7);
createNeighbor(board, rank + 1, file, 0);
if (file < 7)
{
// Not in any corder, adding remainder
createNeighbor(board, rank, file + 1, 2);
createNeighbor(board, rank - 1, file + 1, 3);
createNeighbor(board, rank + 1, file + 1, 1);
}
else
{
// On the right, the only fields that haven't been added yet are on the right
}
}
else
{
// on top
if (file < 7)
{
// Not on the left, so add those fields.
createNeighbor(board, rank, file + 1, 2);
createNeighbor(board, rank - 1, file + 1, 3);
}
else
{
// On the top-left, so nothing else to add.
}
}
}
else
{
createNeighbor(board, rank, file + 1, 2);
createNeighbor(board, rank - 1, file + 1, 3);
if (rank < 7)
{
createNeighbor(board, rank + 1, file, 0);
createNeighbor(board, rank + 1, file + 1, 1);
}
else
{
// Top-left corner, nothing to add
}
}
}
else
{
// Bottom
createNeighbor(board, rank + 1, file, 0);
if (file > 0)
{
// Not on left
createNeighbor(board, rank, file - 1, 6);
createNeighbor(board, rank + 1, file - 1, 7);
if (file < 7)
{
// Not on the right
createNeighbor(board, rank + 1, file + 1, 1);
createNeighbor(board, rank, file + 1, 2);
}
}
else
{
// Bottom-left corner
createNeighbor(board, rank + 1, file + 1, 1);
createNeighbor(board, rank, file + 1, 2);
}
}
}
// Neighbor positions
// 701 +1-1 +10 +1+1
// 6 2 0-1 00 0+1
// 543 -1-1 -10, -1+1
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void createNeighbor(Board board, int rank, int file, int neighbor)
{
var field = board.fields[rank, file];
if (field == null)
{
field = new Field();
board.fields[rank, file] = field;
// Start looking for neighbors after their object is initialized.
field.FindNeighbors(board, rank, file);
}
// Always copy a link to the field, even if it already existed
neighbors[neighbor] = field;
}
}
}
This is the background to this question:
Background
Take any integer n greater than 1 and apply the following algorithm
If n is odd then n = n × 3 + 1 else n = n / 2
If n is equal to 1 then stop, otherwise go to step 1
The following demonstrates what happens when using a starting n of 6
6 - 3 - 10 - 5 - 16 - 8 - 4 - 2 - 1
After 8 generations of the algorithm we get to 1.
It is conjectured that for every number greater than 1 the repeated application of this algorithm will
eventually get to 1.
The question is how can I find a number that takes exactly 500 generations to reduce to 1?
The code below is my version but appearntly got some wrong logic. Could you help me correct this? Thanks in advance.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Sequence1
{
class Program
{
static void Main(string[] args)
{
int start = 1;
int flag = 0;
int value;
while(true){
int temp = (start - 1) / 3;
string sta = temp.ToString();
if (Int32.TryParse(sta, out value) )
{
if (((start - 1) / 3) % 2 == 1)
{
start = (start - 1) / 3;
flag++;
if (flag == 500)
{
break;
}
}
else
{
start = start * 2;
flag++;
if (flag == 500)
{
break;
}
}
}
else
{
start = start * 2;
flag++;
if (flag == 500)
{
break;
}
}
}
Console.WriteLine("result is {0}", start);
Console.ReadLine();
}
}
}
Since your question's title is "A recursion related issue", I will give you a recursive solution.
int Process(int input, int maxRecursionDepth)
{
// condition to break recursion
if (maxRecursionDepth == 0 || input == 1)
return input;
if (input % 2 == 1) // odd case
return Process(input * 3 + 1, maxRecursionDepth - 1);
else // even case
return Process(input / 2, maxRecursionDepth - 1);
}
Now to find all number in a specified range, that return 1 after exactly 500 recursions:
int startRange = 1, endRange = 1000;
int maxDepth = 500;
List<int> resultList = new List<int>();
for (int i = startRange; i <= endRange; i++)
{
if (Process(i, maxDepth) == 1)
resultList.Add(i);
}
Your problem is a part of Collatz conjecture (about recursively defined function) which has not been solved yet:
http://en.wikipedia.org/wiki/Collatz_conjecture
so I think brute force is a good way out:
public static int GetMinNumber(int generations) {
if (generations < 0)
throw new ArgumentOutOfRangeException("generations");
// Memoization will be quite good here
// but since it takes about 1 second (on my computer) to solve the problem
// and it's a throwaway code (all you need is a number "1979515")
// I haven't done the memoization
for (int result = 1; ; ++result) {
int n = result;
int itterations = 0;
while (n != 1) {
n = (n % 2) == 0 ? n / 2 : 3 * n + 1;
itterations += 1;
if (itterations > generations)
break;
}
if (itterations == generations)
return result;
}
}
...
int test1 = GetMinNumber(8); // <- 6
int test2 = GetMinNumber(500); // <- 1979515
Observing the problem,
13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1
In the third iteration we hit the number 10, which is smaller than 13
So instead of calculating the sequence count every time we can use a cache.
static int GetMinCollatz(int maxChain)
{
const long number = 1000000;
int minNumber = 0;
// Temporary values
int tempCount = 0;
long temp = 0;
// Cache
int[] sequenceCache = new int[number + 1];
// Fill the array with -1
for (int index = 0; index < sequenceCache.Length; index++)
{
sequenceCache[index] = -1;
}
sequenceCache[1] = 1;
for (int index = 2; index <= number; index++)
{
tempCount = 0;
temp = index;
// If the number is repeated then we can find
// sequence count from cache
while (temp != 1 && temp >= index)
{
if (temp % 2 == 0)
temp = temp / 2;
else
temp = temp * 3 + 1;
tempCount++;
}
sequenceCache[index] = tempCount + sequenceCache[temp];
if (sequenceCache[index] == maxChain)
{
minNumber = index;
}
}
return minNumber;
}
For more details refer project euler and this.
A recursive solution
private void ReduceTo1(int input, ref int totalCount)
{
totalCount++;
if (input % 2 == 0)
{
input = input / 2;
}
else
{
input = input * 3 + 1;
}
if (input != 1)
ReduceTo1(input, ref totalCount);
}
to test
int desireValue = 0;
for (int i = 1; i < 100000; i++)
{
int totalCount = 0;
ReduceTo1(i, ref totalCount);
if (totalCount >= 500)
{
desireValue = i;
break;
}
}
I have this sequence 1,2,3,4,5,6,8,10,11
Expected output is 1-6,8,10-11
This problem is about formatting the sequence in easy readable form
I tried with c# and used many if & else.
Interviewer said, there is some simple algorithm to do this.
I have no idea how to achive this very simple.
Also for 1,2,3 i shown 1-3. They said its wrong!.
Is there any design pattern(interpreter) involved in this logic?
Here is one way of doing it:
int[] numbers = { 1, 2, 3, 4, 5, 6, 8, 10, 11 };
int start, end;
for (int i = 0; i < numbers.Length; i++)
{
start = numbers[i];
while (i < numbers.Length - 1 && numbers[i] + 1 == numbers[i + 1])
i++;
end = numbers[i];
if(start == end)
Console.WriteLine(start);
else
Console.WriteLine(start + " - " + end);
}
This will display subsequent numbers that grow incrementally as range. Numbers that are not increasing linearly are not written as part of a range.
Here is another version of the first approach, it utilizes the same for loop to iterate on range:
int temp = numbers[0], start, end;
for (int i = 0; i < numbers.Length; i++)
{
start = temp;
if (i < numbers.Length - 1 )
// if subsequent numbers are incremental loop further
if (numbers[i] + 1 == numbers[i + 1])
continue;
// if they are not, number at index i + 1 is a new 'start' for the next iteration
else
temp = numbers[i + 1];
end = numbers[i];
if (start == end)
Console.WriteLine(start);
else
Console.WriteLine(start + " - " + end);
}
A simple implementation in C# could look like this:
public string Format(IEnumerable<int> input)
{
var result = string.Empty;
var previous = -1;
var start = -1;
var first = true;
foreach(var i in input)
{
if(start == -1)
start = i;
else if(previous + 1 != i)
{
result += FormatRange(start, previous, first);
first = false;
start = i;
}
previous = i;
}
if(start != -1)
result += FormatRange(start, previous, first);
return result;
}
public string FormatRange(int start, int end, bool isFirst)
{
var result = string.Empty;
if(!isFirst)
result += ", ";
if(start == end)
result += start;
else
result += string.Format("{0}-{1}", start, end);
return result;
}
This will also output 1-3 for the input 1,2,3, which is perfectly valid. Without a specification what the output should be instead it's impossible to answer that part.
Probably not a suitable answer for an interview question, but using LINQ is another way to solve this.
int[] numbers = { 1, 2, 3, 4, 5, 6, 8, 10, 11 };
var remains = numbers.AsEnumerable();
while (remains.Any())
{
int first = remains.First();
int last = remains.TakeWhile((x, i) => x - first == i).Last();
remains = remains.Skip(last - first + 1);
Console.Write(first + (first == last ? "" : "-" + last) + (remains.Any() ? "," : Environment.NewLine));
}
The following groups consecutive integers, and outputs a string for each group. However, it also allows you to specify the minimum length of group which you want to hyphenate; anything less will just give you the individual numbers. Thus if you only want to hyphenate groups of 4 or more, you can pass in 4; if you want to hyphenate pairs, you can pass in 2. (I'd want to use 3 myself, but I can't tell what they want.)
It also doesn't keep any collections of numbers as it goes along, because you don't need to.
Method:
static IEnumerable<string> Group(IEnumerable<int> input, int minLength)
{
int currentStart = int.MinValue;
int currentLength = 0;
foreach (int c in input)
{
if (currentLength > 0)
if (currentStart + currentLength == c)
currentLength++;
else
{
if (currentLength >= minLength)
yield return string.Format("{0}-{1}",
currentStart, currentStart + currentLength - 1);
else
for (int i = currentStart; i < currentStart + currentLength; i++)
yield return i.ToString();
currentStart = c;
currentLength = 1;
}
else
{
currentStart = c;
currentLength = 1;
}
}
if (currentLength >= minLength)
yield return string.Format("{0}-{1}",
currentStart, currentStart + currentLength + 1);
else
for (int i = currentStart; i < currentStart + currentLength; i++)
yield return i.ToString();
}
Usage:
int minCount = 3;
int[] input = new[] { 1, 2, 3, 4, 5, 6, 8, 10, 11 };
Console.WriteLine(String.Join(",", Group(input, minCount)));
Java code:
int[] arr = {1,2,3,4,5,6,8,10,11};
int start = arr[0], last = arr[0];
String output = "";
for (int i = 1; i <= arr.length; i++)
{
if (i == arr.length || arr[i] != last+1)
{
if (output.length() != 0)
output += ",";
if (start == last)
output += start;
else
output += start + "-" + last;
if (i != arr.length)
start = last = arr[i];
}
else
last = arr[i];
}
System.out.println(output);
Heres my best attempt. Not clever, but simple enough to satisfy that requirement I believe. I'm still pretty confused as to why "1-3" was wrong though....
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 8, 10, 11, 12 };
var groups = new Dictionary<int, int>();
groups.Add(numbers.First(), numbers.First());
foreach (var num in numbers.Skip(1))
{
var grp = groups.Last();
if (grp.Value + 1 == num)
{
groups[grp.Key] = num;
}
else
{
groups.Add(num, num);
}
}
var output = string.Join(",", groups.Select(grp => (grp.Key == grp.Value) ? grp.Value.ToString() : grp.Key.ToString() + "-" + grp.Value.ToString()));
Note: of course using the dictionary and linq etc is completely unnecessary (and way too specific for an answer requiring an algorithm), but I thought it highlighted the grouping aspect of the problem nicely
This is no valid C# code but to show the Idea.
Sort the list from Min to Max then do this:
For i = Min to Max
{
if i < MaxFound
continue;
int step = 1;
Output = i;
while Found(i + Step)
{
Step++;
MaxFound = i + Step;
}
if i < MaxFound
Output = (i + "-" + MaxFound);
Output += ", ";
}
Here is one of the approach:
public static void main(String[] args) {
print(1, 2, 3, 4, 5, 7, 9, 10, 12);
}
public static void print(int ... nums) {
System.out.print(nums[0]);
int idx = 1;
for(int i = 1; i < nums.length; i++, idx++) {
if(nums[i] - nums[i - 1] != 1) {
if(idx > 1) {
System.out.print(" - " + nums[i - 1]);
}
System.out.print(", " + nums[i]);
idx = 0;
}
}
if(idx > 1)
System.out.println(" - " + nums[nums.length - 1]);
}
Here's a Haskell version:
import Data.List
parseRange [] = ""
parseRange n =
let range = takeWhile (\x -> isInfixOf [x,x+1] n) n
in if not (null range)
then show (head range) ++ "-" ++ show (last range + 1)
++ (if length (tail n) > 1 then "," else "")
++ parseRange (drop (length range + 1) n)
else show (head n) ++ (if null (tail n) then "" else ",")
++ parseRange (drop 1 n)
Output:
*Main> parseRange [1,2,3,4,5,6,8,10,11]
"1-6,8,10-11"
And a way to do it with fold in F# - just for fun.
let parseRange numbers =
numbers
|> Seq.fold
(fun list n ->
match list with
|(a,b) :: tail when b+1 = n -> (a, n) :: tail
|_ -> (n,n) :: list) []
|> List.rev
|> Seq.map (fun (a,b) -> if a = b then sprintf "%i" a else sprintf "%i-%i" a b)
|> String.concat ","
Given an array of integers...
var numbers = new int[] { 1,2,1,2,1,2,1,2,1,2,1,2,1,2,2,2,1,2,1 };
I need to determine a the maximum sequence of numbers that alternate up then down or down then up.
Not sure the best way to approach this, the process psuedo wise strikes me as simple but materializing code for it is evading me.
The key is the fact we are looking for max sequence, so while the above numbers could be interpreted in many ways, like a sequence of seven up-down-up and seven down-up-down the important fact is starting with the first number there is a down-up-down sequence that is 14 long.
Also I should not that we count the first item, 121 is a sequence of length 3, one could argue the sequence doesn't begin until the second digit but lets not split hairs.
This seems to work, it assumes that the length of numbers is greater than 4 (that case should be trivial anyways):
var numbers = new int[] { 1,2,1,2,1,2,1,2,1,2,1,2,1,2,2,2,1,2,1 };
int count = 2, max = 0;
for (int i = 1; i < numbers.Length - 1; i++)
{
if ((numbers[i - 1] < numbers[i] && numbers[i + 1] < numbers[i]) ||
(numbers[i - 1] > numbers[i] && numbers[i + 1] > numbers[i]))
{
count++;
max = Math.Max(count, max);
}
else if ((numbers[i - 1] < numbers[i]) || (numbers[i - 1] > numbers[i])
|| ((numbers[i] < numbers[i + 1]) || (numbers[i] > numbers[i + 1])))
{
max = Math.Max(max, 2);
count = 2;
}
}
Console.WriteLine(max); // 14
Here's how I thought of it
First, you need to know whether you're starting high or starting low. eg: 1-2-1 or 2-1-2. You might not even have an alternating pair.
Then, you consider each number afterwards to see if it belongs in the sequence, taking into consideration the current direction.
Everytime the sequence breaks, you need to start again by checking the direction.
I am not sure if it is possible that out of the numbers you have already seen, picking a different starting number can POSSIBLY generate a longer sequence. Maybe there is a theorem that shows it is not possible; maybe it is obvious and I am over-thinking. But I don't think it is possible since the reason why a sequence is broken is because you have two high's or two low's and there is no way around this.
I assumed the following cases
{} - no elements, returns 0
{1} - single element, returns 0
{1, 1, 1} - no alternating sequence, returns 0
No restriction on the input beyond what C# expects. It could probably be condensed. Not sure if there is a way to capture the direction-change logic without explicitly keeping track of the direction.
static int max_alternate(int[] numbers)
{
int maxCount = 0;
int count = 0;
int dir = 0; // whether we're going up or down
for (int j = 1; j < numbers.Length; j++)
{
// don't know direction yet
if (dir == 0)
{
if (numbers[j] > numbers[j-1])
{
count += 2; // include first number
dir = 1; // start low, up to high
}
else if (numbers[j] < numbers[j-1])
{
count += 2;
dir = -1; // start high, down to low
}
}
else
{
if (dir == -1 && numbers[j] > numbers[j-1])
{
count += 1;
dir = 1; // up to high
}
else if (dir == 1 && numbers[j] < numbers[j-1])
{
count += 1;
dir = -1; // down to low
}
else
{
// sequence broken
if (count > maxCount)
{
maxCount = count;
}
count = 0;
dir = 0;
}
}
}
// final check after loop is done
if (count > maxCount)
{
maxCount = count;
}
return maxCount;
}
And some test cases with results based on my understanding of the question and some assumptions.
static void Main(string[] args)
{
int[] nums = { 1}; // base case == 0
int[] nums2 = { 2, 1 }; // even case == 2
int[] nums3 = { 1, 2, 1 }; // odd case == 3
int[] nums4 = { 2, 1, 2 }; // flipped starting == 3
int[] nums5 = { 2, 1, 2, 2, 1, 2, 1 }; // broken seqeuence == 4
int[] nums6 = { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 1, 2, 1 }; // long sequence == 14
Console.WriteLine(max_alternate(nums));
Console.WriteLine(max_alternate(nums2));
Console.WriteLine(max_alternate(nums3));
Console.WriteLine(max_alternate(nums4));
Console.WriteLine(max_alternate(nums5));
Console.WriteLine(max_alternate(nums6));
Console.ReadLine();
}
I'm not from a pc with a compiler right now, so I just give a try:
int max = 0;
int aux =0;
for(int i = 2 ; i < length; ++i)
{
if (!((numbers[i - 2] > numbers[i - 1] && numbers[i - 1] < numbers[i]) ||
numbers[i - 2] < numbers[i - 1] && numbers[i - 1] > numbers[i]))
{
aux = i - 2;
}
max = Math.Max(i - aux,max);
}
if (max > 0 && aux >0)
++max;
Note: should works for sequence of at least 3 elements.
There are probably a lot of ways to approach this, but here is one option:
var numbers = new int[] { 7,1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 1, 2, 1 };
int maxCount = 0;
for (int j = 0; j+1 < numbers.Length; j++)
{
int count = 0;
if (numbers[j] < numbers[j+1])
{
count += 2;
for (int i = j+2; i+1 < numbers.Length; i += 2)
{
if (numbers[i] < numbers[i + 1] )
{
count += 2;
}
else
{
break;
}
}
}
if (maxCount < count)
{
maxCount = count;
}
}
Console.WriteLine(maxCount);
Console.ReadLine();
This solution assumes that you want a sequence of the same two alternating numbers. If that's not a requirement you could alter the second if.
Now that it's written out, it looks more complex than I had imagined in my head... Maybe someone else can come up with a better solution.
Assumes at least 2 elements.
int max = 1;
bool expectGreaterThanNext = (numbers[0] > numbers[1]);
int count = 1;
for (var i = 0; i < numbers.Length - 1; i++)
{
if (numbers[i] == numbers[i + 1] || expectGreaterThanNext && numbers[i] < numbers[i + 1])
{
count = 1;
expectGreaterThanNext = (i != numbers.Length - 1) && !(numbers[i] > numbers[i+1]);
continue;
}
count++;
expectGreaterThanNext = !expectGreaterThanNext;
max = Math.Max(count, max);
}
This works for any integers, it tracks low-hi-low and hi-low-hi just like you asked.
int numbers[] = new int[] { 1,2,1,2,1,2,1,2,1,2,1,2,1,2,2,2,1,2,1 };
int count = 0;
int updownup = 0;
int downupdown = 0;
for(int x = 0;x<=numbers.Length;x++)
{
if(x<numbers.Length - 2)
{
if(numbers[x]<numbers[x+1])
{
if(numbers[x+1]>numbers[x+2])
{
downupdown++;
}
}
}
}
count = 0;
for(x=0;x<=numbers.Length;x++)
{
if(x<numbers.Length - 2)
{
if(numbers[x]>numbers[x+1]
{
if(numbers[x+1]<numbers[x+2])
{
updownup++;
}
}
}
}