Finding the max sum of successive random numbers in an array [closed] - c#

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have an array of 25 random integers between -100 and 100.
For example my array can look like this:
-10, 23, 19, -11, 3, -9, -8, 4, 10, 20, 30, 40, 50, -6, -2, 1, -9, 8, -6, 20, -21, -3, -2, -4, -7
I wish to write a method that receive my array as a parameter, and prints out the following: the first index, the last index, and the sum of the successive elements between them, that will give the possible maximum sum.
For my example the output will be: first index: 1 (value: 23), last index: 19 (value:20), total sum: 177
I don't know how I should deal with this problem. I wrote a code, but it's very complex and unefficient because I used a list to store all the possible sums.
Can you please show a Pseudo-code for this problem, or code in c#?

This is a well known problem in literature, known (among many other names) as Maximum Subarray Problem.
You can find more infos, and a pseudo code with a possible solution here: http://en.wikipedia.org/wiki/Maximum_subarray_problem
Since your problem seems to be that of finding a viable algorithm and not implementing it, the following pseudo-code should be enough:
def max_subarray(A):
max_ending_here = max_so_far = 0
for x in A:
max_ending_here = max(0, max_ending_here + x)
max_so_far = max(max_so_far, max_ending_here)
return max_so_far

You don't need to keep all the possible sums, as you are only interested in the largest.
Loop throught the combinations, and look for any sum that is larger than what you have so far.
You can make use of the fact that the sum of any range of elements is the sum of the elements excluding the last item plus the last item. I.e you don't need to loop through the elements to calculate each possible sum, because you already have the sum of the range that is one element less:
public static void ShowLargestSum(int[] arr) {
int largest = arr[0], start = 0, end = 0;
for (int i = 0; i < arr.Length; i++) {
int sum = 0;
for (int j = i; j < arr.Length; j++) {
sum += arr[j];
if (sum > largest) {
largest = sum;
start = i;
end = j;
}
}
}
Console.WriteLine("first index: {0} (value: {1}), last index: {2} (value:{3}), total sum: {4}", start, arr[start], end, arr[end], largest);
}
Execution time on my computer for your example array: 0.17 ms.

Related

How to change a list based on another list [duplicate]

This question already has answers here:
How to sort a list so that the same changes would happen in another list?
(3 answers)
Closed 3 months ago.
I have a question:
For example I had a list with 132 and a second list 123
I would want my 132 list.sort but the 123 list to sort like 132:
was:
132
123
After
123
132
Not switch place but if the first element changes position in list 1 so should list 2, please help.
This answer involves writing (or editing an existing) sorting algorithm.
In the example below, I've illustrated a way in Javascript to enhance a simple Bubble Sort algorithm to include a second array to manipulate aswell.
I know the question is for C#, but the same concepts apply.
The arrays need to have the same length, otherwise you will get errors.
// Bubblesort algorithm stolen from https://www.geeksforgeeks.org/bubble-sort/
// edited to include a second array (arr2) that mirrors the sorting of the first array
function swap(arr, xp, yp)
{
var temp = arr[xp];
arr[xp] = arr[yp];
arr[yp] = temp;
}
function bubbleSort( arr, arr2, n)
{
var i, j;
for (i = 0; i < n-1; i++)
{
for (j = 0; j < n-i-1; j++)
{
if (arr[j] > arr[j+1])
{
swap(arr,j,j+1);
// swap the elements of the second array aswell
swap(arr2,j,j+1);
}
}
}
}
// just a function for printing
function printArray(arr, size)
{
var i;
for (i=0; i < size; i++)
document.write(arr[i]+ " ");
document.write("<br />");
}
// the two arrays
var array1 = [5, 1, 4, 2, 8];
var array2 = [2, 3, 4, 5, 6];
var n = 5;
document.write("UnSorted arrays: <br />");
printArray(array1, n);
printArray(array2, n);
bubbleSort(array1, array2, n);
document.write("Sorted arrays: <br />");
printArray(array1, n);
printArray(array2, n);
If you run the above snippet, you see that the '1' in the second position of the first array has moved to the first position.
The second array had a '3' in the second position, which is also swapped to the first position, like the first array did.
Long story short: The second array mirrors the sorting of the first array.

