Rotate array of k position performance c# - c#

I'm solving problems on LeetCode, and referring to this problem: 189. Rotate Array
Given an array, rotate the array to the right by k steps, where k is non-negative.
Example 1:
Input: nums = [1,2,3,4,5,6,7], k = 3
Output: [5,6,7,1,2,3,4]
I gave my solution as:
public void Rotate(int[] nums, int k) {
if (k <= 0)
return;
int t = 0;
for (int i = 0; i < k; i++) {
t = nums[nums.Length - 1];
for (int j = nums.Length - 1; j > 0; j--) {
nums[j] = nums[j - 1];
}
nums[0] = t;
}
}
My question is not about the solution, but is about its performance.
Can I improve my solution to be faster? Or is wrong my approach?
Cause it pass all the test cases, but it fail the last one cause is a big array with big numbers, and it fail on being fast enough, it gives me
"Time Limit Exceeded"

You could run it in a single while loop. I don't have leetcode so I can't test it, I just ran it locally but if you run this what do you get? Also, it doesn't do the in place movement so if there is a memory test it might fail that.
public static int[] Rotate(int[] nums, int k) {
if (k <= 0) return nums;
var n = new int[nums.Length];
var stopAt = nums.Length - k;
while(stopAt < 0) {
stopAt = nums.Length - Math.Abs(stopAt);
}
var i = stopAt;
var y = 0;
while (true) {
n[y] = nums[i];
y++;
i++;
if (i >= nums.Length) {
i = 0;
}
if (i == stopAt) break;
}
return n;
}

There's a trick to performing this in place that involves a transformation over two steps. O(n) time, O(1) space.
Example, k = 3:
1234567
First reverse in place each of the two sections delineated by n-k:
4321 765
Now revese the whole array:
5671234
Reversing sections in place left as an exercise to the reader.

If you are looking for performance you can get rid of nested loops to have O(n) time complexity vs. O(n * n):
Compute what each item of the result array should be
Copy result array into initial one
Code:
public void Rotate(int[] nums, int k) {
int[] result = new int[nums.Length];
for (int i = 0; i < nums.Length; ++i) {
int index = (i + k % nums.Length + nums.Length) % nums.Length;
result[index] = nums[i];
}
Array.Copy(result, nums, nums.Length);
}
Note, that in general case we have a quite complex formula for index:
int index = (i + k % nums.Length + nums.Length) % nums.Length;
we should be ready for negative k (while index must not be negative) and huge k (possible integer overflow). If k >= 0 and k <= 1e5 as Leet Code claims we can simplify index into
int index = (i + k) % nums.Length;
and have compact solution as
public void Rotate(int[] nums, int k) {
int[] result = new int[nums.Length];
for (int i = 0; i < nums.Length; ++i)
result[(i + k) % nums.Length] = nums[i];
Array.Copy(result, nums, nums.Length);
}
Edit: Why % (remainder) appears in index formula?
Let's have a look on what's going on. When i + k is less than nums.Length we should write the value just at i + k index. When i + k == nums.Length we should write at index == 0, when i + k == nums.Length + 1 we should write at index == 1, ..., when i + k == nums.Length + r then we should write at index == r, note that r == (i + k) % nums.Length == (nums.Length + r) % nums.Length == 0 + r == r

Related

Print all points in an infinite grid of n dimensions

I can not have infinite points stored in the computer, but what I mean by that is the max value of Int64 (long).
I could use a nested loop, but that would take an eternity to go to the next line, so I found another way.
All the points whose x and y values add upto n are on a diagonal.
(0,0) - 0
(1,0),(0,1) - 1
(2,0),(1,1),(0,2) - 2
(all of these are diagonals)
So we could iterate through all values of n, from 0 to max value of long, that would give us all the points on all the diagonals.
So I wrote the code to do this.
public void Main()
{
for(long i = 0; i < Int64.MaxValue; i++)
{
long[] a = new long[(i + 1)];
long[] b = new long[(i + 1)];
for(long j = 0; j <= i; j++)
{
a[j] = j;
b[j] = (i - a[j]);
}
f(a,b);
}
}
public void f(long[] a, long[] b)
{
string toPrint = "";
for(int i = 0; i < a.Length; i++)
{
toPrint += "(" + a[i] + "," + b[i] + "),";
}
Console.Write(toPrint + "\n\n");
}
It does the job for a grid of 2 dimensions, but I want it to work for n dimensions, the same idea applies

How would you create n nested loops for math?

