Google foobar gearing_up_for_destruction

后端 未结 9 513
醉话见心
醉话见心 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:43

    For a one pass approach

    Denote p_0,p_1,...,p_n the positions of the pegs. Let me define a sequence a_k by the following recurrence relation

    a_0 = 0
    a_k = a_{k-1}+(-1)^{k+1}(p_k-p_{k-1})
    

    If you compute a_n and simplify you see that this is the same alternating sum of p_k that you see in other answers in which most terms have a coefficient 2 except the first and the last one.

    We will see below why it could be convenient to look at this sequence of numbers instead.

    If we denote the radii of the gears by r_0,r_1,...,r_n, then they satisfy the equations

    r_k = (-1)^k(r_0-a_k)
    

    Also, the condition that the radii are not smaller than 1 is equivalent to the inequalities

    r_0 >= a_0 + 1
    r_1 <= a_1 - 1
    r_2 >= a_2 + 1
    r_3 <= a_3 - 1
    ...
    

    This means that the full sequence of inequality conditions for the radii can be reduced to the single pair of inequalities

    max(a_k+1, for k even) <= r_0 <= min(a_k - 1, for k odd)
    

    Finally, the condition of doubling the speed is

    (1+2(-1)^{n+1}) r_0 = 2a_n(-1)^{n+1}
    

    So, computing the sequence a_n allows us to get both the answer and at the same time the restrictions on the radii in one pass.

    Written in Python the code could look as follows. Feel free to improve it further.

    define solution(pegs):
        n = len(pegs)
        if n<2:
            return (-1,-1)
        an = 0 # This contains, at each step the value of the sequence a_k
        pm_one = -1 # The alternating sign in the formulas above.
        # This and the next will get the bounds for the radii.
        max_even_a = -float("inf") 
        min_odd_a = float("inf")
        for i in range(n-1):
            an -= pm_one*(pegs[i+1]-pegs[i])
            pm_one *=-1
            if not i&1:
                min_odd_a = min(min_odd_a, an)
            else:
                max_even_a = max(max_even_a, an)
        # In the formulas above the numerator has a (-1)^{n+1} factor. 
        # Here the sign has been cancelled with the sign of the denominator.
        numerator = 2*an 
        denominator = abs(1+2*pm_one)
        # The inequalities in the explanation are here written as integers.
        # Note that here denominator is positive. So, passing it to the other side
        # doesn't change the sign of the inequality.
        # Of course, the inequalities have here the negated sign and an OR
        # because we are detecting when they fail.
        if numerator < denominator*(max_even_a+1) \
            or numerator > denominator*(min_odd_a-1):
            return (-1,-1)
        # Sometimes the denominator is 3. If it can be cancelled we do so.
        if pm_one == 1 and numerator%3 == 0:
            numerator //=3
            denominator = 1
        return (numerator, denominator)
    
    0 讨论(0)
  • 2020-12-29 11:43
    from fractions import Fraction
    
    def answer(a):
      l = len(a)
      if(not a or l == 1): return [-1,-1]
      s = (a[l-1] - a[0]) if (l % 2 == 0) else (-a[l-1]-a[0]); 
      if(l > 2): 
          for i in range(1, l-1): s+= 2 * (-1)**(i+1) * a[i]
      v = Fraction(2*(float(s)/3 if (l%2==0) else float(s))).limit_denominator();
      c = v;
      for i in range(0, l-2):
        d = a[i+1] - a[i]
        n = d - c
        if(c < 1 or n < 1): return [-1,-1]
        else: c = n
      return [v.numerator, v.denominator];
    
    0 讨论(0)
  • 2020-12-29 11:43

    My python code uses fairly basic operations to get things done without brute-forcing it. However I'm lazy and didn't really comment, so you're gonna have to figure it out yourself. It passed the foobar solution thing, so it definitely works.

    def answer(pegs):
    distances = [pegs[x+1]-pegs[x] for x in range(len(pegs)-1)]
    x = 0 
    for i in distances: #gets d_(n)-d_(n-1)+d_(n-2)...+-d_(1)
        x = i - x
    #this tests if firstGearRadius is positive or negative
    if len(distances)%2 == 0: #if it's positive
        solution =  [x*-2,1] 
    elif len(distances)%2 == 1: #if it's negative
        if x*2 % 3 == 0: #if the numerator is divisible by 3
            solution = [x*2/3,1]
        else:
            solution = [x*2,3]
    #finds sizes of the gears
    gearSizes = [float(solution[0])/float(solution[1])]
    x = gearSizes[0]
    for i in distances:
        x = i - x
        gearSizes.append(x)
    if any([True for x in gearSizes if x<=1]): #gears must be at least 1 unit radius
        return [-1,-1]
    else:
        return solution
    
    0 讨论(0)
  • 2020-12-29 11:48

    Here's the working code in python 2.7 for which all the test cases were passed by Google. This is the best solution that I came up with after scratching papers for a while:

    from fractions import Fraction  
    def answer(pegs):
        arrLength = len(pegs)
        if ((not pegs) or arrLength == 1):
            return [-1,-1]
    
        even = True if (arrLength % 2 == 0) else False
        sum = (- pegs[0] + pegs[arrLength - 1]) if even else (- pegs[0] - pegs[arrLength -1])
    
        if (arrLength > 2):
            for index in xrange(1, arrLength-1):
                sum += 2 * (-1)**(index+1) * pegs[index]
    
        FirstGearRadius = Fraction(2 * (float(sum)/3 if even else sum)).limit_denominator()
    
        # now that we have the radius of the first gear, we should again check the input array of pegs to verify that
        # the pegs radius' is atleast 1.
        # since for valid results, LastGearRadius >= 1 and FirstGearRadius = 2 * LastGearRadius
        # thus for valid results FirstGearRadius >= 2
    
        if FirstGearRadius < 2:
            return [-1,-1]
    
        currentRadius = FirstGearRadius
        for index in xrange(0, arrLength-2):
            CenterDistance = pegs[index+1] - pegs[index]
            NextRadius = CenterDistance - currentRadius
            if (currentRadius < 1 or NextRadius < 1):
                return [-1,-1]
            else:
                currentRadius = NextRadius
    
        return [FirstGearRadius.numerator, FirstGearRadius.denominator]
    

    See this image for how I came up with this code:

    0 讨论(0)
  • 2020-12-29 11:49

    I think your solution is along the right lines, but doesn't allow for a fractional radius.

    Note that we can consider your algorithm symbolically, setting g[0]=x, and then computing all the g[j] values in terms of x. It turns out that each g[j] is a linear function of x (with gradient 1 or -1).

    You will therefore find that g[-1] = a+mx where m is +1 or -1, and a is an integer.

    For a solution to exist you need to solve the equation:

    g[0]/g[-1] = 2
    x/(a+mx) = 2
    x=2(a+mx)
    x(1-2m)=2a
    x=2a/(1-2m)
    

    so this gives a candidate value of x (as a fraction) which you can then recheck to make sure that no intermediate radius went negative.

    0 讨论(0)
  • 2020-12-29 11:49

    After evaluating most of the solutions in this Q&A, I have put calculated the results.

    Gist for coding logic for evaluating correct implementations(mostly correct, but has issues) and performance

    Solutions evaluated with links, and time of implementations(since people are finding faster and faster solutions over time). All solutions were verified excepted for ThisWind's solution

    • NotDijkstra(aka. franklinvp) - June 19, 2020 Easily the most performant
    • Val Do - Feb 16, 2018
    • ThisWind - Has issues with this, and couldn't get it to verify(5 pass and 5 failed). This could be a potential error on my part.
    • Lamichhane - Aug 11, 2017
    • cbarraford - Mar 10, 2017
    • 1lann - Nov 11, 2016
    • Dayz - Sep 27, 2018

    Performance results

    Number of test iterations: 10000
    solutionValDo :  7.3772001
    solutionThisWind :  1.1203797
    solutionNotDijkstra :  0.3143226
    salutionLamichhane :  6.6052445
    solutioncbarraford :  26.4765467
    solution1lann :  147.5525556
    solutionDayz :  6.619154 
    
    0 讨论(0)
提交回复
热议问题