I need to make a function to take in an array of numbers and a target number and return how many different ways you can add or subtract those numbers to get the target number.
ie.
Values = 2, 4, 6, 8 Target = 12
2 + 4 + 6 = 12,
4 + 8 = 12,
6 + 8 - 2 = 12,
2 - 4 + 6 + 8 = 12,
Return 4
Here is what I have so far, but it only counts addition problems.
private void RecursiveSolve(int goal, int currentSum, List<int> included, List<int> notIncluded, int startIndex)
{
for (int index = startIndex; index < notIncluded.Count; index++)
{
int nextValue = notIncluded[index];
if (currentSum + nextValue == goal)
{
List<int> newResult = new List<int>(included);
newResult.Add(nextValue);
mResults.Add(newResult);
}
else if (currentSum - nextValue == goal)
{
List<int> newResult = new List<int>(included);
newResult.Add(nextValue);
mResults.Add(newResult);
}
if (currentSum - nextValue < goal && currentSum - nextValue > 0 )
{
List<int> nextIncluded = new List<int>(included);
nextIncluded.Add(nextValue);
List<int> nextNotIncluded = new List<int>(notIncluded);
nextNotIncluded.Remove(nextValue);
RecursiveSolve(goal, currentSum - nextValue, nextIncluded, nextNotIncluded, startIndex++);
}
if (currentSum + nextValue < goal)
{
List<int> nextIncluded = new List<int>(included);
nextIncluded.Add(nextValue);
List<int> nextNotIncluded = new List<int>(notIncluded);
nextNotIncluded.Remove(nextValue);
RecursiveSolve(goal, currentSum + nextValue, nextIncluded, nextNotIncluded, startIndex++);
}
}
}
Well, the simple way would be to try all of the combinations. If you have N numbers, you have 3^N combinations. The reasoning is this: You sum the numbers but put a coefficient in front of each of them. If your numbers are A1..AN, you add N coefficients (C1..CN) and sum:
Sum (Ai*Ci)
Your Cis can be 1 (meaning you add the number), -1 (meaning you subtract the number) or 0 (meaning you ignore the number).
So, go over all 3^N possible coefficient assignments, calculate the sum and compare to your target.
I am assuming all the numbers are different (as in your example). If a number can appear twice, you need to take that into account.
Related
I have a task to find pairs of amicable numbers and I've already solved it. My solution is not efficient, so please help me to make my algorithm faster.
Amicable numbers are two different numbers so related that the sum of the proper divisors of each is equal to the other number. The smallest pair of amicable numbers is (220, 284). They are amicable because the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110, of which the sum is 284; and the proper divisors of 284 are 1, 2, 4, 71 and 142, of which the sum is 220.
Task: two long numbers and find the first amicable numbers between them. Let s(n) be the sum of the proper divisors of n:
For example:
s(10) = 1 + 2 + 5 = 8
s(11) = 1
s(12) = 1 + 2 + 3 + 4 + 6 = 16
If s(firstlong) == s(secondLong) they are amicable numbers
My code:
public static IEnumerable<long> Ranger(long length) {
for (long i = 1; i <= length; i++) {
yield return i;
}
}
public static IEnumerable<long> GetDivisors(long num) {
return from a in Ranger(num/2)
where num % a == 0
select a;
}
public static string FindAmicable(long start, long limit) {
long numberN = 0;
long numberM = 0;
for (long n = start; n <= limit; n++) {
long sumN = GetDivisors(n).Sum();
long m = sumN;
long sumM = GetDivisors(m).Sum();
if (n == sumM ) {
numberN = n;
numberM = m;
break;
}
}
return $"First amicable numbers: {numberN} and {numberM}";
}
I generally don't write C#, so rather than stumble through some incoherent C# spaghetti, I'll describe an improvement in C#-madeup-psuedo-code.
The problem seems to be in your GetDivisors function. This is linear O(n) time with respect to each divisor n, when it could be O(sqrt(n)). The trick is to only divide up to the square root, and infer the rest of the factors from that.
GetDivisors(num) {
// same as before, but up to sqrt(num), plus a bit for floating point error
yield return a in Ranger((long)sqrt(num + 0.5)) where num % a == 0
if ((long)sqrt(num + 0.5) ** 2 == num) { // perfect square, exists
num -= 1 // don't count it twice
}
// repeat, but return the "other half"- num / a instead of a
yield return num/a in Ranger((long)sqrt(num + 0.5)) where num % a == 0
}
This will reduce your complexity of that portion from O(n) to O(sqrt(n)), which should provide a noticeable speedup.
There is a simple formula giving the sum of divisors of a number knowing its prime decomposition:
let x = p1^a1 * ... * pn^an, where pi is a prime for all i
sum of divisors = (1+p1+...+p1^a1) * ... (1+pn+...+pn^an)
= (1-p1^(a1+1))/(1-p1) * ... ((1-pn^(an+1))/(1-pn)
In order to do a prime decomposition you must compute all prime numbers up to the square root of the maximal value in your search range. This is easily done using the sieve of Erathostenes.
I have a number. For instance, my number is 19 . Then I want to populate my drop down with range in multiplication of 5. So my dropdownlist will consist of items of:
1-5
6-10
11-15
16-19
I tried modulus and division, however, I can't seems to get the range. Is there a fixed method?
Sample code
List<string> range = new List<string>();
int number = 19;
int numOfOccur = (19/5);
for (int i = 1; i < numOfOccur ; i++)
{
range.Add(i + " - " + (i * 5))
}
Sometime I think that old school code, without fancy linq is a bit more clear
int maximum = 19;
int multiple = 5;
int init = 1;
while (init + multiple <= maximum )
{
string addToDDL = init.ToString() + "-" + (init + multiple - 1).ToString();
Console.WriteLine(addToDDL);
init += multiple;
}
if(init <= maximum)
{
string last = init.ToString() + "-" + maximum.ToString();
Console.WriteLine(last);
}
Linq solution (modern techs allow us to put it consize):
int number = 19;
int div = 5;
List<string> range = Enumerable
.Range(0, number / div + (number % div == 0 ? 0 : 1))
.Select(i => $"{i * div + 1} - {Math.Min((i + 1) * div, number)}")
.ToList();
Test
Console.Write(string.Join(Environment.NewLine, range));
Returns
1 - 5
6 - 10
11 - 15
16 - 19
When using modulo arithmetics, do not forget about remainders: you have an error in int numOfOccur = (19/5); line. It should be
int numOfOccur = 19 / 5 + (19 % 5 == 0 ? 0 : 1);
for the last incomplete 16 - 19 range to be proceeded.
Add this package to your project : https://www.nuget.org/packages/System.Interactive/
Then you can do this:
IEnumerable<IList<int>> buffers2 = Enumerable.Range(1, 19).Buffer(5);
IList<int>[] result2 = buffers2.ToArray();
// { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, ...
Don't forget to add System.Interactive namespace to your using block.
Assume I have a list of integers of any length, for an example I have the list of 1,3,5 and 7.
I would like an algorithm to pick a combination of X elements from the list.
For example, X = 1 would return:
1
3
5
7
x = 2 would return:
1 + 1
1 + 3
1 + 5
1 + 7
3 + 3
3 + 5
3 + 7
5 + 5
5 + 7
7 + 7
var listOfInts = new List<int> { 1, 3, 5, 7 };
var combinedInts = new List<int>();
// x = 1 solution
// This is only picking one item from the list.
for (int i = 0; i < listOfInts.Count(); i++)
{
combinedInts.Add(listOfInts[i]);
}
// x = 2 solution
// This is how to pick two. I wrap it around another for loop.
for (int i = 0; i < listOfInts.Count(); i++)
{
for (int j = i; j < listOfInts.Count(); j++)
{
combinedInts.Add(listOfInts[i] + listOfInts[j]);
}
}
// x = 3 solution
// If I go up another level I have to wrap it around another for loop. This solution won't scale.
for (int i = 0; i < listOfInts.Count(); i++)
{
for (int j = i; j < listOfInts.Count(); j++)
{
for (int k = j; k < listOfInts.Count(); k++)
{
combinedInts.Add(listOfInts[i] + listOfInts[j] + listOfInts[k]);
}
}
}
This solution doesn't scale as I have to continually wrap around another for loop for each number of element I'm picking. For example X = 7 would need 7-nested for loops. Is there a better way to write this method that doesn't involve nesting for loops?
You can use the following to get combinations of the sequences:
public static class LinqHelper
{
public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int? k = null)
{
if (!k.HasValue)
k = elements.Count();
return k == 0 ? new[] { new T[0] } :
elements.SelectMany((e, i) => elements.Skip(i).Combinations(k - 1).Select(c => (new[] { e }).Concat(c)));
}
}
var list = new List<int> { 1, 3, 5, 7 };
int x = 2; //Change to 3, 4, 5, etc
var result = list.Combinations(x);
Yields:
1 1
1 3
1 5
1 7
3 3
3 5
3 7
5 7
7 7
To get the sum of each one, you'd aggregate the result:
var result = list.Combinations(x).Select(g => g.Aggregate((left, right) => left + right));
Which produces:
2
4
6
8
6
8
10
10
12
14
There is also a purely iterative way to do this. It requires a great deal more thought and complexity, but can be made very efficient. The basic idea is to simulate the same nested loops, but track the iterations of each nested loop as an array of loop counters, which are iterated forward in the same manner as the original nested loop code. Here is a fully working example:
var listOfInts = new List<int> { 1, 3, 5, 7 };
var combinedInts = new List<int>();
var numInts = listOfInts.Count;
var numElements = 5; // number of "nested loops", or ints selected in each combination
var loopCounters = new int[numElements]; // make one loop counter for each "nested loop"
var lastCounter = numElements - 1; // iterate the right-most counter by default
// maintain current sum in a variable for efficiency, since most of the time
// it is changing only by the value of one loop counter change.
var tempSum = listOfInts[0] * numElements;
// we are finished when the left/outer-most counter has looped past number of ints
while (loopCounters[0] < numInts) {
// you can use this to verify the output is iterating correctly:
// Console.WriteLine(string.Join(",", loopCounters.Select(x => listOfInts[x])) + ": " + loopCounters.Select(x => listOfInts[x]).Sum() + "; " + tempSum);
combinedInts.Add(tempSum);
tempSum -= listOfInts[loopCounters[lastCounter]];
loopCounters[lastCounter]++;
if (loopCounters[lastCounter] < numInts) tempSum += listOfInts[loopCounters[lastCounter]];
// if last element reached in inner-most counter, increment previous counter(s).
while (lastCounter > 0 && loopCounters[lastCounter] == numInts) {
lastCounter--;
tempSum -= listOfInts[loopCounters[lastCounter]];
loopCounters[lastCounter]++;
if (loopCounters[lastCounter] < numInts) tempSum += listOfInts[loopCounters[lastCounter]];
}
// if a previous counter was advanced, reset all future counters to same
// starting number to start iteration forward again.
while (lastCounter < numElements - 1) {
lastCounter++;
if (loopCounters[lastCounter] < numInts) tempSum -= listOfInts[loopCounters[lastCounter]];
loopCounters[lastCounter] = loopCounters[lastCounter - 1];
if (loopCounters[lastCounter] < numInts) tempSum += listOfInts[loopCounters[lastCounter]];
}
}
At the end of the iteration, combinedInts should contains a list of all sum combinations, similar to the original code or the other recursive solutions. If you are working with small sets, and small combinations, then this level of efficiency is unnecessary and you should prefer a recursive solution which is easier to reason about correctness. I present this as an alternative way to think about the problem. Cheers!
This works for me:
Func<IEnumerable<int>, int, IEnumerable<IEnumerable<int>>> generate = null;
generate = (xs, n) =>
(xs == null || !xs.Any())
? Enumerable.Empty<IEnumerable<int>>()
: n == 1
? xs.Select(x => new [] { x })
: xs.SelectMany(x => generate(xs, n - 1).Select(ys => ys.Concat(new [] { x })));
int[] array = { 1, 3, 5, 7, };
var results =
generate(array, 3)
.Select(xs => String.Join("+", xs));
With this call I get:
1+1+1, 3+1+1, 5+1+1, 7+1+1, 1+3+1, 3+3+1, 5+3+1, 7+3+1, 1+5+1, 3+5+1, 5+5+1, 7+5+1, 1+7+1, 3+7+1, 5+7+1, 7+7+1, 1+1+3, 3+1+3, 5+1+3, 7+1+3, 1+3+3, 3+3+3, 5+3+3, 7+3+3, 1+5+3, 3+5+3, 5+5+3, 7+5+3, 1+7+3, 3+7+3, 5+7+3, 7+7+3, 1+1+5, 3+1+5, 5+1+5, 7+1+5, 1+3+5, 3+3+5, 5+3+5, 7+3+5, 1+5+5, 3+5+5, 5+5+5, 7+5+5, 1+7+5, 3+7+5, 5+7+5, 7+7+5, 1+1+7, 3+1+7, 5+1+7, 7+1+7, 1+3+7, 3+3+7, 5+3+7, 7+3+7, 1+5+7, 3+5+7, 5+5+7, 7+5+7, 1+7+7, 3+7+7, 5+7+7,7+7+7
I am trying to figure out the best way to find the closest value, ROUNDED DOWN, in a List of integers using any n that is between two other numbers that are stored in a List. The all integers in this situation will ALWAYS be unsigned, in case that helps.
The assumptions are as follows:
The List always starts at 0
The List is always sorted ASC
All integers in the List are unsigned (no need for Math.Abs)
The number for comparison is always unsigned
For example:
List<int> numbers = new List<int>() { 0, 2000, 4000, 8000, 8500, 9101, 10010 };
int myNumber = 9000;
int theAnswer; // should be 8500
for (int i = 0; i < numbers.Count; i++) {
if (i == numbers.Count - 1) {
theAnswer = numbers[i];
break;
} else if (myNumber < numbers[i + 1]) {
theAnswer = numbers[i];
break;
}
}
The previous code example works without any flaws.
Is there a better more succint way to do it?
You can use List<T>.BinarySearch instead of enumerating elements of list in sequence.
List<int> numbers = new List<int>() { 0, 2000, 4000, 8000, 8500, 9101, 10010 };
int myNumber = 9000;
int r=numbers.BinarySearch(myNumber);
int theAnswer=numbers[r>=0?r:~r-1];
Filter list obtaining all values less than the myNumber and return last one:
theAnswer = numbers.Where(x => x <= myNumber ).Last();
A list can be indexed.
Start at the index in the middle of the list. If you found the exact number, you are good. If the number is less than the target number, search in the middle of the range from the start of the list to one less than the middle of the list. If the number is greater than the target number, work with the opposite half of the list. Continue this binary search until you find either an exact match, or the adjacent numbers that are smaller and larger than the target number.
Select the smaller of the two.
Please try this code:
List<int> numbers = new List<int>() { 0, 2000, 4000, 8000, 8500, 9101, 10010 };
int myNumber = 9000;
int theAnswer = numbers[numbers.Count - 1];
if (theAnswer > myNumber)
{
int l = 0, h = numbers.Count - 1, m;
do
{
m = (int)((double)(myNumber - numbers[l]) / (double)(numbers[h] - numbers[l]) * (h - l) + l);
if (numbers[m] > myNumber) h = m; else l = m;
}
while ((h - l) != 1);
theAnswer = numbers[l];
}
This is my code:
SortedDictionary<int,int> Numbers = new SortedDictionary<int,int>();
List<int> onlyP = new List<int>(Numbers.Keys);
int Inferior = int.Parse(toks[0]);
int Superior = int.Parse(toks[1]);
int count = 0;
int inferiorindex = Array.BinarySearch(Numbers.Keys.ToArray(), Inferior);
if (inferiorindex < 0) inferiorindex = (inferiorindex * -1) - 1;
int superiorindex = Array.BinarySearch(Numbers.Keys.ToArray(), Superior);
if (superiorindex < 0) superiorindex = (superiorindex * -1) - 1;
count = Numbers[onlyP[superiorindex]] - Numbers[onlyP[inferiorindex]];
So what I'm trying to do is this: I've got a sorted dictionary with powers as keys, and a normal iteration as values. I've to print how many numbers of the keys fit within a specified range.
Example:
Some entries of the dict: [1,1],[4,2],[8,3],[9,4],[16,5],[25,6],[27,7],[32,8]
Limits: 2 and 10
Numbers within 2 - 10 : 4, 8, 9 = 3 numbers.
With BinarySearch I'm trying to quickly find the numbers I want and then substract Potencias[onlyP[superiorindex]] - Potencias[onlyP[inferiorindex]] to find how many numbers are within the range. Unfortunately it's not working for all the cases, and it sometimes gives less numbers than the actual amount. How can this be fixed? Thanks in advance.
[EDIT] Examples of the problems: If I select limits: 4 and 4... it returns 0, but the answer is 1.
limits: 1 and 10^9 (the whole range) returns 32669... But the answer is 32670.
The algorithm is ignoring powers.
Finally, having read the documentation. Notice the -1 on the upperIndex conversion and the +1 on the return value, these are important.
var numbers = new[] { 1, 4, 8, 9, 16, 25, 27, 32 };
var lowerBound = 4;
var upperBound = 17;
int lowerIndex = Array.BinarySearch(numbers, lowerBound);
if (lowerIndex < 0) lowerIndex = ~lowerIndex;
// - 1 here because we want the index of the item that is <= upper bound.
int upperIndex = Array.BinarySearch(numbers, upperBound);
if (upperIndex < 0) upperIndex = ~upperIndex - 1;
return (upperIndex - lowerIndex) + 1;
Explanation:
For the lower index we just take the complement because the BinarySearch returns the index of the first item >= lowerBound.
For the upper index we additionally minus one from the complement because we want the first item <= upperBound (not >= upperBound which is what BinarySearch returns).
It seems that you're not doing it the wright way for post processing the binary search return value :
http://msdn.microsoft.com/en-us/library/5kwds4b1.aspx
Should be :
if (inferiorindex < 0) inferiorindex = ~inferiorindex;
(untested)
Moreover, List supports a binary search, so you don't have to do the Array.BinarySearch thing, just work on onlyP.
int inferiorindex = Array.BinarySearch<int>(keys, Inferior);
if (inferiorindex < 0) {
inferiorindex = ~inferiorindex;
}
int superiorindex = Array.BinarySearch<int>(keys, Superior);
if (superiorindex < 0) {
// superiorindex is the binary complement of the next higher.
// -1 because we want the highest.
superiorindex = ~superiorindex - 1;
}
int count = superiorindex - inferiorindex + 1;