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 2 years ago.
Improve this question
The code is running fine and is executing in python compiler online but failing all test cases in the Google Foobar
from math import factorial
from collections import Counter
from fractions import gcd
def cycle_count(c, n):
cc=factorial(n)
for a, b in Counter(c).items():
cc//=(a**b)*factorial(b)
return cc
def cycle_partitions(n, i=1):
yield [n]
for i in range(i, n//2+1):
for p in cycle_partitions(n-i, i):
yield [i]+p
def solution(w, h, s):
grid=0
for cpw in cycle_partitions(w):
for cph in cycle_partitions(h):
m=cycle_count(cpw, w)*cycle_count(cph, h)
grid+=m*(s**sum([sum([gcd(i, j) for i in cpw]) for j in cph]))
return grid//(factorial(w)*factorial(h))
Check out this code which is to be executed .Would love suggestions !!!
This is a gorgeous problem, both mathematically and from the algorithmic point of view.
Let me try to explain each part.
The mathematics
This part is better read with nicely typeset formulas. See a concise explanation here where links to further reading are given.
Let me add a reference directly here: For example Harary and Palmer's Graphical enumeration, Chapter 2.
In short, there is a set (the whole set of h x w-matrices, where the entries can take any of s different values) and a group of permutations that transforms some matrices in others. In the problem the group consists of all permutations of rows and/or columns of the matrices.
The set of matrices gets divided into classes of matrices that can be transformed into one another. The goal of the problem is to count the number of these classes. In technical terminology the set of classes is called the quotient of the set by the action of the group, or orbit space.
The good thing is that there is a powerful theorem (with many generalizations and versions) that does exactly that. That is Polya's enumeration theorem. The theorem expresses the number of elements of the orbit space in terms of the value of a polynomial known in the area as Cycle Index. Now, in this problem the group is a direct product of two special groups the group of all permutations of h and w elements, respectively. The Cycle Index polynomials for these groups are known, and so are formulas for computing the Cycle Index polynomial of the product of groups in terms of the Cycle Index polynomials of the factors.
Maybe a comment worth making that motivates the name of the polynomial is the following:
Every permutation of elements can be seen as cycling disjoint subsets of those elements. For example, a permutation of (1,2,3,4,5) and can be (2,3,1,5,4), where we mean that 2 moved to the position of 1, 3 moved to the position of 2, 1 to the position of 3, 5 to the position of 4 and 4 to the position of 5. The effect of this permutation is the same as cycling 1-> 3 -> 2 and 2 back to 1, and cycling 4 -> 5 and 5 back to 4. Similar to how natural numbers can be factored into a product of prime factors, each permutation can be factored into disjoint cycles. For each permutation, the cycles are unique in a sense for each permutation. The Cycle Index polynomial is computed in terms of the number of cycles of each length for each permutation in the group.
Putting all these together we get that the total count is given by the last formula in the link.
Implementation
As seen in the final formula, we need to compute:
Partitions of a number
Greatest common divisors (gcd) of many numbers.
Factorials of many numbers.
For these, we can do:
To compute all partitions one can use the iterative algorithms here. Already written in Python here.
An efficient way to compute gcd one could use Euclidean algorithm. However, since we are going to need the gcd of all pairs of numbers in a range and each one many times. It is better to pre-compute the full table of gcd all at once by dynamic programming. If a>b, then gcd(a,b)=gcd(a-b,b). This recurrence equation allows to compute gcd of larger pairs in terms of that of smaller pairs. In the table, one has the initial values gcd(1,a)=gcd(a,1)=1 and gcd(a,a)=a, for all a.
The same happens for factorials. The formula will require the factorials of all numbers in a range many times each. So, it is better to compute them all from the bottom up using that n! = n(n-1)! and 0!=1!=1.
An implementation in Python could look like this. Feel free to improve it.
I know this is a copied code but you have to :
1) write your own factorial function
2) write your own gcd function
3) cast to string before returning final value.
Related
I was curious about the time complexity of Python's itertools.combinations function. I did some searching and it seems that many resources claim the time complexity is O(n!) or O(nCr).
However, for the two extremes of when r = 1 and r = n, the formula nCr reduces to n and 1, respectively. Does this mean we can conclude that the time complexity of itertools.combinations is O(n)?
r=1 and r=n rather are (almost) best cases (actually r=0 is the lower extreme), not worst cases. Worst case, at least for number of combinations, is r=n/2. So if you do want to express the complexity in terms of just n, it's O(nC(n/2)) or O(n × nC(n/2)), depending on what you do with the tuples.
Does this mean we can conclude that the time complexity of itertools.combinations is O(n)?
No you / we can't do that.
Consider this statement:
Algorithm X to compute the combinations of r values from a set of n is O(nCr).
It is in fact trivial to prove1 that any algorithm to do the above must be at least O(nCr). But we would need to examine the actual code to determine that a given algorithm is exactly O(nCr)
What you are doing is setting one or both of the variables to fixed values. This is effectively changing the problem.
To illustrate this, we can just substitute the fixed values into the above statement; e.g.
Algorithm X to compute the combinations of 1 value from a set of n is O(nC1).
Since nC1 is n, we can rewrite this as:
Algorithm X to compute the combinations of 1 value from a set of n is O(n).
But notice that this problem is different to the original one.
In short ... this is NOT invalidating the original statement.
Note that the (alleged) claim that itertools.combinations is O(n!) is (I think) a misreading on your part. What that "source" actually says is:
"Getting all combinations of a list is O(n!). Since you're doing that n times to get combinations with different values of r, the whole algorithm is O(n * n!)."
My reading is that it is talking about Pn not nCr. But either way, it is too vague to be considered a credible source.
1 - Informal proof. The set of combinations of r from a set of n has nCr elements. Constructing this set will entail adding nCr elements to a data structure. That involves (at least) nCr memory writes. It will take (at least) O(nCr) time to do this ... assuming a (real world) computer with an upper limit on memory bandwidth.
If I have two positive integers N and M, I need to construct N equally-sized sets that can contain numbers from 1 to M. These sets do not need to be disjoint. The catch is that all of the products of any two numbers from different sets must be unique.
For example, the sets: {1,2,3,4,5} and {6,7,8,13,17} would not be allowed because 3∗8=24 and 4∗6=24. Essentially, the products of the cartesian products of the sets must be unique.
The goal is to derive some sort of algorithm or technique that could maximize the size of each set. Intuitively, I first thought about taking all of the primes from 1 to M and dividing them into N equal sets, however I was told that there were better solutions.
I would appreciate any and all guidance towards properties or techniques that can help me produce an optimal solution.
Disclaimer: This was a problem for a math/programming competition. The event is now over and I am curious to see what solutions are out there.
Using python, I would like to generate all possible permutations of 10 labels (for simplicity, I'll call them a, b, c, ...), and return all permutations that satisfy a list of conditions. These conditions have to do with the ordering of the different labels - for example, let's say I want to return all permutations in which a comes before b and when d comes after e. Notably, none of the conditions pertain to any details of the labels themselves, only their relative orderings. I would like to know what the most suitable data structure and general approach is for dealing with these sorts of problems. For example, I can generate all possible permutations of elements within a list, but I can't see a simple way to verify whether a given permutation satisfies the conditions I want.
"The most suitable data structure and general approach" varies, depending on the actual problem. I can outline three basic approaches to the problem you give (generate all permutations of 10 labels a, b, c, etc. in which a comes before b and d comes after e).
First, generate all permutations of the labels, using itertools.permutations, remove/skip over the ones where a comes after b and d comes before e. Given a particular permutation p (represented as a Python tuple) you can check for
p.index("a") < p.index("b") and p.index("d") > p.index("e")
This has the disadvantage that you reject three-fourths of the permutations that are initially generated, and that expression involves four passes through the tuple. But this is simple and short and most of the work is done in the fast code inside Python.
Second, general all permutation of the locations 0 through 9. Consider these to represent the inverses of your desired permutations. In other words, the number at position 0 is not what will go to position 0 in the permutation but rather shows where label a will go in the permutation. Then you can quickly and easily check for your requirements:
p[0] < p[1] and p[3] > p[4]
since a is the 0'th label, etc. If the permutation passes this test, then find the inverse permutation of this and apply it to your labels. Finding the inverse involves one or two passes through the tuple, so it makes fewer passes than the first method. However, this is more complicated and does more work outside the innards of Python, so it is very doubtful that this will be faster than the first method.
Third, generate only the permutations you need. This can be done with these steps.
3a. Note that there are four special positions in the permutations (those for a, b, d, and e). So use itertools.combinations to choose 4 positions out of the 10 total positions. Note I said positions, not labels, so choose 4 integers between 0 and 9.
3b. Use itertools.combinations again to choose 2 of those positions out of the 4 already chosen in step 3a. Place a in the first (smaller) of those 2 positions and b in the other. Place e in the first of the other 2 positions chosen in step 3a and place d in the other.
3c. Use itertools.permutations to choose the order of the other 6 labels.
3d. Interleave all that into one permutation. There are several ways to do that. You could make one pass through, placing everything as needed, or you could use slices to concatenate the various segments of the final permutation.
That third method generates only what you need, but the time involved in constructing each permutation is sizable. I do not know which of the methods would be fastest--you could test with smaller sizes of permutations. There are multiple possible variations for each of the methods, of course.
During my efforts to solve leetcode 70, climbing stairs, I thought of an answer that uses factorials (how many different ways to form a line with identical elements). Later, I thought that the question could also be solved using fibonacci, and the first few answers appear to be the same.
My questions are:
Is there a formal mathematical proof (or an intuitive explanation) as to why these two might be the same? or if they are the same?
the climbing stairs problem is a problem that asks you to find the number of ways a person only taking one or two steps can climb up a stair with n stairs.
Since this is just a way of saying how many different ways can you line up 1 and 2 that sum up to n. I solved the questions that way.
max_one, and max_two are maximum numbers of 1s or 2s that can exist and I iterated over how many 2s could be in the line, finding how every different line can be formed given number of 2s (represented as i)
the numerator is how many elements in line, the denominator is how many identical elements ( how many 1s, how many 2s) are in the line:
from math import factorial as fac
class Solution:
def climbStairs(self, n):
if n == 1: return 1
if n == 2: return 2
max_two = n//2
max_one = n
ways = 0
for i in range(0,max_two+1):
ways += fac(max_one-i)/(fac(max_one-2*i) * fac(i))
return int(ways)
Congratulations! You’ve rediscovered a very cool identity involving the Fibonacci numbers. Specifically, the rule you’ve found is what’s visually demonstrated in this picture, where adding up terms of Pascal’s triangle along these skew diagonals gives back the Fibonacci sequence:
To see why this is, notice that each term in your summation is equal to (n - i) choose i, which is the entry in row (n - i), column i of Pascal’s triangle. Each term in the summation corresponds to moving up one row and over one column, hence the angle on those lines.
As for a proof, the argument that you’ve outlined is essentially the basis of a double-counting argument. We know that the Fibonacci numbers count the number of ways to walk down a flight of stairs taking steps of sizes one and two, which we can rigorously prove by induction. Additionally, we know that your summation counts the same quantity, as you’re enumerating all the ways to take paths down using 0, 1, 2, 3, ..., etc. steps of size two. Since we’re counting the same quantity in two ways, these two expressions must be equal.
If that doesn’t suffice, you can formalize this using a proof by induction, using the identity (n choose k) = (n-1 choose k) + (n-1 choose k-1) and splitting into cases where n is even and where n is odd.
Hope this helps!
I was given the following assignment by my Algorithms professor:
Write a Python program that implements Euclid’s extended algorithm. Then perform the following experiment: run it on a random selection of inputs of a given size, for sizes bounded by some parameter N; compute the average number of steps of the algorithm for each input size n ≤ N, and use gnuplot to plot the result. What does f(n) which is the “average number of steps” of Euclid’s extended algorithm on input size n look like? Note that size is not the same as value; inputs of size n are inputs with a binary representation of n bits.
The programming of the algorithm was the easy part but I just want to make sure that I understand where to go from here. I can fix N to be some arbitrary value. I generate a set of random values of a and b to feed into the algorithm whose length in binary (n) are bounded above by N. While the algorithm is running, I have a counter that is keeping track of the number of steps (ignoring trivial linear operations) taken for that particular a and b.
At the end of this, I sum the lengths of each individual inputs a and b binary representation and that represents a single x value on the graph. My single y value would be the counter variable for that particular a and b. Is this a correct way to think about it?
As a follow up question, I also know that the best case for this algorithm is θ(1) and worst case is O(log(n)) so my "average" graph should lie between those two. How would I manually calculate average running time to verify that my end graph is correct?
Thanks.