So, I am trying to wrap my head around understanding how you can use a variable to denote how many times a loop is nested.
Here is an example I write up to simulate the output of dimensions = 4:
static void Main(string[] args)
{
int dimensions = 4; // e.g. for (1, 2, 3, 4), dimensions = 4
Console.WriteLine($"{addNumbers(dimensions)}");
Console.ReadKey();
}
static long addNumbers(int dimensions)
{
long number = 0;
// hard coded to be dimensions = 4
for (int h = 0; h <= dimensions; h++)
for (int i = 0; i <= dimensions; i++)
for (int j = 0; j <= dimensions; j++)
for (int k = 0; k <= dimensions; k++)
number += h + i + j + k; // just some random math
return number;
}
This will present the expected output of:
5000
So to readdress the problem, how can I code to allow this for n dimensions? Thanks for your help!
For arbitrary n dimensions you can loop with a help of array int[] address which represents n dimensions:
static long addNumbers(int dimensions) {
int[] address = new int[dimensions];
// size of each dimension; not necessary equals to dimensions
// + 1 : in your code, int the loops you have i <= dimensions, j <= dimensions etc.
int size = dimensions + 1;
long number = 0;
do {
//TODO: some math here
// i == address[0]; j = address[1]; ... etc.
number += address.Sum();
// next address: adding 1 to array
for (int i = 0; i < address.Length; ++i) {
if (address[i] >= size - 1)
address[i] = 0;
else {
address[i] += 1;
break;
}
}
}
while (!address.All(index => index == 0)); // all 0 address - items're exhausted
return number;
}
Finally, let's add some Linq to look at the results:
int upTo = 5;
string report = string.Join(Environment.NewLine, Enumerable
.Range(1, upTo)
.Select(i => $"{i} -> {addNumbers(i),6}"));
Console.Write(report);
Outcome:
1 -> 1
2 -> 18
3 -> 288
4 -> 5000 // <- We've got it: 5000 for 4 dimensions
5 -> 97200

Most efficient way to find the smallest index where its value minus the value of a previous index is smaller than a given x?

I have five long integers p, q, s, m and x. An array numbers[] is created by the following formula.
numbers[0] = s;
for(int i=1; i<numbers.Length;i++){
numbers[i] = (p * numbers[i-1] + q) % m;
}
The first value of numbers (numbers[0]) is s.
What is the most efficient way to find index j where i < j and |numbers[j] - numbers[i]| <= x or |numbers[j] - numbers[i]| >= m-x.
For instance, in a case where p = 3, q= 7, s= 1, m= 29 en x= 1 the array will be:
numbers[0] = 1, numbers[1] = 10, numbers[2] = 8 and numbers[3] = 2.
In this case index j would be 3, because numbers[3] - numbers[0]<=x, because x is 1.
I thought about using something such as a variant of counting sort or radix sort but I can't get anything to work.
As i < j, then you need to grant that numbers has a length of at least 2.
You could do two nested loops, the outer one ranging from j = 1 to numbers.Length - 1 (granting the possible solution to be the smallest j) to i = 0 to i < j.
Then you compare both positions according your specs. If true, return j. If it finishes both loops, then there is no solution.
Edit: Code Sample
public int GetSmallestIndex(long[] numbers, long x, long m)
{
if (numbers.Length >= 2)
{
for (int j = 1; j < numbers.Length; j++)
{
for (int i = 0; i < j; i++)
{
long diff = Math.Abs(numbers[j] - numbers[i]);
if (diff <= x || diff >= m - x)
return j;
}
}
}
return -1; //If no solution is found, return -1 as convention
}
The only way to find out if something is more efficient is to benchmark it by using the StopWatch in System.Diagnostics.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
public static void Main()
{
var stopWatch = new Stopwatch();
stopWatch.Start();
const long x = 1;
var numbers = new long[] {3, 7, 1, 29};
var theSmallestIndex = SmallestIndex(x, numbers);
stopWatch.Stop();
Console.WriteLine("Elapsed Time: {0}", stopWatch.Elapsed);
Console.WriteLine("Smallest Index: {0}", theSmallestIndex);
Console.ReadKey();
}
public static long SmallestIndex(long x, long[] numbers)
{
var values = ValuesMinusTheValueOfPreviousIndex(x, numbers.ToList());
var smallest = values.Values.OrderBy(n => n).FirstOrDefault();
var result = values.Where(n => n.Value.Equals(smallest));
return result.FirstOrDefault().Key;
}
public static Dictionary<int, long> ValuesMinusTheValueOfPreviousIndex(long x, List<long> numbers)
{
var results = new Dictionary<int, long>();
foreach (var number in numbers)
{
var index = numbers.IndexOf(number);
var previousNumber = index > 0 ? numbers.ElementAt(index - 1) : 0;
var result = number - previousNumber;
results.Add(index, result);
}
return results;
}
}
}
EDIT: Added Math.Abs as you requested in the comments
long p = 3, q = 7, s = 1, m = 29, x = 1;
long[] numbers = new long[10];
numbers[0] = s;
for (int i = 1; i < numbers.Length; i++)
{
numbers[i] = (p * numbers[i - 1] + q) % m;
}
// Find the smallest index j in numbers, where i < j &&
// (numbers[j] - numbers[i] <= x || numbers[j] - numbers[i] >= m-x)
int smallestIndex = 0;
long comparison;
for (int j = 1; j < numbers.Length; j++)
{
for (int i = 0; i < j; i++)
{
comparison = Math.Abs(numbers[j] - numbers[i]);
if (comparison <= x || comparison >= m - x)
{
smallestIndex = j;
break;
}
}
if (smallestIndex != 0) break;
}
if (smallestIndex == 0)
{
// No result matches the conditions
}
else
{
// j is the smallest index matching the conditions
// Before using Abs, in the example j is 2, because 8 - 10 = -2, lesser than x
// Now using absolute values, In the example j is 3
}

