arrayMaxConsecutiveSum c# - c#
As part of learning c# I engage in codesignal challenges. So far everything is going good for me, except for the test stated in the title.
The problem is that my code is not efficient enough to run under 3 seconds when the length of an array is 10^5 and the number of consecutive elements (k) is 1000. My code runs as follows:
int arrayMaxConsecutiveSum(int[] inputArray, int k) {
int sum = 0;
int max = 0;
for (int i = 0; i <= inputArray.Length-k; i++)
{
sum = inputArray.Skip(i).Take(k).Sum();
if (sum > max)
max = sum;
}
return max;
}
All visible tests in the website run OK, but when it comes to hidden test, in test 20, an error occured, stating that
19/20 tests passed. Execution time limit exceeded on test 20: Program exceeded the execution time limit. Make sure that it completes execution in a few seconds for any possible input.
I also tried unlocking solutions but on c# the code is somewhat similar to this but he didn't use LINQ. I also tried to run it together with the hidden tests but same error occurred, which is weird as how it was submitted as a solution when it didn't even passed all tests.
Is there any faster way to get the sum of an array?
I also thought of unlocking the hidden tests, but I think it won't give me any specific solution as the problem would still persists.
It would seem that you are doing the addition of k numbers for every loop. This pseudo code should be more efficient:
Take the sum of the first k elements and set this to be the max.
Loop as you had before, but each time subtract from the existing sum the element at i-1 and add the element at i + k.
Check for max as before and repeat.
The difference here is about the number of additions in each loop. In the original code you add k elements for every loop, in this code, within each loop you subtract a single element and add a single element to an existing sum, so this is 2 operations versus k operations. Your code starts to slow down as k gets large for large arrays.
For this specific case, I would suggest you not to use Skip method as it iterates on the collection every time. You can check the Skip implementation at here. Copying the code for reference.
public static IEnumerable<TSource> Skip<TSource>(this IEnumerable<TSource> source, int count) {
if (source == null) throw Error.ArgumentNull("source");
return SkipIterator<TSource>(source, count);
}
static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count) {
using (IEnumerator<TSource> e = source.GetEnumerator()) {
while (count > 0 && e.MoveNext()) count--;
if (count <= 0) {
while (e.MoveNext()) yield return e.Current;
}
}
}
As you can see Skip iterates the collection everytime, so if you have a huge collection with k as a high number, than you can see the execution time sluggish.
Instead of using Skip, you can write simple for loop which iterates required items:
public static int arrayMaxConsecutiveSum(int[] inputArray, int k)
{
int sum = 0;
int max = 0;
for (int i = 0; i <= inputArray.Length-k; i++)
{
sum = 0;
for (int j = i; j < k + i; j++)
{
sum += inputArray[j];
}
if (sum > max)
max = sum;
}
return max;
}
You can check this dotnet fiddle -- https://dotnetfiddle.net/RrUmZX where you can compare the time difference. For through benchmarking, I would suggest to look into Benchmark.Net.
You need to be careful when using LINQ and thinking about performance. Not that it's slow, but that it can easily hide a big operation behind a single word. In this line:
sum = inputArray.Skip(i).Take(k).Sum();
Skip(i) and Take(k) will both take approximately as long as a for loop, stepping through thousands of rows, and that line is run for every one of the thousands of items in the main loop.
There's no magic command that is faster, instead you have to rethink your approach to do the minimum of steps inside the loop. In this case you could remember the sum from each step and just add or remove individual values, rather than recalculating the whole thing every time.
public static int arrayMaxConsecutiveSum(int[] inputArray, int k)
{
int sum = 0;
int max = 0;
for (int i = 0; i <= inputArray.Length-k; i++)
{
// Add the next item
sum += inputArray[i];
// Limit the sum to k items
if (i > k) sum -= inputArray[i-k];
// Is this the highest sum so far?
if (sum > max)
max = sum;
}
return max;
}
This is my solution.
public int ArrayMaxConsecutiveSum(int[] inputArray, int k)
{
int max = inputArray.Take(k).Sum();
int sum = max;
for (int i = 1; i <= inputArray.Length - k; i++)
{
sum = sum - inputArray[i- 1] + inputArray[i + k - 1];
if (sum > max)
max = sum;
}
return max;
}
Yes you should never run take & skip on large lists but here's a purely LINQ based solution that is both easy to understand and performs the task in sufficient time. Yes iterative code will still outperform it so you have to take the trade off for your use case. Benchmarks because of size or easy to understand
int arrayMaxConsecutiveSum(int[] inputArray, int k)
{
var sum = inputArray.Take(k).Sum();
return Math.Max(sum, Enumerable.Range(k, inputArray.Length - k)
.Max(i => sum += inputArray[i] - inputArray[i - k]));
}
Related
time complexity of Method
I want to learn about big-o, I hope someone can help me count operators in Method and tell me what the time complexity of this method is and teach me how to count. I tried to study on Youtube and I was a bit confused. static void SelectionSort(int[] data) { int temp, min; for (int i = 0; i < data.Length - 1 ; i++) { min = i; for (int j = 0; j < data.Length; j++) { if (data[j] < data[min]) { min = j; } temp = data[min]; data[min] = data[i]; data[i] = temp; } } }
first of all this is a function not a method because a method is simply a function inside a class. the time complexity of this algorithm is O(n^2) because of the double for loop that means that this algorithm will take around n^2 operations to be done. for example if you input an array of length 10 it will make 100 steps that's not an exact number but it means a lot if you try an array of length 100 it will make 10000 steps that means that if would take 100 more time to finish. so the less the time complexity the faster the algorithm is. to learn about time complexity check this video it will help a lot--> https://www.youtube.com/watch?v=6aDHWSNKlVw&t=6s
Time Complexity will be O(n^2) for this one. Reason is you have nested loop inside another loop. The outer loop iterates n times giving an element to the inner loop which again loops n times, per one loop of the outer array. https://adrianmejia.com/most-popular-algorithms-time-complexity-every-programmer-should-know-free-online-tutorial-course/#Bubble-sort
What sorting method is this being applied and what is the algorithmic complexity of the method
I came across the code below for implementing sorting array. I have applied to a very long array and it was able to do so in under a sec may be 20 millisec or less. I have been reading about Algorithm complexity and the Big O notation and would like to know: Which is the sorting method (of the existing ones) that is implemented in this code. What is the complexity of the algorithm used here. If you were to improve the algorithm/ code below what would you alter. using System; using System.Text; //This program sorts an array public class SortArray { static void Main(String []args) { // declaring and initializing the array //int[] arr = new int[] {3,1,4,5,7,2,6,1, 9,11, 7, 2,5,8,4}; int[] arr = new int[] {489,491,493,495,497,529,531,533,535,369,507,509,511,513,515,203,205,207,209,211,213,107,109,111,113,115,117,11913,415,417,419,421,423,425,427,15,17,19,21,4,517,519,521,523,525,527,4,39,441,443,445,447,449,451,453,455,457,459,461,537,539,541,543,545,547,1,3,5,7,9,11,13,463,465,467,23,399,401,403,405,407,409,411,499,501,503,505,333,335,337,339,341,343,345,347,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,9,171,173,175,177,179,181,183,185,187,269,271,273,275,277,279,281,283,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,133,135,137,139,141,143,145,285,287,289,291,121,123,125,127,129,131,297,299,373,375,377,379,381,383,385,387,389,97,99,101,103,105,147,149,151,153,155,157,159,161,163,165,167,16,391,393,395,397,399,401,403,189,191,193,195,197,199,201,247,249,251,253,255,257,259,261,263,265,267,343,345,347,349,501,503,505,333,335,337,339,341,417,419,421,423,425,561,563,565,567,569,571,573,587,589,591,593,595,597,599,427,429,431,433,301,303,305,307,309,311,313,315,317,319,321,323,325,327,329,331,371,359,361,363,365,367,369,507,509,511,513,515,351,353,355,57,517,519,521,523,525,527,413,415,405,407,409,411,499,435,437,469,471,473,475,477,479,481,483,485,487,545,547,549,551,553,555,575,577,579,581,583,585,557,559,489,491,493,495,497,529,531,533,535,537,539,541,543,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,293,295}; int temp; // traverse 0 to array length for (int i = 0; i < arr.Length ; i++) { // traverse i+1 to array length //for (int j = i + 1; j < arr.Length; j++) for (int j = i+1; j < arr.Length; j++) { // compare array element with // all next element if (arr[i] > arr[j]) { ///Console.WriteLine(i+"i before"+arr[i]); temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; //Console.WriteLine("i After"+arr[i]); } } } // print all element of array foreach(int value in arr) { Console.Write(value + " "); } } }
This is selection sort. It's time complexity is O(𝑛²). It has nested loops over i and j, and you can see these produce every possible set of two indices in the range {0,...,𝑛-1}, where 𝑛 is arr.Length. The number of pairs is a triangular number, and is equal to: 𝑛(𝑛-1)/2 ...which is O(𝑛²) If we stick to selection sort, we can still find some improvements. We can see that the role of the outer loop is to store in arr[i] the value that belongs there in the final sorted array, and never touch that entry again. It does so by searching the minimum value in the right part of the array that starts at this index 𝑖. Now during that search, which takes place in the inner loop, it keeps swapping lesser values into arr[i]. This may happen a few times, as it might find even lesser values as j walks to the right. That is a waste of operations, as we would prefer to only perform one swap. And this is possible: instead of swapping immediately, delay this operation. Instead keep track of where the minimum value is located (initially at i, but this may become some j index). Only when the inner loop completes, perform the swap. There is less important improvement: i does not have to get equal to arr.Length - 1, as then there are no iterations of the inner loop. So the ending condition for the outer loop can exclude that iteration from happening. Here is how that looks: for (int i = 0, last = arr.Length - 1; i < last; i++) { int k = i; // index that has the least value in the range arr[i..n-1] so far for (int j = i+1; j < arr.Length; j++) { if (arr[k] > arr[j]) { k = j; // don't swap yet -- just track where the minimum is located } } if (k > i) { // now perform the swap int temp = arr[i]; arr[i] = arr[k]; arr[k] = temp; } } A further improvement can be to use the inner loop to not only locate the minimum value, but also the maximum value, and to move the found maximum to the right end of the array. This way both ends of the array get sorted gradually, and the inner loop will shorten twice as fast. Still, the number of comparisons remains the same, and the average number of swaps as well. So the gain is only in the iteration overhead.
This is "Bubble sort" with O(n^2). You can use "Mergesort" or "Quicksort" to improve your algorithm to O(n*log(n)). If you always know the minimum and maximum of your numbers, you can use "Digit sort" or "Radix Sort" with O(n) See: Sorting alrogithms in c#
Difference in syntax and time complexity for C# for loop
I am trying to figure out what the difference between the following for loops is. The first is code that I wrote while practicing algorithms on codewars.com. It times out when attempting the larger test cases. The second is one of the top solutions. It seems functionally similar (obviously its more concise) but runs much faster and does not time out. Can anyone explain to me what the difference is? Also, the return statement in the second snippet is confusing to me. What exactly does this syntax mean? Maybe this is where it is more efficient. public static long findNb(long m) { int sum = 0; int x = new int(); for (int n = 0; sum < m; n++) { sum += n*n*n; x = n; System.Console.WriteLine(x); } if (sum == m) { return x; } return -1; } vs public static long findNb(long m) //seems similar but doesnt time out { long total = 1, i = 2; for(; total < m; i++) total += i * i * i; return total == m ? i - 1 : -1; }
The second approach uses long for the total value. Chances are that you're using an m value that's high enough to exceed the number of values representable by int. So your math overflows and the n value becomes a negative number. You get caught in an infinite loop, where n can never get as big as m. And, like everyone else says, get rid of the WriteLine. Also, the return statement in the second snippet is confusing to me. What exactly does this syntax mean? It's a ternary conditional operator.
Both approaches are roughly the same, except unwanted System.Console.WriteLine(x); which spolis the fun: printing on the Console (UI!) is a slow operation. If you are looking for a fast solution (esp. for the large m and long loop) you can just precompute all (77936) values: public class Solver { static Dictionary<long, long> s_Sums = new Dictionary<long, long>(); private static void Build() { long total = 0; for (long i = 0; i <= 77936; ++i) { total += i * i * i; s_Sums.Add(total, i); } } static Solver() Build(); } public static long findNb(long m) { return s_Sums.TryGetValue(m, out long result) ? result : -1; } }
When I run into micro optimisation challenges like this, I always use BenchmarkDotnet. It's the tool to use to get all the insights to performance, memory allocations, deviations in .NET Framework versions, 64bit vs 32 bit etc. etc. But as others write - remember to remove the WriteLine() statement :)
Keep statistic about sorting algorithms
I have a homework about object oriented programming in c#. a part of my homework, I need to make 2 different sorting algorithms and putting the random numbers into them and observing statistic about 2 different algorithms. about that my teaches said me in e-mail "Non static sorting class can keep statistic about sorting how many numbers, how fast, min, max, average.." So there are my sorting algorithms which Insertion and Count Sortings. Please tell me how can i keep statistic about sorting. Don't forget main subject of my homework is OOP. class InsertionSorting : Sort { public override List<int> Sorting(List<int> SortList) { for ( int i=0; i<SortList.Count-1; i++) { for (int j= i+1; j>0; j--) { if (SortList[j-1] > SortList [j]) { int temp = SortList[j - 1]; SortList[j - 1] = SortList[j]; SortList[j] = temp; } } } return SortList; } } class CountSorting : Sort { public override List<int> Sorting(List<int> SortList) { int n = SortList.Count; List<int> output = new List<int>(); List<int> count = new List<int>(); for (int i = 0; i < 1000; ++i) { count.Add(0); output.Add(0); } for (int i = 0; i < n; ++i) ++count[SortList[i]]; for (int i = 1; i <= 999; ++i) count[i] += count[i - 1]; for (int i = 0; i < n; ++i) { output[count[SortList[i]] - 1] = SortList[i]; --count[SortList[i]]; } for (int i = 0; i < SortList.Count; i++) SortList[i] = output[i]; return SortList; } }
Your sorting is being done in two classes - InsertionSorting & CountSorting. If you want keep track of the statistics declare a variable in the class and increment it every iteration etc etc. Then you can see which one is more effective. E.g class InsertionSorting : Sort { private int iterations = 0 ... for (int j= i+1; j>0; j--) { if (SortList[j-1] > SortList [j]) { iterations++ ... You could also declare a startTime and endTime allowing to you determine the time the sort took. At the start of "Sorting" record the start time and just before you return record the end time. Write a method to report the difference.
Your prof has told you how when they said "...statistics about sorting how many numbers, how fast, min, max, average.." Your best bet here is to create a class such as "Statistics" which contains a method that allows user input, either through args or direct user prompt. The variables should be as easy as "count of numbers to sort" "lower bounds of number range", "upper bound of number range", and, if automating the testing process, "number of times to iterate". Given answers to these questions, you should run the two sorting algos with them (eg use a random number generator, and max and min to generate a list.) Your sorting algos need an addition to "log" these statistics. Most likely a variable that tracks the number of position swaps that occurred in the array. I'm not about to write out your homework for you (that's your job, and you should get good at it.) But if you have any more questions to this, I may be able to steer you in the right direction if this is too vague and you are still struggling.
C# Array of Increments
If I want to generate an array that goes from 1 to 6 and increments by .01, what is the most efficient way to do this? What I want is an array, with mins and maxs subject to change later...like this: x[1,1.01,1.02,1.03...]
Assuming a start, end and an increment value, you can abstract this further: Enumerable .Repeat(start, (int)((end - start) / increment) + 1) .Select((tr, ti) => tr + (increment * ti)) .ToList() Let's break it down: Enumerable.Repeat takes a starting number, repeats for a given number of elements, and returns an enumerable (a collection). In this case, we start with the start element, find the difference between start and end and divide it by the increment (this gives us the number of increments between start and end) and add one to include the original number. This should give us the number of elements to use. Just be warned that since the increment is a decimal/double, there might be rounding errors when you cast to an int. Select transforms all elements of an enumerable given a specific selector function. In this case, we're taking the number that was generated and the index, and adding the original number with the index multiplied by the increment. Finally, the call to ToList will save the collection into memory. If you find yourself using this often, then you can create a method to do this for you: public static List<decimal> RangeIncrement(decimal start, decimal end, decimal increment) { return Enumerable .Repeat(start, (int)((end - start) / increment) + 1) .Select((tr, ti) => tr + (increment * ti)) .ToList() } Edit: Changed to using Repeat, so that non-whole number values will still be maintained. Also, there's no error checking being done here, so you should make sure to check that increment is not 0 and that start < end * sign(increment). The reason for multiplying end by the sign of increment is that if you're incrementing by a negative number, end should be before start.
The easiest way is to use Enumerable.Range: double[] result = Enumerable.Range(100, 500) .Select(i => (double)i/100) .ToArray(); (hence efficient in terms of readability and lines of code)
I would just make a simple function. public IEnumerable<decimal> GetValues(decimal start, decimal end, decimal increment) { for (decimal i = start; i <= end; i += increment) yield return i; } Then you can turn that into an array, query it, or do whatever you want with it. decimal[] result1 = GetValues(1.0m, 6.0m, .01m).ToArray(); List<decimal> result2 = GetValues(1.0m, 6.0m, .01m).ToList(); List<decimal> result3 = GetValues(1.0m, 6.0m, .01m).Where(d => d > 3 && d < 4).ToList();
Use a for loop with 0.01 increments: List<decimal> myList = new List<decimal>(); for (decimal i = 1; i <= 6; i+=0.01) { myList.Add(i); }
Elegant double[] v = Enumerable.Range(1, 600).Select(x => x * 0.01).ToArray(); Efficient Use for loop
Whatever you do, don't use a floating point datatype (like double), they don't work for things like this on behalf of rounding behaviour. Go for either a decimal, or integers with a factor. For the latter: Decimal[] decs = new Decimal[500]; for (int i = 0; i < 500; i++){ decs[i] = (new Decimal(i) / 100)+1 ; }
You could solve it like this. The solution method returns a double array double[] Solution(double min, int length, double increment) { double[] arr = new double[length]; double value = min; arr[0] = value; for (int i = 1; i<length; i++) { value += increment; arr[i] = value; } return arr; }
var ia = new float[500]; //guesstimate var x = 0; for(float i =1; i <6.01; i+= 0.01){ ia[x] = i; x++; } You could multi-thread this for speed, but it's probably not worth the overhead unless you plan on running this on a really really slow processor.