Counting huge permutations - counting elements and getting nth element - c#

I am using this library for combinatorics:
https://github.com/eoincampbell/combinatorics/
What I need is to find n-th permutation and count elements of fairly large sets (up to about 30 elements), but I get stopped in my tracks before even starting, check out this code:
int[] testSet = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21};
var permutation = new Permutations<int>(testSet);
var test = permutation.Count;
Everything works peachy just until 20 element large set, once I add 21st, permutations stop working right, eg.
here is what permutation.Count returns:
-4249290049419214848
which is far from being the right number.
I am assuming that it all boils down to how huge numbers I use - overflowing ints/longs that library uses. That is why, I am asking for an advice - is there a library? approach? or a fairly quick to implement way to have combinatorics work on bigintegers?
Thanks!

Get the number of possible permuations.
The number of permutations is defined by nPr or n over r
n!
P(n,r) = --------
(n - r)!
Where:
n = Number of objects
r = the size of the result set
In your example, you want to get all permutations of a given list. In this case n = r.
public static BigInteger CalcCount(BigInteger n, BigInteger r)
{
BigInteger result = n.Factorial() / (n - r).Factorial();
return result;
}
public static class BigIntExtensions
{
public static BigInteger Factorial(this BigInteger integer)
{
if(integer < 1) return new BigInteger(1);
BigInteger result = integer;
for (BigInteger i = 1; i < integer; i++)
{
result = result * i;
}
return result;
}
}
Get the nTh permutation
This one depends on how you create/enumerate the permutations. Usually to generate any permutation you do not need to know all previous permutations. In other words, creating a permutation could be a pure function, allowing you to directly create the nTh permutation, without creating all possible ones.
This, however, depends on the algorithms used. But will potentially be a lot faster to create the permutation only when needed (in contrast to creating all possible permutations up front -> performance and very memory heavy).
Here is a great discussion on how to create permutations without needing to calculate the previous ones: https://stackoverflow.com/a/24257996/1681616.

This is too long for a comment, but wanted to follow up on #Iqon's solution above. Below is an algorithm that retrieves the nth lexicographical permutation:
public static int[] nthPerm(BigInteger myIndex, int n, int r, BigInteger total)
{
int j = 0, n1 = n;
BigInteger temp, index1 = myIndex;
temp = total ;
List<int> indexList = new List<int>();
for (int k = 0; k < n; k++) {
indexList.Add(k);
}
int[] res = new int[r];
for (int k = 0; k < r; k++, n1--) {
temp /= n1;
j = (int) (index1 / temp);
res[k] = indexList[j];
index1 -= (temp * j);
indexList.RemoveAt(j);
}
return res;
}
Here is a test case and the result of calling nthPerm using the code provided by #Iqon.
public static void Main()
{
int[] testSet = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21};
BigInteger numPerms, n, r;
n = testSet.Length;
r = testSet.Length;
numPerms = CalcCount(n, r);
Console.WriteLine(numPerms);
BigInteger testIndex = new BigInteger(1234567890987654321);
int[] myNthIndex = nthPerm(testIndex, (int) n, (int) r, numPerms);
int[] myNthPerm = new int[(int) r];
for (int i = 0; i < (int) r; i++) {
myNthPerm[i] = testSet[myNthIndex[i]];
}
Console.WriteLine(string.Join(",", myNthPerm));
}
// Returns 1,12,4,18,20,19,7,5,16,11,6,8,21,15,13,2,14,9,10,17,3
Here is a link to ideone with working code.

You can useJNumberTools
List<String> list = new ArrayList<>();
//add elements to list;
JNumberTools.permutationsOf(list)
.uniqueNth(1000_000_000) //next 1 billionth permutation
.forEach(System.out::println);
This API will generate the next nth permutation directly in lexicographic order. So you can even generate next billionth permutation of 100 items.
for generating next nth permutation of given size use:
maven dependency for JNumberTools is:
<dependency>
<groupId>io.github.deepeshpatel</groupId>
<artifactId>jnumbertools</artifactId>
<version>1.0.0</version>
</dependency>

Related

Int Array Reorder with Even Distribution in C#?