Improving performance of a Nested Loop

This logic is to find the number n in the array in which the range between n and n + 5 will include the most numbers in the array. I came up with a solution but it requires a nested loop, therefore it is kind of slow. Is there any way to improve its performance? Thanks in advance.
The array is guaranteed to sorted.
int[] myArray = new int[]{1,2,4,5,7,9,15,19};
int bestNumber = 0;
int MaxMatchFound = 0;
for (int o = 0; o < myArray.Length; o++)
{
int TempMatchFound = 0;
for (int i = 0; i < myArray.Length; i++)
{
if (myArray[i] >= myArray[o] && myArray[i] <= (myArray[o] + 5))
{
TempMatchFound++;
}
}
if (TempMatchFound > MaxMatchFound)
{
bestNumber = myArray[o];
MaxMatchFound = TempMatchFound;
}
}
return bestNumber;
Bucket the values, then loop over the values v and sum the associated counts for all values w that satisfy v <= w <= v + 5, then find the max count:
var buckets = myArray.GroupBy(n => n)
.ToDictionary(g => g.Key, g => g.Count());
var rangeCounts =
buckets.Keys
.Select(v =>
new {
Value = v,
Count = Enumerable.Range(0, 6)
.Sum(i => buckets.ContainsKey(v + i) ?
buckets[v + i] :
0
)
}
);
var bestRange = rangeCounts.MaxBy(x => x.Count);
Now, bestRange.Value is the starting point for your best range and bestRange.Count is the number of elements falling into the range [bestRange.Value, bestRange.Value + 5]. Here, I've used MaxBy.
Think this gets you linear performance. Building dictionary is linear, building rangeCounts is linear, MaxBy is linear. Even works on non-sorted.
Here you go: This runs in O(N) time, and O(1) memory. This forms the buckets described in other solutions, then discards them as you move through the array. The Queue is used to track which buckets are 'active' in the sense that they can be added to. The Dictionary will never have more than 6 entries in it, neither will the Queue.
int[] myArray = new int[]{1,2,4,5,7,9,15,19};
Dictionary<int, int> counts = new Dictionary<int, int>();
Queue<int> q = new Queue<int>();
int n = 0;
int currentMaxCount = 0;
for(int i = 0; i < myArray.Length; i++)
{
var currentNum = myArray[i];
if(counts.ContainsKey(currentNum))
{
counts[currentNum]++;
}
else
{
counts[currentNum] = 1;
q.Enqueue(currentNum);
}
for(int j = 1; j <= 5; j++)
{
if(counts.ContainsKey(currentNum - j))
counts[currentNum - j]++;
}
if(q.Peek() + 5 < currentNum)
{
if(counts[q.Peek()] > currentMaxCount)
{
currentMaxCount = counts[q.Peek()];
n = q.Peek();
}
counts.Remove(q.Dequeue());
}
}
while(q.Count > 0)
{
if(counts[q.Peek()] > currentMaxCount)
{
currentMaxCount = counts[q.Peek()];
n = q.Peek();
}
counts.Remove(q.Dequeue());
}
Console.WriteLine("There are {0} matches between {1} and {2}", currentMaxCount, n, n + 5);
Here's a solution that is O(n) and uses O(1) extra space regardless of the range.
It does a single pass through the array, always making 2N comparisons. I don't see any way to improve on this algorithm, although there are certainly micro optimizations that could squeeze a little more speed out of the implementation.
private int FindRange(int[] myArray)
{
const int range = 5;
int start = 0;
int maxMatchFound = 0;
int maxIndex = 0;
for (int i = 0; i < myArray.Length; ++i)
{
if (myArray[i] > myArray[start] + range)
{
int matchLength = i - start;
if (matchLength > maxMatchFound)
{
maxMatchFound = matchLength;
maxIndex = start;
}
// move forward until within range
do
{
++start;
} while (myArray[i] > myArray[start] + range);
}
}
// Final check, from myArray[start] to end of array
int len = myArray.Length - start;
if (len > maxMatchFound)
{
maxMatchFound = len;
maxIndex = start;
}
return maxIndex;
The idea here is that if a particular number a[x] falls within the range for a[i] then it will fall within the range for a[i+1], assuming that x > i. (So in your original array, the value at a[3] falls within the range of a[0], so it will also fall within the range of a[1] and a[2]).
So the index i is incremented until the value it references falls out of the range of a[start]. Then, start is incremented until a[i] is in range again. The two indexes move forward through the array in that alternating fashion.
Here's a one-line LINQ option. Not the best in terms of performance (it iterates multiple times). Still worth noting.
var result = myArray
.OrderByDescending(i => myArray.Count(i2 => i2 >= i && i2 <= i + 5))
.First();

1D Fast Convolution without FFT

I need an 1D Convolution against 2 big arrays. I'm using this code in C# but it takes a loooong time to run.
I know, i know! FFT convolutions is very fast. But in this project i CAN'T use it.
It is a constraint of the project to not use FFT (please don't ask why :/).
This is my code in C# (ported from matlab, by the way):
var result = new double[input.Length + filter.Length - 1];
for (var i = 0; i < input.Length; i++)
{
for (var j = 0; j < filter.Length; j++)
{
result[i + j] += input[i] * filter[j];
}
}
So, anyone knows any fast convolution algorithm widthout FFT?
Convolution is numerically the same as a polynomial multiplication with an extra wrap-around step. Therefore, all the polynomial and large integer multiplication algorithms can be used to perform convolution.
FFT is the only way to get the fast O(n log(n)) run-time. But you can still get sub-quadratic run-time using the divide-and-conquer approaches like Karatsuba's algorithm.
Karatsuba's algorithm is fairly easy to implement once you understand how it works. It runs in O(n^1.585), and will probably be faster than trying to super-optimize the classic O(n^2) approach.
You could reduce the number of indexed accesses to result, as well as the Length properties:
int inputLength = filter.Length;
int filterLength = filter.Length;
var result = new double[inputLength + filterLength - 1];
for (int i = resultLength; i >= 0; i--)
{
double sum = 0;
// max(i - input.Length + 1,0)
int n1 = i < inputLength ? 0 : i - inputLength + 1;
// min(i, filter.Length - 1)
int n2 = i < filterLength ? i : filterLength - 1;
for (int j = n1; j <= n2; j++)
{
sum += input[i - j] * filter[j];
}
result[i] = sum;
}
If you further split the outer loop, you can get rid of some repeating conditionals. (This assumes 0 < filterLength &leq; inputLength &leq; resultLength)
int inputLength = filter.Length;
int filterLength = filter.Length;
int resultLength = inputLength + filterLength - 1;
var result = new double[resultLength];
for (int i = 0; i < filterLength; i++)
{
double sum = 0;
for (int j = i; j >= 0; j--)
{
sum += input[i - j] * filter[j];
}
result[i] = sum;
}
for (int i = filterLength; i < inputLength; i++)
{
double sum = 0;
for (int j = filterLength - 1; j >= 0; j--)
{
sum += input[i - j] * filter[j];
}
result[i] = sum;
}
for (int i = inputLength; i < resultLength; i++)
{
double sum = 0;
for (int j = i - inputLength + 1; j < filterLength; j++)
{
sum += input[i - j] * filter[j];
}
result[i] = sum;
}
You can use a special IIR filter.
Then process that as like:
y(n)= a1*y(n-1)+b1*y(n-2)...+a2*x(n-1)+b2*x(n-2)......
I think it's faster.
Here are two possibilities that may give minor speedups, but you'd need to test to be sure.
Unroll the inner loop to remove some tests. This will be easier if you know the filter length will always be a multiple if some N.
Reverse the order of the loops. Do filter.length passes over the whole array. This does less dereferencing in the inner loop but may have worse caching behavior.

Categories

Resources