Google foobar gearing_up_for_destruction

后端 未结 9 514
醉话见心
醉话见心 2020-12-29 11:12

I was doing the google foobar challenge but ran out of time on the following challenge i am trying to see what i did wrong.

Challenge

As

相关标签:
9条回答
  • 2020-12-29 11:53

    a passed solution:

    from fractions import Fraction
    
    def solution(p):
        n = len(p)
    
        if n >= 2:
            r0_n = -2 * (p[n - 1] + reduce(
                lambda a, b: a + b, [0] + [(-1)**i * 2 * p[i]
                                           for i in range(n - 2, 0, -1)]) + (-1)**(n-1)*p[0])
    
            r0_d = 1 + ((n+1) % 2)*2
    
            if r0_n < r0_d:
                return [-1, -1]
    
            r = ['NAN'] * n
            r[0] = float(r0_n) / float(r0_d)
            for i in range(1, n):
                r[i] = p[i] - p[i - 1] - r[i - 1]
                if r[i] < 1:
                    return [-1, -1]
    
            r0 = Fraction(r0_n, r0_d)
            r0.limit_denominator()
            
            return [r0.numerator, r0.denominator]
    
        return [-1, -1]
    

    some tests:

    if __name__ == '__main__':
        print solution([4, 30, 50]), [12, 1]
        print solution([4, 17, 50]), [-1, -1]
        print solution([1, 51]), [100, 3]
        print solution([1, 31]), [20, 1]
        print solution([1, 31, 51, 71]), [20, 1]
        print solution([1, 31, 51, 71, 91]), [20, 1]
        print solution([4, 9, 17, 31, 40]), [4, 1] 
    

    output:

    [12, 1] [12, 1]
    [-1, -1] [-1, -1]
    [100, 3] [100, 3]
    [20, 1] [20, 1]
    [20, 1] [20, 1]
    [20, 1] [20, 1]
    [4, 1] [4, 1]
    

    some thinking

    #    equaltion         | i
    # ---------------------|---
    # / r0 + r1 == p1 - p0  [0]
    # | r1 + r2 == p2 - p1  [1]
    # | r2 + r3 == p3 - p2  [2]
    # | r3 + r4 == p4 - p3  [3]
    # | r4 + r5 == p5 - p4  [4]
    # \      r5 == r0/2     [5]
    #
    #
    # / r0 + r1 + 0  + 0  + 0  + 0    = p1 - p0
    # | 0  + r1 + r2 + 0  + 0  + 0    = p2 - p1
    # | 0  + 0  + r2 + r3 + 0  + 0    = p3 - p2
    # | 0  + 0  + 0  + r3 + r4 + 0    = p4 - p3
    # | 0  + 0  + 0  + 0  + r4 + r5   = p4 - p4
    # \ r0 + 0  + 0  + 0  + 0  - 2*r5 = 0
    #
    # / 1 1 0 0 0  0 \   / r0 \   / p1 - p0 \
    # | 0 1 1 0 0  0 |   | r1 |   | p2 - p1 |
    # | 0 0 1 1 0  0 |   | r2 |   | p3 - p2 |
    # | 0 0 0 1 1  0 | * | r3 | = | p4 - p3 |
    # | 0 0 0 0 1  1 |   | r4 |   | p5 - p4 |
    # \ 1 0 0 0 0 -2 /   \ r5 /   \    0    /
    
    0 讨论(0)
  • 2020-12-29 11:55

    If you're interested in a perfect working solution, this is what I wrote: https://gist.github.com/1lann/be45311db1bd8cbbe6650b0a3e9d1977

    It constructs a system of equations where it solves the values for every radius of every gear. Here's how it computes the solution for 4 pegs for example.

    The system of equations would be:

    2x + a = peg[1] - peg[0]
    a + b = peg[2] - peg[1]
    b + x = peg[3] - peg[2]
    

    My program constructs a matrix to represent this:

    [
        [2, 1, 0],
        [0, 1, 1],
        [1, 0, 1]
    ]
    

    It then computes the inverse of the matrix, and then applies it to the distances between the pegs in order to find the radius of every gear. If you're wondering how the maths work, you can look at: https://www.mathsisfun.com/algebra/systems-linear-equations-matrices.html

    Each gear is then verified to have a radius >= 1, and finally the value of x*2 is returned. In order to support fractions (any rational number), all numbers are of a Fraction type.

    I did hard code some edge cases, such as when the number of pegs = 2.

    0 讨论(0)
  • 2020-12-29 12:02

    I got their invitation last night and I worked on this problem for several hours. I created my solution of this problem.

    from fractions import Fraction
    from sympy import symbols, solve
    
    
    def create_equations(_pegs, _isEven, smbls, r0):
        eq = None
        temp = symbols('temp')
        if _isEven:
            for i in range(len(smbls)):
                if i == 0:
                    eq = -r0 - r0 / 2 - smbls[i] + temp
                if 0 < i < len(smbls):
                    eq = eq.subs(temp, (-1) ** (i + 1) * 2 * smbls[i] + temp)
                if i == len(smbls) - 1:
                    eq = eq.subs(temp, - smbls[i])
        else:
            for i in range(len(smbls)):
                if i == 0:
                    eq = -r0 + r0 / 2 - smbls[i] + temp
                if 0 < i < len(smbls):
                    eq = eq.subs(temp, (-1) ** (i + 1) * 2 * smbls[i] + temp)
                if i == len(smbls) - 1:
                    eq = eq.subs(temp, smbls[i])
        return eq
    
    
    def create_symbols(len_pegs):
        smbls = []
        for i in range(len_pegs):
            smbls.append(symbols("P" + str(i)))
        r0 = symbols("r0")
        return smbls, r0
    
    
    def answer(pegs):
    
        # first check
        len_pegs = len(pegs)
        if (not pegs) or len_pegs == 1:
            return [-1, -1]
    
        isEven = True if (len_pegs % 2 == 0) else False
    
        # create list of symbols used in equation based on list length
        smbls, r0 = create_symbols(len_pegs)
    
        # the function returns an equation based on the following equation
        # for even list length : (0 = r0 + rn -Pn + 2Pn-1 - 2Pn-2 + 2Pn-3 ... - P1 + P0)
        # for odd list length : (0 = r0 - rn -Pn + 2Pn-1 - 2Pn-2 + 2Pn-3 ... + P1 - P0)
        #  where rn = r0/2
        equation = create_equations(pegs, isEven, smbls, r0)
    
        # substituting values of variables in the equation
        for i in range(len_pegs):
            equation = equation.subs(smbls[i], pegs[i])
    
        # solving the equation and simplifying float values to simple fraction
        radius_g1 = float(solve(equation)[0])
        radius_g1 = Fraction(radius_g1).limit_denominator()
    
        # finally we check if radius of any gear is less than one as required
        radius_cur = radius_g1
        for i in range(0, len_pegs-1):
            dist_c = pegs[i + 1] - pegs[i]
            radius_next = dist_c - radius_cur
            if radius_cur < 1 or radius_next < 1:
                return [-1, -1]
            else:
                radius_cur = radius_next
    
        # return the end results [numerator, denominator]
        return [radius_g1.numerator, radius_g1.denominator]
    
    
    if __name__ == "__main__":
        # try some examples
        print(answer([4, 30, 50, 56]))
        print(answer([4, 17, 50]))
    
    0 讨论(0)
提交回复
热议问题