12,13,14,15,16,19,19,19,19
to
12,19,13,19,14,19,15,19,16
Hey all. Can anyone point me to clues/samples on how to distribute the first array of Int32 values, where a bunch of 19 values were appended, to the second where the 19 values are fairly evenly interspersed in the array?
I am not looking for a random shuffling, as in this example #19 could still appear consecutively if there was randomization. I want to make sure that #19 is placed in between the other numbers in a predictable pattern.
The use-case for this is something like teams taking turns presenting a topic: teams 12-16 each present once and then team #19 shows up but should not show their topic four times in a row, they should show their topic in between the other teams.
Later, if twelve values of 7 are added to the array, then they will also have to be evenly distributed into the sequence as well, the array would be 21 elements but the same rule that neither #19 or #7 should have consecutive showings.
I thought there might be something in Math.NET library that would do this, but I did not find anything. Using C# on .NET Framework 4.7.
Thanks.
Details on the following method that evenly (mostly) distributes the duplicates in your list. Duplicates can be anywhere in your list, they will be distributed.
Create a dictionary of all numbers and keep track of the number of times they appear in the list
Use a new list without any duplicates. For Each number that has duplicates, spread it over the size of this new list. Each time the distribution is even.
public static List<int> EvenlyDistribute(List<int> list)
{
List<int> original = list;
Dictionary<int, int> dict = new Dictionary<int, int>();
list.ForEach(x => dict[x] = dict.Keys.Contains(x) ? dict[x] + 1 : 1);
list = list.Where(x => dict[x] == 1).ToList();
foreach (int key in dict.Where(x => x.Value > 1).Select(x => x.Key))
{
int iterations = original.Where(x => x == key).Count();
for (int i = 0; i < iterations; i++)
list.Insert((int)Math.Ceiling((decimal)((list.Count + iterations) / iterations)) * i, key);
}
return list;
}
Usage in main:
List<int> test = new List<int>() {11,11,11,13,14,15,16,17,18,19,19,19,19};
List<int> newList = EvenlyDistribute(test);
Output
19,11,13,19,14,11,19,15,16,19,11,17,18
Here's how to do this.
var existing = new[] { 12, 13, 14, 15, 16 };
var additional = new [] { 19, 19, 19, 19 };
var lookup =
additional
.Select((x, n) => new { x, n })
.ToLookup(xn => xn.n * existing.Length / additional.Length, xn => xn.x);
var inserted =
existing
.SelectMany((x, n) => lookup[n].StartWith(x))
.ToArray();
This gives me results like 12, 19, 13, 19, 14, 19, 15, 19, 16.
The only thing that this won't do is insert a value in the first position, but otherwise it does evenly distribute the values.
In case random distribution is enough the following code is sufficient:
static void MixArray<T>(T[] array)
{
Random random = new Random();
int n = array.Length;
while (n > 1)
{
n--;
int k = random.Next(n + 1);
T value = array[k];
array[k] = array[n];
array[n] = value;
}
}
For instance:
int[] input = new int[]{12,13,14,15,16,19,19,19,19};
MixArray<int>(input);
In case you require precise evenly distribution while retaining the order of the elements, to following code will do the job:
public static T[] EvenlyDistribute<T>(T[] existing, T[] additional)
{
if (additional.Length == 0)
return existing;
if (additional.Length > existing.Length)
{
//switch arrays
T[] temp = additional;
additional = existing;
existing = temp;
}
T[] result = new T[existing.Length + additional.Length];
List<int> distribution = new List<int>(additional.Length);
double ratio = (double)(result.Length-1) / (additional.Length);
double correction = -1;
if (additional.Length == 1)
{
ratio = (double)result.Length / 2;
correction = 0;
}
double sum = 0;
for (int i = 0; i < additional.Length; i++)
{
sum += ratio;
distribution.Add(Math.Max(0, (int)(sum+correction)));
}
int existing_added = 0;
int additional_added = 0;
for (int i = 0; i < result.Length; i++)
{
if (additional_added == additional.Length)
result[i] = existing[existing_added++];
else
if (existing_added == existing.Length)
result[i] = additional[additional_added++];
else
{
if (distribution[additional_added] <= i)
result[i] = additional[additional_added++];
else
result[i] = existing[existing_added++];
}
}
return result;
}
For instance:
int[] existing = new int[] { 12, 13, 14, 15, 16};
int[] additional = new int[] { 101, 102, 103, 104};
int[] result = EvenlyDistribute<int>(existing, additional);
//result = 12, 101, 13, 102, 14, 103, 15, 104, 16

Previous index in an array c#

