construct an array of integers to achieve specific sequence - c#

construct the shortest possible sequence of integers ending with A,
using the following rules:
the first element of the sequence is 1, each of the successive
elements is the sum of any two preceding elements (adding a single
element to itself is also permissible), each element is larger than
all the preceding elements; that is, the sequence is increasing.
For example, for A = 42, a possible solutions is [1, 2, 3, 6, 12, 24,
30, 42]. Another possible solution is [1, 2, 4, 5, 8, 16, 21, 42].
I have written the following but it fails on input of 456, by returning[1,2,4,8,16,32,64,128,200,256,456] , there are no numbers in the sequence that can be added together to get 200.
how can I fix the below code? what am I doing wrong?
public static int[] hit(int n)
{
List<int> nums = new List<int>();
int x = 1;
while (x < n)
{
nums.Add(x);
x = x * 2;
if (x > n)
{
nums.Add(n - (x / 2));
nums.Add(n);
}
}
nums.Sort();
int[] arr = nums.ToArray();
return arr;
}

I know there is gonna be a mathematical proof behind this, but my guess would be along the lines of dividing the number by 2, if it divides equally, repeat the process. If the there is a remainder, it would be 1. So you would have the integer quotient and the quotient plus one. Since one is guaranteed to be in the set, the larger of the 2 numbers is already taken care of. So just repeat the process for the smaller. This problem certainly implies a recursive solution that should be relatively trivial, so I will leave that up to the poster to implement.

I think I got it:
public Set<Integer> shortList(int n){
Set<Integer> result = new HashSet<Integer>();
Stack<Integer> stack = new Stack<Integer>();
result.add(n);
int num=n, den=0;
while(num>1){
while(num > den){
num--; den++;
if(num%den==0)
stack.push(num);
}//num>den
if(!stack.isEmpty()){
num = stack.pop();
result.add(num);
stack.clear();
}else{
result.add(num);
result.add(den);
}
den=0;
}
return result;
}//
Results (unsorted)
for 42: [1, 2, 3, 21, 6, 7, 42, 14]
for 15: [1, 2, 4, 5, 10, 15]
for 310: [1, 2, 155, 4, 5, 310, 10, 124, 62, 31, 15, 30]

