-
-
Save 1lann/be45311db1bd8cbbe6650b0a3e9d1977 to your computer and use it in GitHub Desktop.
from fractions import Fraction | |
def invert(matrix): | |
n = len(matrix) | |
inverse = [[Fraction(0) for col in range(n)] for row in range(n)] | |
for i in range(n): | |
inverse[i][i] = Fraction(1) | |
for i in range(n): | |
for j in range(n): | |
if i != j: | |
if matrix[i][i] == 0: | |
return false | |
ratio = matrix[j][i] / matrix[i][i] | |
for k in range(n): | |
inverse[j][k] = inverse[j][k] - ratio * inverse[i][k] | |
matrix[j][k] = matrix[j][k] - ratio * matrix[i][k] | |
for i in range(n): | |
a = matrix[i][i] | |
if a == 0: | |
return false | |
for j in range(n): | |
inverse[i][j] = inverse[i][j] / a | |
return inverse | |
def answer(pegs): | |
if len(pegs) < 2: | |
return [-1, -1] | |
if len(pegs) == 2: | |
x = (Fraction(pegs[1] - pegs[0]) / Fraction(3)) * Fraction(2) | |
if (x.numerator < 1) or (x.numerator < x.denominator): | |
return [-1, -1] | |
return [x.numerator, x.denominator] | |
matrix = [] | |
rowNum = 0 | |
deltas = [] | |
for loc in pegs: | |
deltas.append(Fraction(pegs[rowNum + 1] - pegs[rowNum])) | |
if rowNum == 0: | |
row = [Fraction(2), Fraction(1)] + [Fraction(0)] * (len(pegs) - 3) | |
matrix.append(row) | |
elif rowNum == len(pegs) - 2: | |
row = [Fraction(1)] + [Fraction(0)] * (len(pegs) - 3) + [Fraction(1)] | |
matrix.append(row) | |
break | |
else: | |
row = [Fraction(0)] * rowNum + [Fraction(1), Fraction(1)] + [Fraction(0)] * (len(pegs) - rowNum - 3) | |
matrix.append(row) | |
rowNum = rowNum + 1 | |
inverse = invert(matrix) | |
if not(inverse): | |
return [-1, -1] | |
# Validate all gears | |
for i in range(1, len(pegs)-1): | |
y = Fraction(0) | |
for j in range(len(pegs)-1): | |
y = y + inverse[i][j] * deltas[j] | |
if (y.numerator < 1) or (y.numerator < y.denominator): | |
return [-1, -1] | |
x = Fraction(0) | |
for i in range(len(pegs)-1): | |
x = x + inverse[0][i] * deltas[i] | |
x = x * Fraction(2) | |
if (x.numerator < 1) or (x.numerator < x.denominator): | |
return [-1, -1] | |
return [x.numerator, x.denominator] | |
print(answer([1, 2])) |
@cbarraford I see you only check if the solution has a denominator of 3 or 1, is there any reason for that?
@SammyIsra The denominators can only be 3 or 1 because if you work out the math...
Given:
n is the number of pegs, with pegs numbered from 1 to n
Let:
d(n) - the distance between peg[n] and peg[n+1]
x - the size of the first gear
y - the size of the last gear
Then:
if n is odd, y = d(n-1) - d(n-2) + d(n-3) - ... - d(1) + x
if n is even, y = d(n-1) - d(n-2) + d(n-3) - ... + d(1) - x
Since x = 2y, you can solve for y:
if n is odd, y = d(1) - d(2) + d(3) - ... - d(n-1)
if n is even, 3y = d(1) - d(2) + d(3) - ... + d(n-1)
I'll post my solution and the full rundown of the math in another gist.
IMO, @cbarraford's solution is better than the matrix one but it's also a brute force trial-and-error solution. My solution iterates through the pegs array exactly twice, once to calculate for y, then another time to check that the calculated value of x results in all gears in the chain being valid. I have to confess that I could have been stuck with 2 failing tests for a while if I hadn't gotten some insight from @cbarraford's solution regarding validity of the gear sizes.
Update: I created https://gist.github.com/jlacar/e66cd25bac47fab887bffbc5e924c2f5 to give a more detailed rundown of the math I used and also shared part of my Java solution.
I want to thank everyone on this thread for the insight into this problem. Unfortunately, I ran out of time trying to figure how to handle solutions with fractional radii and was only able to get 6/10 test cases to pass. Seeing the math that shows the denominator of the solution in its simplest form can only be 1 or 3 was enlightening, and I believe I was able to finalize my solution with that info. I'm not positive that it's bulletproof because I couldn't verify, but it takes a similar approach to @cbarraford and I wanted to post it for anyone else who comes across this thread:
https://gist.github.com/rosemichaele/30e138c4fa2125074d50a186fc5652d2
I came up with a very efficient solution for this problem. I also have an image there to explain if you are interested to see. Please upvote my answer if you like it. Thanks
https://stackoverflow.com/a/45626410/8447619
I am struggling to understand the final part of the question.
it says:
returns a list of two positive integers a and b representing the numerator and denominator of the first gear's radius in its simplest form
what does it mean?
suppose I have the full list of gears radius like :
p = [4, 30, 50] and r = [12, 16, 6]
how do I get a
and b
?
I am struggling to understand the final part of the question.
it says:
returns a list of two positive integers a and b representing the numerator and denominator of the first gear's radius in its simplest form
what does it mean?
suppose I have the full list of gears radius like :
p = [4, 30, 50] and r = [12, 16, 6]
how do I geta
andb
?
here r = [12,14,6] .
While this does work, i found the code hard to read/follow as theres no comments. Heres my answer that works and is a lot simpler.