Home > Blockchain >  slow runtime for large input values
slow runtime for large input values

Time:04-11

This code is supposed to take a string of r (red), b (blue) and y (yellow) values and combine them, pairwise, to find one resulting colour. For example, 'rybbry' -> 'brbyb' -> 'yyrr' -> 'ybr' -> 'ry' -> 'b'. It works for small inputs, but forever for big ones. Too many nested loops?

def colour_trio(colours):
  while len(colours) > 1:
    new_colours = ''
    for i in range(len(colours) - 1):
      if colours[i:i 2] == 'rr' or colours[i:i 2] == 'by' or colours[i:i 2] == 'yb':
        new_colours = new_colours   'r'
      elif colours[i:i 2] == 'bb' or colours[i:i 2] == 'ry' or colours[i:i 2] == 'yr':
        new_colours = new_colours   'b'
      else:
        new_colours = new_colours   'y'
    colours = new_colours
  
  if len(colours) == 1:
    if colours[0] == 'b':
        return 'b'
    if colours[0] == 'y':
        return 'y' 
    if colours[0] == 'r':
        return 'r' 

CodePudding user response:

Your code makes use of repeated string concatencation. Each addition operation on a string takes O(n) time, because strings are immutable. This operation occurs O(n^2) times, so the runtime of your algorithm is O(n^3), where n is the length of the string.

One optimization is to use a list to store the letters, and then call ' '.join(), taking the runtime from O(n^3) to O(n^2):

def colour_trio(colours):
    result = colours
    
    while len(result) != 1:
        letters = []
        for fst, snd in zip(result, result[1:]):
            if fst == snd:
                letters.append(fst)
            else:
                [letter_to_add] = list(set('ryb') - set(fst) - set(snd))
                letters.append(letter_to_add)
            
        result = ''.join(letters)
        
    return result
    
print(colour_trio("rybbry")) # Prints "b"

CodePudding user response:

I think this is faster than the last solution I posted and faster than other solutions, I think classes make everything tidy looking, but you can re-work it to become a single function.

New Solution

colors = ['r', 'b', 'y']

def split(x):
    return [f'{Couple(i)}' if len(i)>1 else i for i in 
           [''.join(x[i:i 2]) for i in range(0, len(x), 2)]]

class Couple:
    def __init__(self, x) -> None:
        self.a = x[0]
        self.b = x[1]

    def __repr__(self) -> str:
        if self.a == self.b:
            return self.a
        return (set(colors).difference(set((self.a, self.b))).pop())

def ColoursTrio(x):
    while len(x) > 1:
        x = split(x)
    return x[0]

print(ColoursTrio('rybbry'))

or even shorter (and faster):

def ColoursTrio(x):
    
    while len(x) > 1:
        x = [f'''{i[0] if i[0] == i[1] 
            else  set("rby").difference(set((i[0],
            i[1]))).pop()}''' if len(i)>1 else i for i in 
            [''.join(x[i:i 2]) for i in range(0, len(x), 2)]]
    
    return x[0]

Old Solution

This is almost a bit convoluted but I think it's faster, I also think it's very similar to the one posted by @BrokenBenchmark (and I think his is better) so I'll add his example string too!

COLORS = ['r','b','y']

class ColorsCouple:
    def __init__(self, x:str, y:str) -> None:
        self.x = x
        self.y = y
    
    def mix(self):
        if self.x == self.y:
            return f'{self.x}'
        if 'y' in (self.x, self.y):
            return set(COLORS).difference((self.x, self.y)).pop()
        return 'y'

class Colors:
    def __init__(self, colors:str) -> None:
        self.colors = self.get_couples([*colors])
    
    def get_couples(self, element):
        return [element[x:x 2] for x in range(0, len(element), 2)]

    def get_color(self):
        colors = [ColorsCouple(*couples).mix() if len(couples)==2 else couples[0] for couples in self.colors]
        while len(colors)>1:       
            colors = self.get_couples(colors)
            colors = [ColorsCouple(*couples).mix() if len(couples)==2 else couples[0] for couples in colors]
        return colors[0]

    def __repr__(self) -> str:
        return f'{self.get_color()}'



print(Colors('rybbry'))
  • Related