Here is my solution in C++ (may be trivially changed to C#):
void printSequenceTo(unsigned n)
{
if (n == 1) { printf("1"); return; }
if (n & 1) {
int factor = 3;
do {
if (n % factor == 0) {
printSequenceTo(n / factor * (factor-1));
factor = 0;
break;
}
factor += 2;
} while (factor * factor <= n);
if (factor) printSequenceTo(n-1);
}
else
printSequenceTo(n/2);
printf(",%u", n);
}
Demonstration: http://ideone.com/8lXxc
Naturally it could be sped up using a sieve for factorization.
Note, this is significant improvement over the accepted answer, but it still is not optimal.

Here is my attempt. It may be optimised, but it shows my idea:
private static IEnumerable<int> OptimalSequence(int lastElement)
{
var result = new List<int>();
int currentElement = 1;
do
{
result.Add(currentElement);
currentElement = currentElement * 2;
} while (currentElement <= lastElement);
var realLastElement = result.Last();
if (lastElement != realLastElement)
{
result.Add(lastElement);
FixCollection(result, lastElement - realLastElement);
}
return result;
}
private static void FixCollection(List<int> result, int difference)
{
for (int i = 0; i < result.Count; i++)
{
if (result[i] == difference) break;
if (result[i] > difference)
{
result.Insert(i, difference);
FixCollection(result, difference - result[i-1]);
break;
}
}
}
Edit
I can't prove it formally but my answer and Chris Gessler's answer give sequences of the same size (at least I checked for numbers between 1 and 10000) because both algorithms compensate odd numbers.
Some examples:
Number 1535
1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1024,1535
Number 2047
1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2047
Number 3071
1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2048,3071
Number 4095
1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2047,2048,4095
Number 6143
1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2047,2048,4096,6143
Number 8191
1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2047,2048,4095,4096,8191
==============
Number 1535
1,2,4,5,10,11,22,23,46,47,94,95,190,191,382,383,766,767,1534,1535
Number 2047
1,2,3,6,7,14,15,30,31,62,63,126,127,254,255,510,511,1022,1023,2046,2047
Number 3071
1,2,4,5,10,11,22,23,46,47,94,95,190,191,382,383,766,767,1534,1535,3070,3071
Number 4095
1,2,3,6,7,14,15,30,31,62,63,126,127,254,255,510,511,1022,1023,2046,2047,4094,4095
Number 6143
1,2,4,5,10,11,22,23,46,47,94,95,190,191,382,383,766,767,1534,1535,3070,3071,6142,6143
Number 8191
1,2,3,6,7,14,15,30,31,62,63,126,127,254,255,510,511,1022,1023,2046,2047,4094,4095,8190,8191

public static int[] hit(int n)
{
List<int> nums = new List<int>();
nums.Add(n);
int x = 0;
int Right = 0;
int Left = 0;
do
{
//even num
if (n % 2 == 0)
{
x = n / 2;
//result of division is also even 20/2 = 10
if (x % 2 == 0 || n>10 )
{
nums.Add(x);
n = x;
}
else
{
nums.Add(x + 1);
nums.Add(x - 1);
n = x - 1;
}
}
//numbers that can only be divided by 3
else if (n % 3 == 0)
{
x = n / 3;//46/3 =155
Right = x * 2;//155*2 = 310
Left = x;//155
nums.Add(Right);
nums.Add(Left);
n = x;
}
//numbers that can only be divided by 5
else
{
x = n / 2;
Right = x + 1;
Left = x;
nums.Add(Right);
nums.Add(Left);
n = Left;
}
} while (n > 2);
nums.Add(1);
nums.Reverse();
int[] arr = nums.ToArray();
return arr;
}

Related

Pairs of amicable numbers

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.

Divide number into defined stacks

So basically I want to split a number, for example: 862 in C#
into stacks of 100 (or below with remainder), so it would result in:
100, 100, 100, 100, 100, 100, 100 , 100, 62
I know this is probably easily done, but I've searched and couldn't quite found a solution. I don't quite know what to search as well so that could possibly be the issue.
Cheers
This is simple division to get the number of 100 stacks and modulo to get the remainder.
int number = 862;
int stackSize = 100;
var results = Enumerable.Repeat(stackSize, number / stackSize);
if (number % stackSize > 0)
results = results.Concat(Enumerable.Repeat(number % stackSize, 1));
Console.WriteLine(string.Join(", ", results));
outputs
100, 100, 100, 100, 100, 100, 100, 100, 62
Or as a one liner (credit to spendor)
var results = Enumerable.Repeat(stackSize, number / stackSize)
.Concat(Enumerable.Repeat(number % stackSize, 1))
.Where(‌​x => x > 0);
This should do the trick:
static int[] DivideIntoStacks(int number, int stacksize)
{
int num = number;
List<int> stacks = new List<int>();
while (num > 0)
{
if (num - stacksize >= 0)
{
stacks.Add(stacksize);
num -= stacksize;
}
else
{
stacks.Add(num);
break;
}
}
return stacks.ToArray();
}
For your example, call the function with: DivideIntoStacks(862, 100)
This supplies you with an int[] with the desired values.
while the number is greater than stackSize, add a stackSize to the stack, and subtract that from the number. Once the number is less than stackSize, if there's a remainder, add that to the stack:
static void Main(string[] args)
{
int stackSize = 100;
int num = 862;
var stacks = new List<int>();
while (num > stackSize)
{
stacks.Add(stackSize);
num -= stackSize;
}
if (num > 0)
{
stacks.Add(num);
}
}
I'm sure there's some spiffy LINQ one-liner to do this as well.
int number = 862;
int d = number / 100;
if(d == 0)
{
return (d).ToString();
}
int r = number % 100;
string str = string.Join(",", Enumerable.Repeat("100", d));
if(number % 100 > 0)
str = str + ", " + r;
return str;
Example works for non whole numbers. Just check if value is less then 100 or d == 0(You can check by any of these), so return zero.
get the total number of hundreds in number and build a comma separated string.
At the end if value has some remainder with 100 append to the string with comma.

Finding the closest integer value, rounded down, from a given array of integers

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];
}

