Skip to content

Instantly share code, notes, and snippets.

@jlacar
Last active April 9, 2023 19:53
Show Gist options
  • Save jlacar/e66cd25bac47fab887bffbc5e924c2f5 to your computer and use it in GitHub Desktop.
Save jlacar/e66cd25bac47fab887bffbc5e924c2f5 to your computer and use it in GitHub Desktop.
Math for solution to Google foo.bar challenge - Gearing Up for Destruction

This is about the Google foo.bar Gearing Up for Destruction challenge - 2nd of 2 challenges on Level 2. It was pretty interesting and I got through most of it without looking for answers. I did get stuck on 2 failing tests so I finally caved. I didn't copy my solution though, just got an insight from the solution that @CBarraford posted here: https://gist.github.com/1lann/be45311db1bd8cbbe6650b0a3e9d1977, which was a more brute-force trial-and-error solution.

Here's the math I worked out for this problem:

Given: 
   n 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

Constraint: 
   x = 2y
   
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

A long mind-numbing proof (work it out yourself if you want) can show that given n number of pegs, you can rearrange the terms to start from d(1) to d(n-1) and get the following:

y = (d(1) - d(2) + d(3) - ... + (sign * d(n-1)))/divisor

where sign (of last term) is
  +1 if n is even.
  -1 if n is odd.
  
and divisor is
  1 if n odd.
  3 if n is even.

This is easier to see with an example:

If n = 4 (even),
   y = d(3) - d(2) + d(1) - x   

rearranging terms,
   y = d(1) - d(2) + d(3) - x
  
substituting x = 2y,
   y = d(1) - d(2) + d(3) - 2y
  3y = d(1) - d(2) + d(3)
  
and you get 
   y = (d(1) - d(2) + d(3))/3   ## [general form: sign = +1, divisor = 3]

If n = 5 (odd),
   y = d(4) - d(3) + d(2) - d(1) + x
   
substituting x = 2y,
   y = d(4) - d(3) + d(2) - d(1) + 2y
   y - 2y = d(4) - d(3) + d(2) - d(1)
   -y = d(4) - d(3) + d(2) - d(1)
   y = -1 * (d(4) - d(3) + d(2) - d(1))
   y = -d(4) + d(3) - d(2) + d(1)
   
rearranging terms,
   y = d(1) - d(2) + d(3) - d(4)   
   
and you get
   y = (d(1) - d(2) + d(3) - d(4))/1  ## [general form: sign = -1, divisor = 1]
   

Basically, you sum up the distances from d(1) to d(n-1), alternating the sign of each additional term from negative to positive.

Maybe this might help visualize it better:

Peg   1             2             3             4             5
d(n)  <---- d1 ----><---- d2 ----><---- d3 ----><---- d4 ---->
y(n)            y(2)=r2       y(3)=r3       y(4)=r4       y(5)=r5         
r(n)  r1=x      = d1-r1       = d2-r2       = d3-r3       = d4-r4
                = d1-x        = d2 -        = d3 -        = d4 -
                                (d1-x)        (d2 -         (d3 -
                                              (d1-x))       (d2 -
                                                            (d1-x)))                                     
So,
  y(2) = r2
       = d1 - r1
       = d1 - x

  y(3) = d2 - y(2)
       = d2 - (d1 - x) 
       = d2 - d1 + x
     
  y(4) = d3 - y(3)
       = d3 - (d2 - (d1 - x)) 
       = d3 - (d2 - d1 + x) 
       = d3 - d2 + d1 - x
     
  y(5) = d4 - y(4)
       = d4 - (d3 - (d2 - (d1 - x)))
       = d4 - (d3 - (d2 - d1 + x))
       = d4 - (d3 - d2 + d1 - x)
       = d4 - d3 + d2 - d1 + x
          
  and so on...

Basically,

For n >= 2,
   y(n) = d(n-1) - y(n-1) for n >= 2
   
Where
   y(1) = -x when n is odd 
        = +x when n is even       

I think that should be right. (Shrug) I haven't done this kind of math in a while so if there's something off, it's in my presentation, not the concept.

Anyway, I submitted my fully verified solution based on this idea. Here's the Java code:

   public static int[] answer(int[] pegs) {

        int firstGearSize = lastGearSize(pegs) * 2;
        int divisor = 1;

        if ((pegs.length % 2 == 0)) {
            if (firstGearSize % 3 == 0) {
                firstGearSize /= 3;
            } else {
                divisor = 3;
            }
        }

        return allGearsFit(pegs, ...) 
                ? new int[] { firstGearSize, divisor } 
                : new int[] { -1, -1 };
    }

    private static int lastGearSize(int[] pegs) {
        ... // elided - no more than 10 lines of code
    }

    private static boolean allGearsFit(int[] pegs, int ...) {
        ... // elided - no more than 10 lines of code
    }

This solution is simpler than the two others I have seen, one involving matrix inversion or something like that and the other one which was a more brute force, trial-and-error solution, iterating through all the possible radii to see if a solution that met all requirements could be verified.

This solutions translates almost directly from the math that I show above.

NOTE: I had this in another gist but decided I would elide parts of my solution since it looks like Google could be using this foo.bar challenge as a way to identify potential hires. Sorry if that pisses you off but I understand how hard it is to hire good people; it takes me 15 to 20 audition before I can usually find the one person I think deserves the job. I may be giving away too much with this gist already as it is. Anyway, the parts I left out are kind of obvious once you understand the math that I explained above.

@ostheperson
Copy link

ostheperson commented Feb 19, 2021

Nice solution.
But is there a way to mathematically determine if gears fit if you have the first and last one, rather than manually fitting them in? (by manually, I mean adding the radii until last value matches)

@joakimawesome
Copy link

Nice solution.
But is there a way to mathematically determine if gears fit if you have the first and last one, rather than manually fitting them in? (by manually, I mean adding the radii until last value matches)

Just knowing the first and last gears alone doesn't seem to guarantee that the gear sizes in between are >= 1.

@jlacar
Copy link
Author

jlacar commented Nov 22, 2021

@mukulsai7 Yes, I did get the interview call but I didn't follow through with it. Had an initial conversation but there was too much going on on my end at the time and the trajectory I wanted to keep my career on (being an Agile technical coach) didn't seem to line up with any of their needs.

@n1teshy
Copy link

n1teshy commented Apr 9, 2023

I love you, thank you for existing @jlacar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment