Home > Enterprise >  Is this a technical issue? a Math issue? A Python issue?
Is this a technical issue? a Math issue? A Python issue?

Time:05-10

First of all, I want to say that I am not looking for someone to do "my homework" I have invested some time thinking and working on this problem I'm just not sure if I just hit a Python edge or if there's something weird with really big numbers (beyond 10**256) that I'm missing. So, I'm solving Google Foobar Challenge #4 which states:

Fuel Injection Perfection

Commander Lambda has asked for your help to refine the automatic quantum antimatter fuel injection system for the LAMBCHOP doomsday device. It's a great chance for you to get a closer look at the LAMBCHOP -- and maybe sneak in a bit of sabotage while you're at it -- so you took the job gladly.

Quantum antimatter fuel comes in small pellets, which is convenient since the many moving parts of the LAMBCHOP each need to be fed fuel one pellet at a time. However, minions dump pellets in bulk into the fuel intake. You need to figure out the most efficient way to sort and shift the pellets down to a single pellet at a time.

The fuel control mechanisms have three operations:

  1. Add one fuel pellet
  2. Remove one fuel pellet
  3. Divide the entire group of fuel pellets by 2 (due to the destructive energy released when a quantum antimatter pellet is cut in half, the safety controls will only allow this to happen if there is an even number of pellets)

Write a function called solution(n) which takes a positive integer as a string and returns the minimum number of operations needed to transform the number of pellets to 1. The fuel intake control panel can only display a number up to 309 digits long, so there won't ever be more pellets than you can express in that many digits.

For example:

solution(4) returns 2: 4 -> 2 -> 1

solution(15) returns 5: 15 -> 16 -> 8 -> 4 -> 2 -> 1


My solution:

def solution(n):
    
    n = int(n)
    operations = 0

    # Handling edge cases here:
    # n(3)=2, n(2)=1 and n(1)=0
    if (n >= 1) and (n <= 3):
        return n - 1
    
    while n > 1:
    
        # Any even number will be divided by two
        # until we get an odd number. Since we are
        # guaranteed the number is divisible by
        # two we use floor division to avoid stack
        # overflow with strings of 309 digits.
        if n % 2 == 0:
            n = n // 2

        # Any odd number has two even neighbors:
        # a) One can be divided by two just ONCE, and
        # b) The other can be divided by two MORE than once
        # We will always take option b) for path optimization:
        elif (n-1) % 4 == 0:
            n -= 1
        else:
            n  = 1

        operations  = 1
 
    return operations

Now, my code passes 8 out of 10 cases. I check and rechecked... and rechecked again the code and the Math looks perfect, at some point I decided to do something I didn't want to do at first: Google other answers to find what was wrong. So I found this:

cnt=0
def divide(x):
    global cnt
    while(x>1):
        if (x & 1==0):
            #Dividing even number by two by shifting binary digits one step to the right.
            x=x>>1
        else:
            a=x 1
            b=x-1
            #counters ac & bc will be used to count trailing 0s
            ac=bc=0
            #count trailing 0's for x 1
            while(a & 1==0):
                a=a>>1
                ac =1
            #count trailing 0's for x-1
            while(b & 1==0):
                b=b>>1
                bc =1
            #go with x 1 if it has more trailing 0s in binary format. Exception is number 
            #3 as b10 can be divided in less steps than b100.
            #edge case 3 identified by manually testing numbers 1-10.
            if (ac>bc and x!=3):
                x =1
            else:
                x-=1
        cnt =1

def solution(n):
    global cnt
    n=int(n)
    divide(n)
    return cnt

Source: Google Foobar: How to find edge cases and identify test cases. Python

Now, here comes the really strange thing, that second code seems to use a similar approach to mine (looking for the largest amount of trailing zeros in binary is kinda the same as looking for the number that can be divided by two more than once instead of just once), and both codes reach the exact same solution for any integer between 1 and 10^256, now at some point between 10^256 and 10^257 something really weird happens: my code gives an answer of 'n' operations while the other solution gives an output of 'n-1' operations. Now we know that 256 is kind of a 'magic' number for digital computers, the internet itself (IPv4) is built upon that number. Did I just break something here?

Now, can anybody tell me why am I getting different results with the scripts? am I missing something? I'm losing my mind here.

CodePudding user response:

Your code looks like it's going to get the wrong result for 12.
12 -> 6 -> 3 -> 4 -> 2 -> 1 instead of 12 -> 6 -> 3 -> 2 -> 1.

Your special casing of 3 needs to be inside the loop, not outside of it.


And to answer your other question. 256 is special. There's nothing special about 2^256 or 10^256.

  • Related