Efficient way to generate combinations ordered by increasing sum of indexes

For a heuristic algorithm I need to evaluate, one after the other, the combinations of a certain set until I reach a stop criterion.
Since they are a lot, at the moment I'm generating them using the following memory efficient iterator block (inspired by python's itertools.combinations):
public static IEnumerable<T[]> GetCombinations<T>(this IList<T> pool, int r)
{
int n = pool.Count;
if (r > n)
throw new ArgumentException("r cannot be greater than pool size");
int[] indices = Enumerable.Range(0, r).ToArray();
yield return indices.Select(idx => pool[idx]).ToArray();
while (true)
{
int i;
for (i = r - 1; i >= 0; i--)
if (indices[i] != i + n - r)
break;
if (i < 0)
break;
indices[i] += 1;
for (int j = i + 1; j < r; j++)
indices[j] = indices[j - 1] + 1;
yield return indices.Select(idx => pool[idx]).ToArray();
}
}
The problem is, to greatly improve the efficiency of my heuristic, I'd need to generate these combinations sorted by the sum of they indexes (in other words I need to generate first, the combinations containing the first elements of the set).
e.g.
Consider the set S = {0,1,2,3,4,5}
(I choose this set for simplicity since elements and their indexes coincide).
All possible combinations of r=4 numbers generated from the given algorithm are:
(0, 1, 2, 3) SUM: 6
(0, 1, 2, 4) SUM: 7
(0, 1, 2, 5) SUM: 8
(0, 1, 3, 4) SUM: 8
(0, 1, 3, 5) SUM: 9
(0, 1, 4, 5) SUM: 10
(0, 2, 3, 4) SUM: 9
(0, 2, 3, 5) SUM: 10
(0, 2, 4, 5) SUM: 11
(0, 3, 4, 5) SUM: 12
(1, 2, 3, 4) SUM: 10
(1, 2, 3, 5) SUM: 11
(1, 2, 4, 5) SUM: 12
(1, 3, 4, 5) SUM: 13
(2, 3, 4, 5) SUM: 14
where, as you can see, the combinations are not strictly sorted by ascending sum.
The desired outcome is instead the following :
(the order of the combinations having the same sum is not important)
(0, 1, 2, 3) SUM: 6
(0, 1, 2, 4) SUM: 7
(0, 1, 2, 5) SUM: 8
(0, 1, 3, 4) SUM: 8
(0, 1, 3, 5) SUM: 9
(0, 2, 3, 4) SUM: 9
(0, 1, 4, 5) SUM: 10
(0, 2, 3, 5) SUM: 10
(1, 2, 3, 4) SUM: 10
(0, 2, 4, 5) SUM: 11
(1, 2, 3, 5) SUM: 11
(0, 3, 4, 5) SUM: 12
(1, 2, 4, 5) SUM: 12
(1, 3, 4, 5) SUM: 13
(2, 3, 4, 5) SUM: 14
A trivial solution would be to generate all the combinations then sort them according to their sum; but this is not really efficient/feasible since the number of combinations becomes huge as n grows.
I also had a quick look to combinatorial Gray Codes but I couldn't find anyone suitable for this problem.
Do you have an idea on how to implement something like this ?
EDIT :
This problem has an alternate (unfortunately not easier) formulation.
Given a set S and a number r, all the possible sums are trivial to find, since they are simply all the numbers from the sum of the first r elements of S to the sum of the last r elements of S.
That being said, if, for each sum T we can efficiently¹ find all the combinations having sum T we solve the original problem since we simply generate them in ascending order.
¹ efficiently means that I don't want to generate all the combinations and discard the ones having a different sum.
EDIT 2:
After #EricLippert suggestion I created the following code:
public static IEnumerable<T[]>
GetCombinationsSortedByIndexSum<T>(this IList<T> pool, int r)
{
int n = pool.Count;
if (r > n)
throw new ArgumentException("r cannot be greater than pool size");
int minSum = ((r - 1) * r) / 2;
int maxSum = (n * (n + 1)) / 2 - ((n - r - 1) * (n - r)) / 2;
for (int sum = minSum; sum <= maxSum; sum++)
{
foreach (var indexes in AllMonotIncrSubseqOfLenMWhichSumToN(0, n - 1, r, sum))
yield return indexes.Select(x => pool[x]).ToArray();
}
}
static IEnumerable<IEnumerable<int>>
AllMonotIncrSubseqOfLenMWhichSumToN(int seqFirstElement, int seqLastElement, int m, int n)
{
for (int i = seqFirstElement; i <= seqLastElement - m + 1; i++)
{
if (m == 1)
{
if (i == n)
yield return new int[] { i };
}
else
{
foreach (var el in AllMonotIncrSubseqOfLenMWhichSumToN(i + 1, seqLastElement, m - 1, n - i))
yield return new int[] { i }.Concat(el);
}
}
}
This works fine (hopefully is what Eric meant :P) but I'm still concerned about the complexity of the recursive method. In fact it seems that we're regenerating all the combinations for each sum discarding the ones not summing up to the desired value.
To reduce the complexity of the inner function I found a way to limit the iterations by using effective upper and lower bounds (and now it's really hard to say what is the complexity of this).
Check my answer to see the final code.
The solution I had in mind was:
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
// Preconditions:
// * items is a sequence of non-negative monotone increasing integers
// * n is the number of items to be in the subsequence
// * sum is the desired sum of that subsequence.
// Result:
// A sequence of subsequences of the original sequence where each
// subsequence has n items and the given sum.
static IEnumerable<IEnumerable<int>> M(IEnumerable<int> items, int sum, int n)
{
// Let's start by taking some easy outs. If the sum is negative
// then there is no solution. If the number of items in the
// subsequence is negative then there is no solution.
if (sum < 0 || n < 0)
yield break;
// If the number of items in the subsequence is zero then
// the only possible solution is if the sum is zero.
if (n == 0)
{
if (sum == 0)
yield return Enumerable.Empty<int>();
yield break;
}
// If the number of items is less than the required number of
// items, there is no solution.
if (items.Count() < n)
yield break;
// We have at least n items in the sequence, and
// and n is greater than zero, so First() is valid:
int first = items.First();
// We need n items from a monotone increasing subsequence
// that have a particular sum. We might already be too
// large to meet that requirement:
if (n * first > sum)
yield break;
// There might be some solutions that involve the first element.
// Find them all.
foreach(var subsequence in M(items.Skip(1), sum - first, n - 1))
yield return new[]{first}.Concat(subsequence);
// And there might be some solutions that do not involve the first element.
// Find them all.
foreach(var subsequence in M(items.Skip(1), sum, n))
yield return subsequence;
}
static void Main()
{
int[] x = {0, 1, 2, 3, 4, 5};
for (int i = 0; i <= 15; ++i)
foreach(var seq in M(x, i, 4))
Console.WriteLine("({0}) SUM {1}", string.Join(",", seq), i);
}
}
The output is your desired output.
I've made no attempt to optimize this. It would be interesting to profile it and see where most of the time is spent.
UPDATE: Just for fun I wrote a version that uses an immutable stack instead of an arbitrary enumerable. Enjoy!
using System;
using System.Collections.Generic;
using System.Linq;
abstract class ImmutableList<T> : IEnumerable<T>
{
public static readonly ImmutableList<T> Empty = new EmptyList();
private ImmutableList() {}
public abstract bool IsEmpty { get; }
public abstract T Head { get; }
public abstract ImmutableList<T> Tail { get; }
public ImmutableList<T> Push(T newHead)
{
return new List(newHead, this);
}
private sealed class EmptyList : ImmutableList<T>
{
public override bool IsEmpty { get { return true; } }
public override T Head { get { throw new InvalidOperationException(); } }
public override ImmutableList<T> Tail { get { throw new InvalidOperationException(); } }
}
private sealed class List : ImmutableList<T>
{
private readonly T head;
private readonly ImmutableList<T> tail;
public override bool IsEmpty { get { return false; } }
public override T Head { get { return head; } }
public override ImmutableList<T> Tail { get { return tail; } }
public List(T head, ImmutableList<T> tail)
{
this.head = head;
this.tail = tail;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
for (ImmutableList<T> current = this; !current.IsEmpty; current = current.Tail)
yield return current.Head;
}
}
class Program
{
// Preconditions:
// * items is a sequence of non-negative monotone increasing integers
// * n is the number of items to be in the subsequence
// * sum is the desired sum of that subsequence.
// Result:
// A sequence of subsequences of the original sequence where each
// subsequence has n items and the given sum.
static IEnumerable<ImmutableList<int>> M(ImmutableList<int> items, int sum, int n)
{
// Let's start by taking some easy outs. If the sum is negative
// then there is no solution. If the number of items in the
// subsequence is negative then there is no solution.
if (sum < 0 || n < 0)
yield break;
// If the number of items in the subsequence is zero then
// the only possible solution is if the sum is zero.
if (n == 0)
{
if (sum == 0)
yield return ImmutableList<int>.Empty;
yield break;
}
// If the number of items is less than the required number of
// items, there is no solution.
if (items.Count() < n)
yield break;
// We have at least n items in the sequence, and
// and n is greater than zero.
int first = items.Head;
// We need n items from a monotone increasing subsequence
// that have a particular sum. We might already be too
// large to meet that requirement:
if (n * first > sum)
yield break;
// There might be some solutions that involve the first element.
// Find them all.
foreach(var subsequence in M(items.Tail, sum - first, n - 1))
yield return subsequence.Push(first);
// And there might be some solutions that do not involve the first element.
// Find them all.
foreach(var subsequence in M(items.Tail, sum, n))
yield return subsequence;
}
static void Main()
{
ImmutableList<int> x = ImmutableList<int>.Empty.Push(5).
Push(4).Push(3).Push(2).Push(1).Push(0);
for (int i = 0; i <= 15; ++i)
foreach(var seq in M(x, i, 4))
Console.WriteLine("({0}) SUM {1}", string.Join(",", seq), i);
}
}
For the sake of completeness and clarity I'll post my final code:
// Given a pool of elements returns all the
// combinations of the groups of lenght r in pool,
// such that the combinations are ordered (ascending) by the sum of
// the indexes of the elements.
// e.g. pool = {A,B,C,D,E} r = 3
// returns
// (A, B, C) indexes: (0, 1, 2) sum: 3
// (A, B, D) indexes: (0, 1, 3) sum: 4
// (A, B, E) indexes: (0, 1, 4) sum: 5
// (A, C, D) indexes: (0, 2, 3) sum: 5
// (A, C, E) indexes: (0, 2, 4) sum: 6
// (B, C, D) indexes: (1, 2, 3) sum: 6
// (A, D, E) indexes: (0, 3, 4) sum: 7
// (B, C, E) indexes: (1, 2, 4) sum: 7
// (B, D, E) indexes: (1, 3, 4) sum: 8
// (C, D, E) indexes: (2, 3, 4) sum: 9
public static IEnumerable<T[]>
GetCombinationsSortedByIndexSum<T>(this IList<T> pool, int r)
{
int n = pool.Count;
if (r > n)
throw new ArgumentException("r cannot be greater than pool size");
int minSum = F(r - 1);
int maxSum = F(n) - F(n - r - 1);
for (int sum = minSum; sum <= maxSum; sum++)
{
foreach (var indexes in AllSubSequencesWithGivenSum(0, n - 1, r, sum))
yield return indexes.Select(x => pool[x]).ToArray();
}
}
// Given a start element and a last element of a sequence of consecutive integers
// returns all the monotonically increasing subsequences of length "m" having sum "sum"
// e.g. seqFirstElement = 1, seqLastElement = 5, m = 3, sum = 8
// returns {1,2,5} and {1,3,4}
static IEnumerable<IEnumerable<int>>
AllSubSequencesWithGivenSum(int seqFirstElement, int seqLastElement, int m, int sum)
{
int lb = sum - F(seqLastElement) + F(seqLastElement - m + 1);
int ub = sum - F(seqFirstElement + m - 1) + F(seqFirstElement);
lb = Math.Max(seqFirstElement, lb);
ub = Math.Min(seqLastElement - m + 1, ub);
for (int i = lb; i <= ub; i++)
{
if (m == 1)
{
if (i == sum) // this check shouldn't be necessary anymore since LB/UB should automatically exclude wrong solutions
yield return new int[] { i };
}
else
{
foreach (var el in AllSubSequencesWithGivenSum(i + 1, seqLastElement, m - 1, sum - i))
yield return new int[] { i }.Concat(el);
}
}
}
// Formula to compute the sum of the numbers from 0 to n
// e.g. F(4) = 0 + 1 + 2 + 3 + 4 = 10
static int F(int n)
{
return (n * (n + 1)) / 2;
}

No of transformation steps to qualize array

Hi Can any one tell me how to solve this problem in C#.
I have an array consisting of N elements. elements in array can be positive and negative intgers.
if A=[11, 3, 7, 1]
i want to calculate minimum no of transformation steps required to make array elements equal.
each element in array can be incremented or decremented by 1.
Array A will need 5 transformation steps to get A =[6, 6, 6, 6]
In very transformation each element has to be incremented or decremented by 1.
[11, 3, 7, 1] (initial array)
[10, 4, 6, 2] (after step 1)
[9, 5, 7, 3] (after step 2)
[8, 6, 6, 4] (after step 3)
[7, 7, 5, 5] (after step 4)
[6, 6, 6, 6] (after step 5)
Some in some arrays it may not be possible.
for example it is not possible with [1,4,7] to equalise elements to one number. In Such cases it should return -1
Thanks in advance.
Well presumably you just:
Find the maximum element
Find the minimum element
The number of steps required will be half the difference between the maximum and the minimum, rounding up
You'd find the mean of the maximum and minimum element, rounding either up or down - it won't affect the number of steps - and then on each transformation step, you'd adjust each array element towards that mean.
EDIT: It's hard to see how you could get more efficient than this. In each step, the maxmimum and minimum elements can't get more than 2 closer to each other (the maximum being reduced by one, the minimum being increased by one) so the number of steps is at least half the difference, rounding up. My solution also says how you get to that state in exactly half the difference, rounding up, so it's a concrete solution, with none better.
EDIT: Here's the code to perform the transformations. Not as efficient as it can be, but it works...
using System;
using System.Linq;
class Test
{
static void Main()
{
int[] current = new[] { 1, 3, 9, 11, 5 };
// Check all odd or all even
if (current.Select(x => x % 2).Distinct().Skip(1).Any())
{
Console.WriteLine("No solution!");
return;
}
while (current != null)
{
Console.WriteLine(string.Join(" ", current));
current = Transform(current);
}
}
static int[] Transform(int[] input)
{
// We could do the "mean" calculation just once,
// but it doesn't really matter for the sake of
// demonstration
int max = input.Max();
int min = input.Min();
if (max == min)
{
// Done
return null;
}
int mean = (max + min) / 2;
return input.Select(x => x > mean ? x - 1 : x + 1)
.ToArray();
}
}
Does this work?
edit sorry, this:
public int[] Equalize(int[] arr)
{
int min = int.MaxValue;
int max = int.MinValue;
int parity = arr[0] % 2;
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] % 2 != parity) return null;
if (arr[i] < min) min = arr[i];
if (arr[i] > max) max = arr[i];
}
int diff = (max - min) / 2;
int midVal = diff + min;
return arr.Select(i => midVal).ToArray();
}
Is ROUND_DOWN(SUM(each) / N) works as expected?
Java 8 version of Jon Skeet solution
public static void main(String[] args) throws FileNotFoundException {
System.out.println(getTransformationCount(new int[] {1, 3, 9, 11, 5 }));
}
public static int getTransformationCount(int[] A) {
int count = 0;
A = Transform(A);
if (IntStream.of(A).map(n -> n % 2).distinct().skip(1).count() > 0) {
return -1;
}
while (A != null) {
A = Transform(A);
count++;
}
return count;
}
public static int[] Transform(int[] input) {
int min = Arrays.stream(input).max().getAsInt();
int max = Arrays.stream(input).min().getAsInt();
if (max == min) {
return null;
}
int mean = (max + min) / 2;
return Arrays.stream(input).map((n) -> {
if (n > mean)
return n - 1;
else
return n + 1;
}).toArray();
}

Categories