Sorting numbers using maximum spread

I want to sort a list of integers in such a way that they end up being spread out as much as possible. Assuming base 8, the order of items between 1 and 7 ought to be: {4, 6, 2, 7, 1, 5, 3} as per:
There is a fair amount of ambiguity of course, as both 6 and 2 are equally far away from 4, 0 and 8, so the specific ordering of 6 and 2 is irrelevant. What I'm trying to achieve is to first pick the number furthest away from 0 and base, then pick the number furthest away from 0, base and first number, etc. Any multiple of the base will never occur so I don't care how that is handled.
I can manually design the sort order for any given base, but I need this to work for any base >= 2. Is there a clever/fast way to compute this or do I need to lazily build the sorting mapping tables and cache them for future use?
int SortOrder(int radix, int value)
{
int offset = value % radix;
int[] table = {int.MinValue, 4, 2, 6, 0, 5, 1, 3}; // Hand-crafted for base-8
return table[offset];
}
This is specifically not an answer to the question since it doesn't attempt to find the answer quickly. Rather it builds a dictionary of cached sorting values for each radix.
#region sorting logic
/// <summary>
/// Maintains a collection of sorting maps for all used number bases.
/// </summary>
private static readonly Dictionary<int, int[]> _sortingTable = new Dictionary<int, int[]>();
private static readonly object _sortingLock = new object();
/// <summary>
/// Compute the sorting key for a given multiple.
/// </summary>
/// <param name="radix">Radix or base.</param>
/// <param name="multiple">Multiple.</param>
/// <returns>Sorting key.</returns>
public static int ComputeSortingKey(int radix, long multiple)
{
if (radix < 2)
throw new ArgumentException("Radix may not be less than 2.");
if (multiple == 0)
return int.MinValue; // multiple=0 always needs to be sorted first, so pick the smallest possible key.
int[] map;
if (!_sortingTable.TryGetValue(radix, out map))
lock (_sortingLock)
{
map = new int[radix];
map[0] = -1; // Multiples of the radix are sorted first.
int key = 0;
HashSet<int> occupancy = new HashSet<int> { 0, radix };
HashSet<int> collection = new HashSet<int>(1.ArrayTo(radix)); // (ArrayTo is an extension method in this project)
while (collection.Count > 0)
{
int maxValue = 0;
int maxDistance = 0;
foreach (int value in collection)
{
int distance = int.MaxValue;
foreach (int existingValue in occupancy)
distance = Math.Min(distance, Math.Abs(existingValue - value));
if (distance > maxDistance)
{
maxDistance = distance;
maxValue = value;
}
}
collection.Remove(maxValue);
occupancy.Add(maxValue);
map[maxValue] = key++;
}
_sortingTable.Remove(radix); // Just in case of a race-condition.
_sortingTable.Add(radix, map);
}
long offset = multiple % radix;
if (offset != 0)
if (multiple < 0)
offset = radix - (Math.Abs(multiple) % radix);
return map[(int)offset];
}
#endregion
My original answer was to find the maximum delta. To work your way from out to in, use the same comparison but different selects:
List<double> answer = new List<double>();
List<double> doub = new List<double>() { 0, -1, 2, 3, 4, -5, 7 };//SORT this list for sorted results!
List<double> lowerHalf = new List<double>();
List<double> upperHalf = new List<double>();
for (int i = 0; i < doub.Count; i++)
{
if (i <= (int)Math.Floor((double)doub.Count / 2))
lowerHalf.Add(doub[i]);
else
upperHalf.Add(doub[i]);
}
if (upperHalf.Count < lowerHalf.Count)
{
upperHalf.Insert(0,lowerHalf[lowerHalf.Count-1]);
}
//if(upperHalf[0]==lowerHalf[lowerHalf.Count-1]){double median = lowerHalf[lowerHalf.Count-1]+upperHalf[1])/2;lowerHalf[lowerHalf.Count-1] = median; upperHalf[0]=median;}//use Math.Round or Math.Floor/Ceiling if necessary
for (int i = 0; i < lowerHalf.Count; i++)
{
double deltas = Math.Sqrt(Math.Pow(upperHalf[upperHalf.Count - (i + 1)] - lowerHalf[i], 2));
answer.Add(deltas);
Console.WriteLine("The answer for {1}, {2} is: {0}", deltas, lowerHalf[i], upperHalf[upperHalf.Count - (i+1)]);
}
Console.ReadLine();
This will provide:
The answer for 0, 7 is: 7
The answer for -1, -5 is: 4
The answer for 2, 4 is: 2
The answer for 3, 3 is: 0
NOTE that in the event of an odd number of items in the original range, this method uses the same item for both upper and lower lists. I've added a line to use the "actual" median for your benefit
To get rid of duplicates, use a hashset, union, or distinct()
Original answer - to find maximum delta):
You can use math in your Linq, like:
List<double> doub = new List<double>() { 0, 1, 2, 3, 4, 5, 7 };
double deltas = doub.Select(p => p - doub.First()).OrderBy(p => p).Last();
Console.WriteLine("The answer is: {0}",deltas);
Console.ReadLine();
If your values go negative, you'd need to use squares:
double deltas = Math.Sqrt( doub.Select(p => Math.Pow(p - doub.First(), 2)).OrderBy(p => p).Last());
or Math.Abs or a test to see which is larger - but this should give you an idea on how to get started. If the numbers aren't in order in the original list, you can call an orderby before the select, as well.
Literally:
List<double> doub = new List<double>() { 0, 1, 2, 3, 4, 5, 7 };
double deltas = Math.Sqrt( doub.Select(p => Math.Pow(p - doub.First(), 2)).OrderBy(p => p).Last());
Console.WriteLine("The answer is: {0}",deltas);
Console.ReadLine();
produces
'OilTracker.vshost.exe' (CLR v4.0.30319: OilTracker.vshost.exe): Loaded 'C:\Users\User\Documents\Visual Studio 2015\Projects\OilTracker\OilTracker\bin\Debug\TDAInterface.dll'. Symbols loaded.
'OilTracker.vshost.exe' (CLR v4.0.30319: OilTracker.vshost.exe): Loaded 'C:\Users\User\Documents\Visual Studio 2015\Projects\OilTracker\OilTracker\bin\Debug\BackFeeder.exe'. Symbols loaded.
The answer is: 7
Moving forward to sorting the list, use:
List<double> answer = new List<double>();
List<double> doub = new List<double>() { 0, 1, 2, 3, 4, 5, 7 };
//sort doub if necessary
foreach (double num in doub)
{
double deltas = Math.Sqrt(Math.Pow(doub.Select(p => p - num).OrderBy(p => p).Last(), 2));
answer.Add(deltas);
Console.WriteLine("The answer for {1} is: {0}", deltas,num);
}
Console.ReadLine();
(Again, use another orderby if the list is not in order).
Produces:
'OilTracker.vshost.exe' (CLR v4.0.30319: OilTracker.vshost.exe): Loaded 'C:\Users\User\Documents\Visual Studio 2015\Projects\OilTracker\OilTracker\bin\Debug\TDA_Stream_Interface.dll'. Symbols loaded.
The answer for 0 is: 7
The answer for 1 is: 6
The answer for 2 is: 5
The answer for 3 is: 4
The answer for 4 is: 3
The answer for 5 is: 2
The answer for 7 is: 0
The squares/square root help us change signs and deal with negatives - so
List<double> doub = new List<double>() { 0, -1, 2, 3, 4, -5, 7 };
Produces:
The answer for 0 is: 7
The answer for -1 is: 8
The answer for 2 is: 5
The answer for 3 is: 4
The answer for 4 is: 3
The answer for -5 is: 12
The answer for 7 is: 0
(which aren't in order because I failed to sort the list on either the inbound or outbound sides).
After running, the list "answer" will contain the results - the lowest delta can be accessed by answers.First() and the highest by answers.Last(). similar deltas will exist for different numbers the same number of units apart - you could use a HashSet conversion in the formula if you want to eradicate duplicate deltas. If you need help with that, please let me know.
If you need to store the numbers that created the delta as well as the delta itself, they are available to you in the For/Each loop as the Console.WriteLine() indicates.
If you want to work the range-to-median on both sides of the median, it's probably a good idea to split the list and work in pairs. Make 0 to median in one list, and median to endRange in the second list, work out in the first and in in the second. This should get you there, but if you need help getting over that final hump, let me know.
Hope this helps!!

C#: sequence from min to max [duplicate]

This question already has an answer here:
Generating numbers list in C#
(1 answer)
Closed 9 years ago.
I want to get a sequence of integers from a value A to a value B.
For example A=3 and B=9. Now I want to create a sequence 3,4,5,6,7,8,9 with one line of code and without a loop. I played around with Enumerable.Range, but I find no solution that works.
Has anybody an idea?
var sequence = Enumerable.Range(min, max - min + 1);
?
For info, though - personally I'd still be tempted to use a loop:
for(int i = min; i <= max ; i++) { // note inclusive of both min and max
// good old-fashioned honest loops; they still work! who knew!
}
int A = 3;
int B = 9;
var seq = Enumerable.Range(A, B - A + 1);
Console.WriteLine(string.Join(", ", seq)); //prints 3, 4, 5, 6, 7, 8, 9
if you have lots and lots of numbers and the nature of their processing is streaming (you handle items one at a time), then you don't need to hold all of the in memory via array and it's comfortable to work with them via IEnumerable<T> interface.

Top 5 values from three given arrays

Recently i faced a question in
C#,question is:-
There are three int arrays
Array1={88,65,09,888,87}
Array2={1,49,921,13,33}
Array2={22,44,66,88,110}
Now i have to get array of highest 5 from all these three arrays.What is the most optimized way of doing this in c#?
The way i can think of is take an array of size 15 and add array elements of all three arrays and sort it n get last 5.
An easy way with LINQ:
int[] top5 = array1.Concat(array2).Concat(array3).OrderByDescending(i => i).Take(5).ToArray();
An optimal way:
List<int> highests = new List<int>(); // Keep the current top 5 sorted
// Traverse each array. No need to put them together in an int[][]..it's just for simplicity
foreach (int[] array in new int[][] { array1, array2, array3 }) {
foreach (int i in array) {
int index = highests.BinarySearch(i); // where should i be?
if (highests.Count < 5) { // if not 5 yet, add anyway
if (index < 0) {
highests.Insert(~index, i);
} else { //add (duplicate)
highests.Insert(index, i);
}
}
else if (index < 0) { // not in top-5 yet, add
highests.Insert(~index, i);
highests.RemoveAt(0);
} else if (index > 0) { // already in top-5, add (duplicate)
highests.Insert(index, i);
highests.RemoveAt(0);
}
}
}
Keep a sorted list of the top-5 and traverse each array just once.
You may even check the lowest of the top-5 each time, avoiding the BinarySearch:
List<int> highests = new List<int>();
foreach (int[] array in new int[][] { array1, array2, array3 }) {
foreach (int i in array) {
int index = highests.BinarySearch(i);
if (highests.Count < 5) { // if not 5 yet, add anyway
if (index < 0) {
highests.Insert(~index, i);
} else { //add (duplicate)
highests.Insert(index, i);
}
} else if (highests.First() < i) { // if larger than lowest top-5
if (index < 0) { // not in top-5 yet, add
highests.Insert(~index, i);
highests.RemoveAt(0);
} else { // already in top-5, add (duplicate)
highests.Insert(index, i);
highests.RemoveAt(0);
}
}
}
}
The most optimized way for a fixed K=5 is gong through all arrays five times, picking the highest element not taken so far on each pass. You need to mark the element that you take in order to skip it on subsequent passes. This has the complexity of O(N1+N2+N3) (you go through all N1+N2+N3 elements five times), which is as fast as it can get.
You can combine the arrays using LINQ, sort them, then reverse.
int[] a1 = new int[] { 1, 10, 2, 9 };
int[] a2 = new int[] { 3, 8, 4, 7 };
int[] a3 = new int[] { 2, 9, 8, 4 };
int[] a4 = a1.Concat(a2).Concat(a3).ToArray();
Array.Sort(a4);
Array.Reverse(a4);
for (int i = 0; i < 5; i++)
{
Console.WriteLine(a4[i].ToString());
}
Console.ReadLine();
Prints: 10, 9, 9, 8, 8 from the sample I provided as input for the arrays.
Maybe you could have an array of 5 elements which would be the "max values" array.
Initially fill it with the first 5 values, which in your case would just be the first array. Then loop through the rest of the values. For each value, check it against the 5 max values from least to greatest. If you find the current value from the main list is greater than the value in the max values array, insert it above that element in the array, which would push the last element out. At the end you should have an array of the 5 max values.
For three arrays of length N1,N2,N3, the fastest way should be combining the 3 arrays, and then finding the (N1+N2+N3-4)th order statistic using modified quick sort.
In the resultant array, the elements with indices (N1+N2+N3-5) to the maximum (N1+N2+N3-1) should be your 5 largest. You can also sort them later.
The time complexity of this approach is O(N1+N2+N3) on average.
Here are the two ways for doing this task. The first one is using only basic types. This is the most efficient way, with no extra loop, no extra comparison, and no extra memory consumption. You just pass the index of elements that need to be matched with another one and calculate which is the next index to be matched for each given array.
First Way -
http://www.dotnetbull.com/2013/09/find-max-top-5-number-from-3-sorted-array.html
Second Way -
int[] Array1 = { 09, 65, 87, 89, 888 };
int[] Array2 = { 1, 13, 33, 49, 921 };
int[] Array3 = { 22, 44, 66, 88, 110 };
int [] MergeArr = Array1.Concat(Array2).Concat(Array3).ToArray();
Array.Sort(MergeArr);
int [] Top5Number = MergeArr.Reverse().Take(5).ToArray()
Taken From -
Find max top 5 number from three given sorted array
Short answer: Use a SortedList from Sorted Collection Types in .NET as a min-heap.
Explanation:
From the first array, add 5 elements to this SortedList/min-heap;
Now iterate through all the rest of the elements of arrays:
If an array element is bigger than the smallest element in min-heap then remove the min element and push this array element in the heap;
Else, continue to next array element;
In the end, your min-heap has the 5 biggest elements of all arrays.
Complexity: Takes Log k time to find the minimum when you have a SortedList of k elements. Multiply that by total elements in all arrays because you are going to perform this 'find minimum operation' that many times.
Brings us to overall complexity of O(n * Log k) where n is the total number of elements in all your arrays and k is the number of highest numbers you want.

How to sort first M elements in N length array?

I have some tasks about sorting arrays in C#. I've been trying everything I could think of - no luck.
The task is to sort an array of integers by known sorting algorithms (insertion, selection, bubble, quick). Thing is, I have to sort ONLY the smallest M elements.
Example: I have an array of 7 elements 2 9 8 3 4 15 11 and I need to sort the smallest 3 elements so that my array becomes 2 3 4 9 8 15 11.
Please help, I can't seem to find anything neither here in SO, nor anywhere through Google. I don't ask to do all the algorithms for me, I just need one of those just to get hold on how's that possible.
E: Thank you for your thoughts. I've reviewed all of your recommendations and have accomplished to make an insertion sort like that:
static int[] insertSort(int[] arr, out int swaps, out int checks) {
int step = 0;
swaps = 0;
checks = 0;
for (int i = 0; i < arr.Length; i++) {
int min = arr[i], minind = i;
for (int j = i + 1; j < arr.Length; j++) {
checks++;
if (arr[j] < min) {
min = arr[j];
minind = j;
}
}
int temp = arr[minind];
if (step < M) {
for (int j = minind; j > i; j--) {
swaps++;
arr[j] = arr[j - 1];
}
arr[i] = temp;
swaps++;
step++;
}
}
return arr;
}
Swaps and checks - requirement for my application.
P.S. I've seen many times that SO doesn't like to do homework for someone. That's why I haven't asked for code, I've just asked for thoughts on how to accomplish that.
Thanks again for those who have helped me out here.
Since there is no efficiency limitations:
Set i to 0.
Look for the minimum among the not sorted elements.
Insert it into the position i, shift the array.
Increment i.
Repeat M times.
Complexity is O(N * M).
Without seeing your implementation, this is hard to answer. There are many ways to do this, and most are straight-forward.
Here are a few ideas though:
Create a "temporary" array that only holds the numbers to sort, sort it, then replace in original array (probably a sub-optimal solution)
Use a for loop that iterates the number of times you need (3 or whatever). This is probably the best solution
Post your code here on SO and some naive person will probably give you a solution so you don't have to do your schoolwork yourself. (This is a lazy and unbecoming solution)
I think here is what you are looking for, this is an example sorting of array ascending based on specific indixes.
int startIndex=2;
int endIndex=5;
int[] elements=new int[7];
elements[0]=2;
elements[1]=9;
elements[2]=8;
elements[3]=3;
elements[4]=4;
elements[5]=15;
elements[6]=11;
for (int a=startIndex-1;a<endIndex;a++){
for(int b=startIndex-1;b<endIndex;b++){
if (elements[a]<elements[b]){
int temp =elements[a];
elements[a]=elements[b];
elements[b]=temp;
}
}
}
for (int c=0;c<elements.Length;c++){
Console.Write(elements[c]+",");
}
Just change the "<" to ">" if you want to sort it desc.
You'd want to take a look at what sorting algorithm you're required to use. Say for example we're using one that uses a for loop. Most cases you'd see something like this
for(int i = 0; i < arrayName.length(); i++)
{}
In your case, just change the parameters of the for loop
for(int i = 0; i < M; i++)
{}
Where M is less than arrayName.length(); and is the number of positions from the beginning you would like to sort.
The rest of the array, untouched, should remain the same.
Couple things. Most sorting algorithms use array.length as the maximum range.
Could you just use m there instead? ie
for (int i = 0; i < m; i++)
Also, you could use a temporary array of the first m characters, sort it, then reassign.
int[] temp;
for (int i = 0; i < m; i++)
{
temp[i] = realArray[i];
}
//sort, then
for (int i = 0; i < m; i++)
{
realArray[i] = temp[i];
}
I would sort the full array and put it into the an other one.
Truncate the new array to only keep the smallest x elements.
Get the largest number from that array (in your example, 4).
Loop through the initial array and append all numbers that are higher.
Input: 2 9 8 3 4 15 11
Sort all: 2 3 4 8 9 11 15
Truncate: 2 3 4
Get highest value from this array (4)
Loop through original array and append
Is 2 higher than 4? no
Is 9 higher than 4? yes, append (we now have: 2 3 4 9)
Is 8 higher than 4? yes, append (we now have: 2 3 4 9 8)
Is 3 higher than 4? no
Is 4 higher than 4? no
Is 15 higher than 4? yes, append (we now have: 2 3 4 9 8 15)
Is 11 higher than 4? yes, append (we now have: 2 3 4 9 8 11)
*This is not the most efficient way and might cause problems if you have duplicate numbers
Any prescriptions on using LINQ?
int a[] = new int[] {2, 9, 8, 3, 4, 15, 11};
const int M = 5;
a = a.Take(M).OrderBy(e => e).ToArray(); // EDIT: Added .ToArray()

Categories

Resources