Related
Got stuck on quite simple problem in my code. I need to count what I would call a nested sums of an array. Let's take as an example the array:
[1,2,2,3,6]
I want to sum them as:
0 + 1 = 1
1 + 2 = 3
1 + 2 + 2 = 5
1 + 2 + 2 + 3 = 8
1 + 2 + 2 + 3 + 6 = 14
sum = 1 + 3 + 5 + 8 + 14 = 31
Edit:
I tried to do it with stack, but it failed
int sums = 0;
Stack<int> sum = new Stack<int>();
for (int i = 0; i < queries.Length; i++)
{
sum.Push(queries[i]);
}
for (int i = 0; sum.Count != 0; i++)
{
if(i != 0)
{
sums += sum.Pop();
}
}
You can run this task in a single loop considering when you have an array of size 5, the first element is repeating 5 times, second element repeating 4 times and etc.
int[] arr = { 1, 2, 2, 3, 6 };
int mysum = 0;
for (int i = 0; i < arr.Length; i++)
mysum += (arr.Length - i) * arr[i];
Console.WriteLine(mysum);
Output:
31
Explanation:
1 = 1
1 + 2 = 3
1 + 2 + 2 = 5
1 + 2 + 2 + 3 = 8
1 + 2 + 2 + 3 + 6 = 14
========================
5*1 + 4*2 + 3*2 + 2*3 + 1*6 = 31
You can do this much more efficiently and more easily, by multiplying each value by its reversed index + 1
For example, using LINQ
int[] arr = { 1, 2, 2, 3, 6 };
var result = arr.Reverse().Select((val, i) => val * (i + 1)).Sum();
Note that .Reverse on an array (or other Collection<T>) does not actually move any items, it just reads them backwards. So this is therefore an O(n) operation, as opposed to your original solution which is O(n2 / 2)
dotnetfiddle
You can also do this procedurally, this is almost the same as #aminrd's answer.
int[] arr = { 1, 2, 2, 3, 6 };
var result = 0;
for (var i = arr.Length - 1; i >= 0; i--)
result += arr[i] * (i + 1);
Take advantage of Linq! .Sum() will add up everything in your collection. You run that twice, once per each slice, and once per each subtotal.
var input = new [] { 1, 2, 2, 3, 6 };
var totalSum = Enumerable.Range(1, input.Length).Sum(len => input[0..len].Sum());
// totalSum is 31
Enumerable.Range gets you a collection of numbers between (and including) 1 and 5 - the possible lengths of each slice of your sub arrays. You then use the range operator [0..#] to get increasingly larger slices.
Yes, this is not as clever as aminrd's solution - it's doing all the computations manually and you're performing many slices.
Let's say I have an array with integers, which represent the daily changes in the price of a stock, as an example the following array:
[3, -1, -4, 1, 5, -9, 2, 6].
How would I find the amount of subarrays which have a sum between two values (lower and upper, so l <= s <= u), such as -1 (=lower) and 0 (=upper)? In this case, the answer would be 5. You can have the subarrays
[3, -1, -4, 1]
[-1]
[-1, -4, 1, 5, -9, 2, 6]
[1, 5, -9, 2]
[-9, 2, 6]
Another example array would be:
[4, 2, 2, -6, 7]
with lower bound 3, upper bound 4. The answer to this would be 3. I have tried the following very naïve approach, which I'm certain there are many faster alternatives for. I'm wondering how I can solve this problem faster, with divide-and-conquer or possibly through dynamically programming.
Class
public class Stock
{
public int sequenceLength;
public int[] prices;
public int lowerBound;
public int upperBound;
public int count = 0;
public Stock()
{
sequenceLength = Int32.Parse(Console.ReadLine());
prices = new int[sequenceLength];
var split = Console.ReadLine();
var splitSpace = split.Split(' ');
for (int i = 0; i < sequenceLength; i++)
prices[i] = Int32.Parse(splitSpace[i]);
lowerBound = Int32.Parse(Console.ReadLine());
upperBound = Int32.Parse(Console.ReadLine());
}
}
Usage
static void Main(string[] args)
{
int testcases = Int32.Parse(Console.ReadLine());
Stock[] stock = new Stock[testcases];
for (int i = 0; i < testcases; i++)
stock[i] = new Stock();
int count = 0;
for (int i = 0; i < stock.Length; i++)
{
for (int j = 0; j < stock[i].sequenceLength - 1; j++)
{
int sum = stock[i].prices[j];
if (sum >= stock[i].lowerBound && sum <= stock[i].upperBound)
count++;
for (int k = j + 1; k < stock[i].sequenceLength; k++)
{
sum += stock[i].prices[k];
if (sum >= stock[i].lowerBound && sum <= stock[i].upperBound)
count++;
}
}
if (stock[i].prices[stock[i].sequenceLength - 1] >= stock[i].lowerBound && stock[i].prices[stock[i].sequenceLength - 1] <= stock[i].upperBound)
count++;
stock[i].count = count;
count = 0;
}
Console.Clear();
for (int i = 0; i < stock.Length; i++)
Console.WriteLine(stock[i].count);
}
There's already an answer with O(N^2) complexity, I'll propose a O(NlogN) solution.
Create an array sums, where sums[0] = array[0] and sums[i] = sums[i-1]+array[i]. Now, for each index i in sums, you need to find number of indexes j such that sums[i] - sums[j] is in range [lower, upper]. But how to find number of indexes j?
Create a balanced binary search tree (AVL tree). Insert sums[0] in it. Start processing nodes from left to right. After processing a node, add it to the tree. You can search for the number of indexes in range [lower, upper] in O(logN) complexity, and same applies for the insertion as well. That will give you a total time complexity of O(NlogN).
If I understand the problem (and the jury is out)
The premise is, the first loop works its way across the array. The second loop is in charge of keeping a sum and checking the range, then yielding the result
Obviously this is O(n2) time complexity
Given
public static IEnumerable<int[]> GetSubs(int[] source, int lower, int upper)
{
for (var i = 0; i < source.Length; i++)
for (int j = i, sum = 0; j < source.Length; j++)
{
sum += source[j];
if (sum >= lower && sum <= upper)
yield return source[i..(j+1)];
}
}
Usage
var array = new[] { -5, -4, -3, -2, -1, 0, 2, 3, 4, 5, 6, 7, 8, 9 };
foreach (var sequence in GetSubs(array,2,5))
Console.WriteLine($"{sequence.Sum()} : [{string.Join(", ", sequence)}]");
Output
5 : [-5, -4, -3, -2, -1, 0, 2, 3, 4, 5, 6]
4 : [-4, -3, -2, -1, 0, 2, 3, 4, 5]
3 : [-3, -2, -1, 0, 2, 3, 4]
2 : [-2, -1, 0, 2, 3]
4 : [-1, 0, 2, 3]
2 : [0, 2]
5 : [0, 2, 3]
2 : [2]
5 : [2, 3]
3 : [3]
4 : [4]
5 : [5]
Full Demo Here
Note : You could probably do this in linq with Enumerable.Range, however this is pretty easy to understand
If you just wanted the count, you could remove the iterator all together, and just increment a counter when the if condition is true
public static int GetSubs(int[] source, int lower, int upper)
{
var result = 0;
for (var i = 0; i < source.Length; i++)
for (int j = i, sum = 0; j < source.Length; j++)
{
sum+= source[j];
if (sum >= lower && sum <= upper)
result++;
}
return result;
}
I have this question:
Given a grid of positive numbers, start from 0,0 and end at n,n.
Move only to right and down.
Find path with sum of numbers is maximum.
Input Example:
5 1 2
6 7 8
1 4 9
output Example:
35
I solved it with many scenarios for example i wrote an easy equation to get the max path length then take some decisions to get the correct result.
But this example is easy to got that it should solved using dynamic programming as it's recursion and some overlaps with small space:
fn(0,0)
fn(0,1) f(1,0)
f(0,2) f(1,1) f(2,0) f(1,1)
I solved it easy using Memoization technique:
public int GetMaxPathTopDown(int r, int c, int[,] arr, int[,] mem)
{
if (r >= arr.GetLength(0) || c >= arr.GetLength(1))
{
return 0;
}
// Base Case
if (r == arr.GetLength(0) - 1 && c == arr.GetLength(1) - 1)
{
return arr[r, c];
}
if (mem[r, c] != -1)
{
return mem[r, c];
}
int firstPath = GetMaxPathTopDown(r, c + 1, arr, mem);
int secondPath = GetMaxPathTopDown(r + 1, c, arr, mem);
return mem[r, c] = arr[r, c] + Math.Max(firstPath, secondPath);
}
but I want to find standard solution to solve it using Tabulation way. I tried many solutions but i thought it's not a correct way of tabulation so any help?
#Marzouk, you can try this:
dp[i, j] will be the maximum sum you can get from (0, 0) to (i, j). Now, dp[i, j] will depend on dp[i - 1, j] and dp[i, j - 1]. So, the recurrence will be:
dp[i, j] = max(dp[i - 1, j], dp[i, j - 1]) + mt[i, j]
You need to handle corner cases here (i = 0 or j = 0).
using System;
class MainClass {
public static void Main (string[] args) {
int[,] mt = new[,] { {5, 1, 2}, {6, 7, 8}, {1, 4, 9} };
int[,] dp = new[,] { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} };
int R = mt.GetLength(0);
int C = mt.GetLength(1);
for (int i = 0; i < R; i++)
for (int j = 0; j < C; j++) {
dp[i, j] = mt[i, j];
if (i > 0 && j > 0) {
dp[i, j] += Math.Max(dp[i - 1, j], dp[i, j - 1]);
} else if (i > 0) {
dp[i, j] += dp[i - 1, j];
} else if (j > 0) {
dp[i, j] += dp[i, j - 1];
}
}
Console.WriteLine(dp[R-1, C-1]);
}
}
The basic steps to build bottom-up dynamic programming solutions are as follows:
1- Determine the required set of parameters that uniquely describe the problem (the state).
2- If there are N parameters required to represent the states, prepare an N dimensional DP table, with one entry per state.
This is equivalent to the memo table in top-down DP. However, there are differences. In bottom-up DP, we only need to initialize some cells of the DP table with known initial values (the base cases). Recall that in topdown DP, we initialize the memo table completely with dummy values (usually -1) to indicate that we have not yet computed the values.
3- Now, with the base-case cells/states in the DP table already filled, determine the cells/states that can be filled next (the transitions).
Repeat this process until the DP table is complete.
For the bottom-up DP, this part is usually accomplished through iterations, using loops.
lets build a table for 3*3 array with values:
5 1 2
3 1 2
0 1 1
we notice that we need two parameters : Move_right, Move_down
initially, the first row and column should have the cumulative sum of the array elements to start maximization
then follow the steps in the attached picture which explain the code below
dp[0,0] = arr[0,0];
for (int i = 1; i < n; i++){
dp[0,i] = arr[0,i] + dp[0,i - 1];
}
for (int i = 1; i < n; i++){
dp[i,0] = arr[i,0] + dp[i-1,0];
}
for (int i = 1; i < n; i++){
for (int j = 1; j < n; j++){
dp[i,j] = arr[i,j] + Math.max(dp[i - 1,j], dp[i,j - 1]);
}
}
Console.WriteLine(dp[n - 1,n - 1]);
the required answer should be 12, and you find it in the most right-down cell
building table
I am working on a Visa credit card generator and I'm not seeing the problem with the following:
My code seems to work for 16 digit card numbers, however, it doesn't seem to work for 13 digit cards, as the generated card numbers are invalid on both online testers and on my app.
Code:
var randomNum = new Random();
int [] lengths = new int[] { 13, 16 };
int length = lengths[randomNum.Next(lengths.Length)];
int [] str;
int [] reversed;
var lastDigit = 0;
var sum = 0;
if (length == 16)
{
str = new int[16];
reversed = new int[15];
}
else
{
str = new int[13];
reversed = new int[12];
}
Random rnd = new Random();
while (pos < length - 1)
{
str[pos++] = rnd.Next(0, 9);
}
for (int i = 0; i < str.Length - 1; i++)
{
reversed[i] = str[str.Length - i - 2];
}
for (pos = 0; pos < length - 1; pos++)
{
if (pos % 2 == 0 && length == 16)
{
reversed[pos] *= 2;
if (reversed[pos] > 9)
reversed[pos] = reversed[pos] - 9;
}
else if (pos % 2 == 1 && length == 13)
{
reversed[pos] *= 2;
if (reversed[pos] > 9)
reversed[pos] = reversed[pos] - 9;
}
sum += reversed[pos];
}
lastDigit = (10 - (sum % 10)) % 10;
str[length - 1] = lastDigit;
I apologize for copying the whole code, but I thought it would make things more understandable.
The algorithm I followed from http://www.freeformatter.com/credit-card-number-generator-validator.html:
Drop the last digit from the number. The last digit is what we want to check against
Reverse the numbers
Multiply the digits in odd positions (1, 3, 5, etc.) by 2 and
subtract 9 to all any result higher than 9
Add all the
numbers together
The check digit (the last number of the card) is the amount that you
would need to add to get a multiple of 10 (Modulo 10)
Sample card numbers generated by my code:
16 digit: 4145422641287432 - Valid
13 digit: 4354735186403 - Invalid
(The sum before adding the check
digit was 47 meaning 3 would be the check digit resulting in the whole sum being 50 => 50%10=0)
What exactly am I doing wrong here?
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++;
}
}
}
}