Interview Question (Find Final Line Number / Debugging)

Question:

I got stuck on an interview question that I couldn’t quite figure out.

Prompt Summary:

You are debugging a program of "length" lines.

You have 2 arrays: actions, breakpoints

The actions array consists of two different values: "next" or "continue"
The breakpoints array consists of line numbers aka where the next breakpoint is.

It’s guaranteed that 1<= breakpoints[i] <= length.

If the value is "next", you go to the next line.

If the value is "continue":

  • You go to the next breakpoint that is greater than the current line number.
  • If there are no more breakpoints left and the action is continue, return the length.

line_number is initialized to 1, but if there are breakpoints in breakpoints, the line_number should be initialized to breakpoints[0]

When there are no more actions left to do, return the line_number you’re at.

I’ve been trying to figure it out after the interview, here is what I have so far.

# Initialize line_number to 1
line_number = 1

# If there are no breakpoints or actions, return 1
if len(actions) == 0 and len(breakpoints) == 0:
    return line_number

# If there are no actions, but there are breakpoints, return the first breakpoint
if len(actions) == 0 and len(breakpoints) > 0:
    return breakpoints[0]

# If there are actions, but not breakpoints, make sure actions are all "next", else, return length
if len(actions) > 0 and len(breakpoints) == 0:
    if "continue" in actions:
        return length
    else:
        for i in actions:
            if i == "next":
                line_number += 1
        return line_number

# If there are actions and breakpoints...
while (len(actions) > 0):
    # If the line_number exceeds the length, return length
    if line_number >= length:
        return length

    # While the action is "continue"...
    while actions[0] == "continue":
        # If the length of breakpoint is greater than 0
        if len(breakpoints) == 0:
            return length
        
        # If the length of breakpoints is greater than 0...
        if len(breakpoints) > 0:
            # If the next breakpoint is greater than the line_number, then set line_number to the next breakpoint
            if breakpoints[0] > line_number:
                line_number = breakpoints[0]
                breakpoints.pop(0)
                actions.pop(0)
            
            # If the next breakpoint is less than the line_number...
            else:
                # Pop until the next breakpoint is greater than the line_number or the length of breakpoints is 0.
                while breakpoints[0] <= line_number:
                    if len(breakpoints) == 0:
                        return length
                    breakpoints.pop(0)
                line_number = breakpoints[0]
                breakpoints.pop(0)
                actions.pop(0)

    # If the action is "next", then set line_number to the next line
    while actions[0] == "next":
        line_number += 1
        actions.pop(0)

return(line_number)

I was only able to pass about 70% of the test cases. This isn’t exactly what I submitted, but somewhat close. If anybody could give me some advice about what I’m doing wrong or how to optimize it, that would be great. I originally just did two nested while loops inside a while loop. I was using i to increment actions, and j to increment breakpoints.

Asked By: Mr.Squid

||

Answers:

Your code is too busy, and it seems to be hiding the fact that you missed a requirement. For starters, you have a bunch of edge checks at the start of your function, but they’re not necessary.

This is a more compact version that (I think) accomplishes the goal. Its key differences are twofold:

  1. Initialize line_number to breakpoints[0] if it exists.
  2. Only pop one action per loop. This makes it much easier to follow what’s going on.
# Initialize line_number to 1 or breakpoints[0]
if len(breakpoints) > 0:
  line_number = breakpoints[0]
  # You could pop that first breakpoint here, since line_number only increases
  # But it's not necessary because the while True loop catches it.
else:
  line_number = 1

while len(actions) > 0:

  if actions[0] == 'continue':

    # Jump to the next largest breakpoint, if it exists
    while True:

      if len(breakpoints) == 0:
        # We've run out of breakpoints, return length.
        return length

      # Store the breakpoint and pop it
      nextBreakpoint = breakpoints[0]
      breakpoints.pop(0)
      
      # If the breakpoint is ahead of line_number, update line_number and stop looking.
      if nextBreakpoint > line_number:
        line_number = nextBreakpoint
        break

  if actions[0] == 'next':
    line_number += 1

  # Inside this loop, each iteration will remove exactly ONE action.
  actions.pop(0)

  # If the action resulted in a number too large, stop.
  if line_number > length:
    line_number = length
    break

# Note that if there were no actions, we return 1 or breakpoint[0], as required.
return line_number
Answered By: Welbog