Here's my quicksort working on a List, it's supposed to read from a large .txt file containing one number per line. After filling up the List from the file I tried to sort it, but for some reason it's taking way too long.
// Main.cs
List<int> myList = new List<int>();
string[] lines = System.IO.File.ReadAllLines("largeFile.txt");
foreach (string num in lines)
myList.Add(int.Parse(num));
QuickSort(ref myList, 0, myList.Count - 1);
quick.cs:
static void Swap(List<int> myList, int indexA, int indexB)
{
int tmp = myList[indexA];
myList[indexA] = myList[indexB];
myList[indexB] = tmp;
}
static int Partition(ref List<int> myList, int leftIdx, int rightIdx)
{
int pivot = leftIdx - 1;
for (int i = leftIdx; i < rightIdx; ++i)
{
if (myList[i] < myList[rightIdx])
{
++pivot;
Swap(myList, pivot, i);
}
}
++pivot;
Swap(myList, pivot, rightIdx);
return pivot;
}
static void QuickSort(ref List<int> myList, int leftIdx, int rightIdx)
{
if (rightIdx <= leftIdx)
return;
int pivotIdx = Partition(ref myList, leftIdx, rightIdx);
QuickSort(ref myList, leftIdx, pivotIdx - 1);
QuickSort(ref myList, pivotIdx + 1, rightIdx);
return;
}
Compared to List.Sort() (which sorts it almost immediately) this is ridiculously slow, how can I improve this? For instance List.Sort takes 3 milliseconds while my method takes 14769
Example code for classic Lomuto partition scheme. It swaps middle element with last element which is then used as the pivot. Recurse on smaller, loop on larger reduces stack space to O(log(n)), but worst case time complexity remains at O(n^2).
static public void QuickSort(int [] a, int lo, int hi)
{
while (lo < hi){
int t;
int p = a[(lo+hi)/2]; // use mid point for pivot
a[(lo+hi)/2]= a[hi]; // swap with a[hi]
a[hi] = p;
int i = lo;
for (int j = lo; j < hi; ++j){ // Lomuto partition
if (a[j] < p){ // if a[j] < pivot
t = a[i]; // swap a[i], a[j]
a[i] = a[j];
a[j] = t;
++i; // i += 1
}
}
t = a[i]; // swap a[i], a[hi]
a[i] = a[hi]; // to put pivot in place
a[hi] = t;
if(i - lo <= hi - i){ // recurse on smaller partiton
QuickSort(a, lo, i-1); // loop on larger
lo = i+1;
} else {
QuickSort(a, i+1, hi);
hi = i-1;
}
}
}
Given an array of n integers and a number, d, perform left rotations on the array. Then print the updated array as a single line of space-separated integers.
Sample Input:
5 4
1 2 3 4 5
The first line contains two space-separated integers denoting the respective values of n (the number of integers) and d (the number of left rotations you must perform).
The second line contains n space-separated integers describing the respective elements of the array's initial state.
Sample Output:
5 1 2 3 4
static void Main(String[] args)
{
string[] arr_temp = Console.ReadLine().Split(' ');
int n = Int32.Parse(arr_temp[0]);
int d = Int32.Parse(arr_temp[1]);
string[] arr = Console.ReadLine().Split(' ');
string[] ans = new string[n];
for (int i = 0; i < n; ++i)
{
ans[(i + n - d) % n] = arr[i];
}
for (int j = 0; j < n; ++j)
{
Console.Write(ans[j] + " ");
}
}
How to use less memory to solve this problem?
This will use less memory in most cases as the second array is only as big as the shift.
public static void Main(string[] args)
{
int[] n = { 1, 2, 3, 4, 5 };
LeftShiftArray(n, 4);
Console.WriteLine(String.Join(",", n));
}
public static void LeftShiftArray<T>(T[] arr, int shift)
{
shift = shift % arr.Length;
T[] buffer = new T[shift];
Array.Copy(arr, buffer, shift);
Array.Copy(arr, shift, arr, 0, arr.Length - shift);
Array.Copy(buffer, 0, arr, arr.Length - shift, shift);
}
This problem can get a bit tricky but also has a simple solution if one is familiar with Queues and Stacks.
All I have to do is define a Queue (which will contain the given array) and a Stack.
Next, I just have to Push the Dequeued index to the stack and Enqueue the Popped index in the Queue and finally return the Queue.
Sounds confusing? Check the code below:
static int[] rotLeft(int[] a, int d) {
Queue<int> queue = new Queue<int>(a);
Stack<int> stack = new Stack<int>();
while(d > 0)
{
stack.Push(queue.Dequeue());
queue.Enqueue(stack.Pop());
d--;
}
return queue.ToArray();
}
Do you really need to physically move anything? If not, you could just shift the index instead.
Actually you asked 2 questions:
How to efficiently rotate an array?
and
How to use less memory to solve this problem?
Usually efficiency and low memory usage are mutually exclusive. So I'm going to answer your second question, still providing the most efficient implementation under that memory constraint.
The following method can be used for both left (passing negative count) or right (passing positive count) rotation. It uses O(1) space (single element) and O(n * min(d, n - d)) array element copy operations (O(min(d, n - d)) array block copy operations). In the worst case scenario it performs O(n / 2) block copy operations.
The algorithm is utilizing the fact that
rotate_left(n, d) == rotate_right(n, n - d)
Here it is:
public static class Algorithms
{
public static void Rotate<T>(this T[] array, int count)
{
if (array == null || array.Length < 2) return;
count %= array.Length;
if (count == 0) return;
int left = count < 0 ? -count : array.Length + count;
int right = count > 0 ? count : array.Length - count;
if (left <= right)
{
for (int i = 0; i < left; i++)
{
var temp = array[0];
Array.Copy(array, 1, array, 0, array.Length - 1);
array[array.Length - 1] = temp;
}
}
else
{
for (int i = 0; i < right; i++)
{
var temp = array[array.Length - 1];
Array.Copy(array, 0, array, 1, array.Length - 1);
array[0] = temp;
}
}
}
}
Sample usage like in your example:
var array = Enumerable.Range(1, 5).ToArray(); // { 1, 2, 3, 4, 5 }
array.Rotate(-4); // { 5, 1, 2, 3, 4 }
Isn't using IEnumerables better? Since It won't perform all of those maths, won't allocate that many arrays, etc
public static int[] Rotate(int[] elements, int numberOfRotations)
{
IEnumerable<int> newEnd = elements.Take(numberOfRotations);
IEnumerable<int> newBegin = elements.Skip(numberOfRotations);
return newBegin.Union(newEnd).ToArray();
}
IF you don't actually need to return an array, you can even remove the .ToArray() and return an IEnumerable
Usage:
void Main()
{
int[] n = { 1, 2, 3, 4, 5 };
int d = 4;
int[] rotated = Rotate(n,d);
Console.WriteLine(String.Join(" ", rotated));
}
I have also tried this and below is my approach...
Thank you
public static int[] RotationOfArray(int[] A, int k)
{
if (A == null || A.Length==0)
return null;
int[] result =new int[A.Length];
int arrayLength=A.Length;
int moveBy = k % arrayLength;
for (int i = 0; i < arrayLength; i++)
{
int tmp = i + moveBy;
if (tmp > arrayLength-1)
{
tmp = + (tmp - arrayLength);
}
result[tmp] = A[i];
}
return result;
}
I have tried to used stack and queue in C# to achieve the output as follows:
public int[] rotateArray(int[] A, int rotate)
{
Queue<int> q = new Queue<int>(A);
Stack<int> s;
while (rotate > 0)
{
s = new Stack<int>(q);
int x = s.Pop();
s = new Stack<int>(s);
s.Push(x);
q = new Queue<int>(s);
rotate--;
}
return q.ToArray();
}
I've solve the challange from Hackerrank by following code. Hope it helps.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace ConsoleApp1
{
class ArrayLeftRotationSolver
{
TextWriter mTextWriter;
public ArrayLeftRotationSolver()
{
mTextWriter = new StreamWriter(#System.Environment.GetEnvironmentVariable("OUTPUT_PATH"), true);
}
public void Solve()
{
string[] nd = Console.ReadLine().Split(' ');
int n = Convert.ToInt32(nd[0]);
int d = Convert.ToInt32(nd[1]);
int[] a = Array.ConvertAll(Console.ReadLine().Split(' '), aTemp => Convert.ToInt32(aTemp))
;
int[] result = rotLeft(a, d);
mTextWriter.WriteLine(string.Join(" ", result));
mTextWriter.Flush();
mTextWriter.Close();
}
private int[] rotLeft(int[] arr, int shift)
{
int n = arr.Length;
shift %= n;
int[] vec = new int[n];
for (int i = 0; i < n; i++)
{
vec[(n + i - shift) % n] = arr[i];
}
return vec;
}
static void Main(string[] args)
{
ArrayLeftRotationSolver solver = new ArrayLeftRotationSolver();
solver.Solve();
}
}
}
Hope this helps.
public static int[] leftrotation(int[] arr, int d)
{
int[] newarr = new int[arr.Length];
var n = arr.Length;
bool isswapped = false;
for (int i = 0; i < n; i++)
{
int index = Math.Abs((i) -d);
if(index == 0)
{
isswapped = true;
}
if (!isswapped)
{
int finalindex = (n) - index;
newarr[finalindex] = arr[i];
}
else
{
newarr[index] = arr[i];
}
}
return newarr;
}
Take the Item at position 0 and add it at the end. remove the item at position 0. repeat n times.
List<int> iList = new List<int>();
private void shift(int n)
{
for (int i = 0; i < n; i++)
{
iList.Add(iList[0]);
iList.RemoveAt(0);
}
}
An old question, but I thought I'd add another possible solution using just one intermediate array (really, 2 if you include the LINQ Take expression). This code rotates to right rather than left, but may be useful nonetheless.
public static Int32[] ArrayRightRotation(Int32[] A, Int32 k)
{
if (A == null)
{
return A;
}
if (!A.Any())
{
return A;
}
if (k % A.Length == 0)
{
return A;
}
if (A.Length == 1)
{
return A;
}
if (A.Distinct().Count() == 1)
{
return A;
}
for (var i = 0; i < k; i++)
{
var intermediateArray = new List<Int32> {A.Last()};
intermediateArray.AddRange(A.Take(A.Length - 1).ToList());
A = intermediateArray.ToArray();
}
return A;
}
O(1) space, O(n) time solution
I think in theory this is as optimal as it gets, since it makes a.Length in-place swaps and 1 temp variable swap per inner loop.
However I suspect O(d) space solutions would be faster in real life due to less code branching (fewer CPU command pipeline resets) and cache locality (mostly sequential access vs in d element steps).
static int[] RotateInplaceLeft(int[] a, int d)
{
var swapCount = 0;
//get canonical/actual d
d = d % a.Length;
if(d < 0) d += a.Length;
if(d == 0) return a;
for (var i = 0; swapCount < a.Length; i++) //we're done after a.Length swaps
{
var dstIdx = i; //we need this becasue of ~this: https://youtu.be/lJ3CD9M3nEQ?t=251
var first = a[i]; //save first element in this group
for (var j = 0; j < a.Length; j++)
{
var srcIdx = (dstIdx + d) % a.Length;
if(srcIdx == i)// circled around
{
a[dstIdx] = first;
swapCount++;
break; //hence we're done with this group
}
a[dstIdx] = a[srcIdx];
dstIdx = srcIdx;
swapCount++;
}
}
return a;
}
If you take a look at constrains you will see that d <= n (number of rotations <= number of elements in array). Because of that this can be solved in 1 line.
static int[] rotLeft(int[] a, int d)
{
return a.Skip(d).Concat(a.Take(d)).ToArray();
}
// using the same same array, and only one temp variable
// shifting everything several times by one
// works, simple, but slow
public static int[] ArrayRotateLeftCyclical(int[] a, int shift)
{
var length = a.Length;
for (int j = 0; j < shift; j++)
{
int t = a[0];
for (int i = 0; i < length; i++)
{
if (i == length - 1)
a[i] = t;
else
a[i] = a[i + 1];
}
}
return a;
}
Let's say if I have a array of integer 'Arr'. To rotate the array 'n' you can do as follows:
static int[] leftRotation(int[] Arr, int n)
{
int tempVariable = 0;
Queue<int> TempQueue = new Queue<int>(a);
for(int i=1;i<=d;i++)
{
tempVariable = TempQueue.Dequeue();
TempQueue.Enqueue(t);
}
return TempQueue.ToArray();`
}
Let me know if any comments. Thanks!
This is my attempt. It is easy, but for some reason it timed out on big chunks of data:
int arrayLength = arr.Length;
int tmpCell = 0;
for (int rotation = 1; rotation <= d; rotation++)
{
for (int i = 0; i < arrayLength; i++)
{
if (arr[i] < arrayElementMinValue || arr[i] > arrayElementMaxValue)
{
throw new ArgumentException($"Array element needs to be between {arrayElementMinValue} and {arrayElementMaxValue}");
}
if (i == 0)
{
tmpCell = arr[0];
arr[0] = arr[1];
}
else if (i == arrayLength - 1)
{
arr[arrayLength - 1] = tmpCell;
}
else
{
arr[i] = arr[i + 1];
}
}
}
what about this?
public static void RotateArrayAndPrint(int[] n, int rotate)
{
for (int i = 1; i <= n.Length; i++)
{
var arrIndex = (i + rotate) > n.Length ? n.Length - (i + rotate) : (i + rotate);
arrIndex = arrIndex < 0 ? arrIndex * -1 : arrIndex;
var output = n[arrIndex-1];
Console.Write(output + " ");
}
}
It's very straight forward answer.
Main thing is how you choose the start index.
public static List<int> rotateLeft(int d, List<int> arr) {
int n = arr.Count;
List<int> t = new List<int>();
int h = d;
for (int j = 0; j < n; j++)
{
if ((j + d) % n == 0)
{
h = 0;
}
t.Add(arr[h]);
h++;
}
return t;
}
using this code, I have successfully submitted to hacker rank problem,
// fast and beautiful method
// reusing the same array
// using small temp array to store replaced values when unavoidable
// a - array, s - shift
public static int[] ArrayRotateLeftWithSmallTempArray(int[] a, int s)
{
var l = a.Length;
var t = new int[s]; // temp array with size s = shift
for (int i = 0; i < l; i++)
{
// save cells which will be replaced by shift
if (i < s)
t[i] = a[i];
if (i + s < l)
a[i] = a[i + s];
else
a[i] = t[i + s - l];
}
return a;
}
https://github.com/sam-klok/ArraysRotation
public static void Rotate(int[] arr, int steps)
{
for (int i = 0; i < steps; i++)
{
int previousValue = arr[arr.Length - 1];
for (int j = 0; j < arr.Length; j++)
{
int currentValue = arr[j];
arr[j] = previousValue;
previousValue = currentValue;
}
}
}
Here is an in-place Rotate implementation of a trick posted by גלעד ברקן in another question. The trick is:
Example, k = 3:
1234567
First reverse in place each of the two sections delineated by n-k:
4321 765
Now reverse the whole array:
5671234
My implementation, based on the Array.Reverse method:
/// <summary>
/// Rotate left for negative k. Rotate right for positive k.
/// </summary>
public static void Rotate<T>(T[] array, int k)
{
ArgumentNullException.ThrowIfNull(array);
k = k % array.Length;
if (k < 0) k += array.Length;
if (k == 0) return;
Debug.Assert(k > 0);
Debug.Assert(k < array.Length);
Array.Reverse(array, 0, array.Length - k);
Array.Reverse(array, array.Length - k, k);
Array.Reverse(array);
}
Live demo.
Output:
Array: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
Rotate(5)
Array: 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7
Rotate(-2)
Array: 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9
I've been starting at this for an hour and can't figure out where I'm going wrong. My implementation is
static void LeftRotation(int[] arr, int d)
{
int[] copy = arr.Select(val => val).ToArray();
for(int i = 0; i < arr.Length; ++i)
{
int j = i - d;
arr[i] = j < 0 ? copy[copy.Length + j] : copy[j];
}
}
and d is the number of rotations.
e.g. arr=[1,2,3,4], d= 2 --> arr=[3,4,1,2]
A different way, as an example:
static void LeftRotation(int[] arr, int d)
{
for (int i = 1; i <= d; i++)
{
//saves the first element
int temp = arr[0];
//moves each element to the left, starting from the 2nd
for (int j = 1; j < arr.Length; ++j)
{
arr[j - 1] = arr[j];
}
//replaces the last elmt with the previously saved first elmt
arr[arr.Length - 1] = temp;
}
}
Your are shifting left, but you shift the old value that used to exist in the array, instead of shifting the current looped element.
To make things simple, determine first your next position, and then use the index to go to that position in the original array (not i position), but get the value form the copy array.
static void LeftRotation(int[] arr, int d)
{
int[] copy = arr.Select(val => val).ToArray();
for(int i = 0; i < arr.Length; ++i)
{
int j = i - d;
int position = j < 0 ? copy.Length + j : j;
arr[position] = copy[i];
}
}
For one rotation, Swap lower index with the next higher one, until you reach the 2nd last element.
while (d-- > 0) {
for(int i=0; i < arr.Length-1; i++) {
swap(i, i+1);
}
Fiddle: https://dotnetfiddle.net/DPkhNw
Your logic is shifting right by d slots, not left. To shift left you want the item from index i+d copied to index i, so change
int j = i - d;
to
int j = i + d;
here is the (not working code) and it should print the shape below but its not :
static void Main(string[] args)
{
int i = 1;
int k = 5;
int h = 1;
while (i <= 5)
{
Console.WriteLine("");
while (k > i)
{
Console.Write(" ");
k--;
}
while (h <= i)
{
Console.Write("**");
h++;
}
i++;
}
Console.ReadLine();
}
but when I try to do the same using the while statement the shape gets totally messed up.
any help ?
You have to declare k and h within the loop:
static void Main(string[] args)
{
int i = 1;
while (i <= 5)
{
int k = 5;
int h = 1;
Console.WriteLine("");
while (k > i)
{
Console.Write(" ");
k--;
}
while (h <= i)
{
Console.Write("**");
h++;
}
i++;
}
Console.ReadLine();
}
With your current solution, after first outer loop iteration, inner loops do nothing.
int NumberOfLines = 5;
int count = 1;
while (NumberOfLines-- != 0)
{
int c = count;
while (c-- != 0)
{
Console.Write("*");
}
Console.WriteLine();
count = count + 2;
}
That's it, simplest implementation.
The problem is that i, k and h are initialised before the outermost loop is entered. Within the outer loop k and h are altered by the inner loops. On the second execution of the outer loop k and h have the same values as were left after running the inner loops previously. As i increments in the outer loop, the k loop will not be entered and the h loop will only run once.
Think about what values h and k should have inside the outermost loop on the second execution.
I'll not solve for you just will give you hint only:
Use 3 loop statements
1. for line change
2. for spaces (reverse loop)
3. for printing * (odd series in this case) i.e. 2n-1
check in third while statement h <= 2*i - 1;
and print only one * in place of **
Check here:
http://ideone.com/xOB2OI
Actually I've done this via 'for' loop, z is height and x is equal to length of side.
Isosceles triangle (x>z):
public void Print(int x, int z)
{
var peakStart = x;
var peakEnd = x;
for (int i = 0; i < z; i++)
{
for (int j = 0; j < 2 * x + 1; j++)
{
if (peakStart < 1.5 * x && j >= peakStart && j <= peakEnd)
Console.Write("*");
else
Console.Write(" ");
}
peakStart--;
peakEnd++;
Console.WriteLine("");
}
}
I'm working on a simple algorithm problem for practice and i'm trying to figure out why on about 20 percent of test cases it fails. The problem is thus, given an array of ints find the average of all valid ints in the array.
An int is valid if
It is greater than or equal to -273
at least one of the previous two or next two ints are two points away from the current one
if the int is invalid it should not be included in calculating the average. Also, I don't believe the problem wants the solution to be cyclic (not sure though just thought about it while writing this so will try) i.e. if you are at the first int array[0], then there are no previous two ints as opposed to the last two being the previous two in a cyclic array.
my strategy is summed up in the code below:
public double averageTemperature(int[] measuredValues)
{
Queue<int> qLeft = new Queue<int>(2);
Queue<int> qRight = new Queue<int>(2);
double sum = 0d;
int cnt = 0;
for (int i = 0; i < measuredValues.Length; i++)
{
if (measuredValues[i] < -273)
continue;
if (qLeft.Count == 3)
qLeft.Dequeue();
for (int j = i + 1; j < measuredValues.Length; j++)
{
if (qRight.Count == 2)
{
break;
}
qRight.Enqueue(measuredValues[j]);
}
if (b(qLeft, qRight, measuredValues[i]) == true)
{
sum += measuredValues[i];
cnt++;
qLeft.Enqueue(measuredValues[i]);
}
qRight.Clear();
}
if (cnt > 0)
return sum / cnt;
return -300.0;
}
bool b(Queue<int> a, Queue<int> b, int c)
{
foreach (int q in a)
{
if (Math.Abs(q - c) <= 2)
return true;
}
foreach (int w in b)
{
if (Math.Abs(w - c) <= 2)
return true;
}
return false;
}
However, my strategy fails for this test case
{-13, 12, -14, 11, -15, 10, -16, 9, -17, 8, -18, 7, 6, -19, 5, -400, -400, 4, -390, -300, -270, 3, -12, 3, 2}
I don't understand why. I'm i missing something obvious? i know they're might be another more efficient way of solving this but i don't want to try them until i know why my "naive" way does not work.
Well I finally figured out why thanks to you guys. Here is my revised code for those who may find it helpful:
public double averageTemperature(int[] measuredValues)
{
Queue<int> qLeft = new Queue<int>(2);
Queue<int> qRight = new Queue<int>(2);
double sum = 0d;
int cnt = 0;
for (int i = 0; i < measuredValues.Length; i++)
{
if (qLeft.Count == 3)
qLeft.Dequeue();
for (int j = i + 1; j < measuredValues.Length; j++)
{
if (qRight.Count == 2)
{
break;
}
qRight.Enqueue(measuredValues[j]);
}
if (isValid(qLeft, qRight, measuredValues[i]) == true)
{
sum += measuredValues[i];
cnt++;
}
qLeft.Enqueue(measuredValues[i]);
qRight.Clear();
}
if (cnt > 0)
return sum / cnt;
return -300.0;
}
bool isValid(Queue<int> a, Queue<int> b, int c)
{
foreach (int q in a)
{
if (c >=-273 && Math.Abs(q - c) <= 2)
return true;
}
foreach (int w in b)
{
if (c >=-273 && Math.Abs(w - c) <= 2)
return true;
}
return false;
}
try starting at the same point in the nested for() loop when comparing. like this: what do you get when you run it?
public double averageTemperature(int[] measuredValues)
{
Queue<int> qLeft = new Queue<int>(2);
Queue<int> qRight = new Queue<int>(2);
double sum = 0d;
int cnt = 0;
for (int i = 0; i < measuredValues.Length; i++)
{
if (measuredValues[i] < -273)
continue;
if (qLeft.Count == 3)
qLeft.Dequeue();
for (int j = 0; j < measuredValues.Length; j++)
{
if (qRight.Count == 2)
{
break;
}
qRight.Enqueue(measuredValues[j]);
}
if (b(qLeft, qRight, measuredValues[i]) == true)
{
sum += measuredValues[i];
cnt++;
qLeft.Enqueue(measuredValues[i]);
}
qRight.Clear();
}
if (cnt > 0)
return sum / cnt;
return -300.0;
}
bool b(Queue<int> a, Queue<int> b, int c)
{
foreach (int q in a)
{
if (Math.Abs(q - c) <= 2)
return true;
}
foreach (int w in b)
{
if (Math.Abs(w - c) <= 2)
return true;
}
return false;
}
is it adding one each direction to put you two away like you were before?
You are enqueuing into qLeft only when the current value in the array is valid, but this is not right. You need to enqueue into qLeft at each iteration of the outer for-loop that is being controlled by i.
See the following code:
for (int i = 0; i < measuredValues.Length; i++)
{
if (measuredValues[i] < -273)
continue;
if (qLeft.Count == 3)
qLeft.Dequeue();
for (int j = i + 1; j < measuredValues.Length; j++)
{
if (qRight.Count == 2)
{
break;
}
qRight.Enqueue(measuredValues[j]);
}
if (b(qLeft, qRight, measuredValues[i]) == true)
{
sum += measuredValues[i];
cnt++;
}
qLeft.Enqueue(measuredValues[i]); // YOU NEED TO ENQUEUE INTO qLeft EACH TIME REGARDLESS OF IT IS VALID OR INVALID
qRight.Clear();
}