I have an array initialized as such:
int[] myArray = new int[] {9, 8, 7, 3, 4, 5, 6, 2, 1};
I then have a for() loop searching the array for the highest value each time using:
int maxValue = myArray.Max();
int maxIndex = myArray.ToList().IndexOf(maxValue);
It obviously keeps finding 9 as the highest value.
I want it to first set the previously indexed value to a randomized value below the current maxValue but above -1 and continue searching the array for the next maxValue and print it to console.
(If all values reach a value == 0 then the simulation stops) <- this part I know how to do.
Is this possible? If so, how?
I guess this might be what you want. Let me know how it works for you.
using System;
using System.Linq;
public class Program
{
private static Random random = new Random();
public static void Main()
{
int[] myArray = new int[] {9, 8, 7, 3, 4, 5, 6, 2, 1};
Simulate(myArray);
}
static void Simulate(int[] myArray)
{
int maxValue = myArray.Max();
Console.WriteLine(string.Join(" ",myArray));
var continueSimulation = true;
do{
int maxIndex = myArray.ToList().IndexOf(maxValue);
var randomValue = random.Next(0, maxValue);
myArray[maxIndex] = randomValue;
maxValue = myArray.Max();
if (maxValue == 0)
continueSimulation = false;
Console.WriteLine(string.Join(" ",myArray));
}while(continueSimulation);
}
}
You can check it out on this fiddle.
Hope this helps!
If you want to find the second max, you can mark the position of the first one and continue with your same approach. How can be done? 1- initialize an array of bool with the same length of the array where you want to find the max, then find the first max and mark that position in the second array with true, if you want the second max, make a loop through the array asking for the max and if that element is not marked in the second array of bool. Finally you will get the second max .
Another idea is taking the values in a list and once you find the max, remove the max from the list to continue with the same algorithm but with an array of less values
static int Max(int [] num)
{
int max = num[0];
for(int i = 0; i < num.Length; i ++)
{
if(num[i] > max)
max = num[i];
}
return max;
}
static int SecondMax(int[]a)
{
if(a.Length < 2) throw new Exception("....");
int count = 0;
int max = Max(a);
int[]b = new int[a.Length];
for(int i = 0; i < a.Length; i ++)
{
if(a[i] == max && count == 0)
{
b[i] = int.MinValue;
count ++;
}
else b[i] = a[i];
}
return Max(b);
}
Honestly, the question feels a bit unusual, so if you share why you're trying to do this, maybe someone could suggest a better approach. However, to answer your original question, you can just use .NET's random number generator.
int[] myArray = new int[] { 9, 8, 7, 3, 4, 5, 6, 2, 1 };
Random random = new Random();
for (int max = myArray.Max(); max > 0; max = myArray.Max())
{
int index = myArray.IndexOf(max);
DoSomething(max);
myArray[index] = random.Next(0, max);
}
From the MSDN doco on Random, the upper bound is exclusive, which means that it will generate a random number between 0 and max-1, unless max==0, in which case it will return 0.

Array not displaying properly

This is homework assignment for school, but I'm begging for someone to just correct my code. I've been working at this for two days and I think I have everything worked out except I can't get it to work as a 2D Array, so I set this up temporarily just to try to figure things out, but I'm digging myself deeper into a hole I think.
The assignment requires that two dice be rolled 36,000 times and then the results for each sum be displayed on the right, and the sum of the two dice on the left, like this in a 2D array:
12 850
11 1020
10 1200
...
2 900
I've got the right column displaying correctly, but the left column won't display the sums, it just displays "System.Int32[]" a bunch of times.
Here's the code:
Random rand = new Random();
const int ARRAY_SIZE = 13;
const double DICE_ROLLS = 36000;
int sum = 0;
int die1 = 0;
int die2 = 0;
int[] sums = new int[ARRAY_SIZE];
int[] dice = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
for (int i = 0; i < DICE_ROLLS; i++ )
{
die1 = rand.Next(1, 7);
die2 = rand.Next(1, 7);
sum = die1 + die2;
sums[sum] += 1;
}
for (int i = 2; i < sums.Length; i++)
{
Console.WriteLine("{0,2} {1,8}", dice, sums[i]);
}
In the spirit of the homework assignment, rather than fixing the code outright, I will try to explain the parts you need to fix, and let you do the actual fixing.
The primary issue in your code is that you are trying to print dice as the value for the left column of the output, rather than individual elements of dice (e.g. dice[i]).
Note, however, that you can't just use dice[i], because your dice array has fewer elements in it than the sums array. If you just replaced dice with dice[i] in your WriteLine() statement, you'd get an index-out-of-bounds exception.
IMHO, the best way to address this is to initialize sums with 11 elements instead of 13, and then when tracking the sums (i.e. in your first loop), subtract 2 from the actual sum value to get the index for the sums array:
sums[sum - 2] += 1;
Then in your second loop, you can safely just use i to index both arrays.
I hope that helps. Please feel free to ask for any clarifications and good luck with your assignment.
Since you'll be using a 2d array you'll want to do something like this:
var rand = new Random();
const double diceRolls = 36000;
var sums = new[,] {{2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}, {10, 0}, {11, 0}, {12, 0}};
for (var i = 0; i < diceRolls; i++)
{
var die1 = rand.Next(1, 7);
var die2 = rand.Next(1, 7);
var sum = die1 + die2;
sums[sum - 2, 1] += 1;
}
for (var i = 0; i < sums.GetLength(0); i++)
{
Console.WriteLine("{0,2} {1,8}", sums[i, 0], sums[i, 1]);
}
Note 1: sum - 2. Since the array length is only 11 you need to subtract 2 from the dice value. (0-10 instead of 2-12).
Note 2: sums.GetLength(0). If you use sums.Length you'll get 22 since there actually are 22 elements in the array. You need to get the length for rank 0
Note 3: Since you're dealing with 2d arrays you'll have the sum of the dice roll in sum[i, 0] and the total count in sum[i, 1].

