Home > database >  two commands in comprehension
two commands in comprehension

Time:01-03

Sorry if the title is inaccurate but I'm unsure how to title this as I am kind of a rookie.

I am trying to solve a challenge:

"Complete the function scramble(str1, str2) that returns True if a portion of s1 characters can be rearranged to match s2, otherwise returns False."

So first i wanted to complete it like this:

return True if "".join(str(e) for e in s2 if e in s1 and s1.count(e) >= s2.count(e)) == s2 else False

However, this times out and apparently is not sufficiently optimized.

Oblivious as I am I assume it has something to do with the count() method so instead I am trying to remove e from s1 below if e is in s1 - because when a character from s2 is found in s1 it can not be used again (unless more of same character exist in s1. So for example s2 = 'stress' would need 3 x 's' occurences in s1 for the function to return True.

however, in the code below it seem like this part: s1.replace(e, '', 1) does not do anything when I print before/after.

def scramble(s1, s2):
    print(s1)
    ("".join(str(e), s1.replace(e, '', 1)) for e in s2 if e in s1)
    print(s1)
scramble('abcdefghijklmnopqrstuvzxy', 'stress')

What can I do?

CodePudding user response:

Your algorithm iterates over each character in s2, and then finds the character count of that character for s1 and s2. For ease of notation, let m = len(s1) and n = len(s2). Then, each .count() operation takes linear time in the number of characters in the string invoking .count(). So, we have O(n) iterations, and O(m n) work per iteration -- our final runtime is O(n*m n^2). If s2 is really long, we're going to see a lot of slowdown.

We can do better, by generating the counts before beginning to analyze them.

# You can use collections.Counter() here, but I've chosen to forgo this to make the runtime analysis clearer.
def count_characters(s):
    chars = {}
    for char in s:
        if char in chars:
            chars[char]  = 1
        else:
            chars[char] = 1
    return chars

def scramble2(s1, s2):
    s1_characters = count_characters(s1)
    s2_characters = count_characters(s2)
   
    for char in s2_characters:
        if char not in s1_characters or s1_characters[char] < s2_characters[char]:
            return False
    
    return True

Let's analyze the runtime of the revised algorithm:

count_characters() is linear in the length of the input string. So the character counters take O(m n) time to generate. Then, we need to examine each counter in s2_characters, and compare it with a counter in s1_characters. Regardless of whether you assume the alphabet is constant size, this takes O(n) time in the worst case. So, the final runtime is O(m n) -- i.e. linear in the lengths of the input strings.

  • Related