construct an array of integers to achieve specific sequence

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

C# - 1 2 4 8 16 32 64... series - Find the indexes based on input number, recursive function?

I have a series of number as such: [1 2 4 8 16 32 64 128], if I input a number, i.e. 66, then the output should be 64 and 2. If I input 87, then the output should be 64, 16, 4, 2, 1.
(Basically, it first divide by the largest possible number, find the remainder, then keep dividing by the largest number possible, until the remainder is 0. Or another way maybe just to subtract the largest possible number and keep subtracting like that until it reaches 0.)
I'm thinking of a recursive function, but not really sure. Any help?
Thanks.
class Program
{
[Flags]
enum Bits
{
_1 = 1,
_2 = 2,
_4 = 4,
_8 = 8,
_16 = 16,
_32 = 32,
_64 = 64,
_128 = 128
}
static void Main(string[] args)
{
var b = (Bits)87;
Console.WriteLine(b);
Console.ReadKey();
}
}
Here's the iterative version
public static IEnumerable<int> FindIndex(int input)
{
var power = 0;
while (input > 0)
{
var digit = input % 2;
if (digit == 1)
{
yield return (int)Math.Pow(2, power);
}
input /= 2;
power++;
}
}
and here's the recursive version
public static void FindIndexRec(int input, int power, ICollection<int> numbers)
{
if (input == 0)
{
return;
}
var digit = input % 2;
if (digit == 1)
{
numbers.Add((int)Math.Pow(2, power));
}
FindIndexRec(input / 2, ++power, numbers);
}
and you can call it like
var numbers = new List<int>();
FindIndexRec(input, 0, numbers);
You could use bit masks. In fact, scratch that - you should use bit masks! That is almost certainly how the error code was created, and it's how it should be picked apart. Anything else is highly likely to confuse your audience of other programmers.
I make no claims to represent all programmers, nor do I claim to be any good, but I am a programmer, and all the other answers confused me. It's obviously a bitwise "problem", so why obfuscate?
There's no need to even store the result anywhere, since it's as quick to recompute it every time, like so:
for(int i=0;i<8;++i) {
if((error&(1<<i))!=0 {
// 1<<i is in the resulting list.
}
}
List<int> additives = new List<int>()
List<int> sourceNumbers = new List<int> { 1, 2, 4, 8, 16, 32, 64, 128 };
int sourceNumber = 87;
foreach(var number in sourceNumbers.Reverse())
{
if(sourceNumber % number > 0)
{
additives.Add(number);
sourceNumber -= number;
}
else
{
additives.Add(number);
break;
}
}
Here's a pretty naive iterated solution in pseudocode. Try to take it somewhere more interesting from here. You can do it recursively, you can convert the integer to binary representation and iterate on that string, id imagine theres a clever way to do it with LINQ very concisely, etc.
v = inputNumber
while(v > 0):
temp = greatest power of 2 less than v
print temp
v -= temp
PS - this does not explictly store the series in question - it presumes powers of 2.
string calculate(int input)
{
string output = string.Empty;
int[] series = new int[] { 1, 2, 4, 8, 16, 32, 64, 128 };
foreach (int i in series.Reverse<int>())
{
if (input >= i)
{
output += i.ToString() + " ";
input -= i;
}
}
return output;
}
This one will work with input numbers greater than 256:
int[] calculate(int input)
{
List<int> retVal = new List<int>();
string output = string.Empty;
int[] series = new int[] { 1, 2, 4, 8, 16, 32, 64, 128 };
foreach (int i in series.Reverse<int>())
{
while (input >= i)
{
retVal.Add(i);
input -= i;
}
}
return retVal.ToArray();
}
Ex:
var result = calculate(284);
// result = 128, 128, 16, 8, 4
IEnumerable<int> GetFlags(int input,IEnumerable<int> series)
{
foreach (int value in series)
if ((input & value)==value)
yield return value;
}
Or LINQ solution to the problem.
IEnumerable<int> GetFlags(int input, IEnumerable<int> series)
{
return series.Where(x => (x & input) == x);
}
Programming aside, you can also look at it mathematically. It's basically 2 to the power of (integer value of) log(2, input)
Putting this in a recursive function would be easy ofcourse, it would even look simple and smooth, but I doubt it being less computationally complex and it sure doesn't help with your homework, just thought I would throw it here.

Categories