Morgan and a String HackerRank challenge
This is an improvement on @Toby's answer

Instead of str += char which allocates a new string you can yield the result and &quot;&quot;.join() it later on

Here's the problem: consider &quot;BAB&quot;, &quot;BAC&quot;. One would think to compare the two strings, see that BA-&gt;B is more minimal than BA-&gt;C. or you see that BA-&gt;B(end of string) is shorter than BA-&gt;(jump to other string)BA. Both of these are wrong, because we end up with BABBAC, instead of BABABC, which is more minimal (BABA &lt; BABB).
The z fixes things because it fixes the issue where we incorrectly choose BA-&gt;B\0 over BA(first stack)-&gt;(other stack)BA. BA-&gt;BA &lt; BA-&gt;Bz. Realistically what we should do during tiebreakers is jump to the other stack when one ends so we are comparing against BABB instead of BABz, but the z solution is faster.

Normally with the &quot;z&quot; fix you need to remove them from the end result, but because any uppercase char is lower then the lowercase &quot;z&quot; we know after len(a) + len(b) - 2 iterations only the 2 &quot;z&quot; strings remain in the resulting string. thus we only need to loop len(a) + len(b) - 2 times


Improved code
def morgan(a, b):
    a += &quot;z&quot;
    b += &quot;z&quot;
    for _ in range(len(a) + len(b) - 2):
        if a &lt; b:
            yield a[0]
            a = a[1:]
        else:
            yield b[0]
            b = b[1:]

def morgan_and_string(a, b):
    &quot;&quot;&quot;
    Return the lexicographically smallest string formed from the input strings, keeping each string
    in order in the result.

    Same length
    &gt;&gt;&gt; morgan_and_string(&quot;ACEG&quot;, &quot;BDFH&quot;)
    'ABCDEFGH'
    &gt;&gt;&gt; morgan_and_string(&quot;ABCD&quot;, &quot;ABCD&quot;)
    'AABBCCDD'

    Empty input
    &gt;&gt;&gt; morgan_and_string(&quot;ABCD&quot;, &quot;&quot;)
    'ABCD'
    &gt;&gt;&gt; morgan_and_string(&quot;&quot;, &quot;ABCD&quot;)
    'ABCD'

    Different length
    &gt;&gt;&gt; morgan_and_string(&quot;Z&quot;, &quot;ABCD&quot;)
    'ABCDZ'
    &gt;&gt;&gt; morgan_and_string(&quot;ABCD&quot;, &quot;Z&quot;)
    'ABCDZ'

    Descending strings
    &gt;&gt;&gt; morgan_and_string(&quot;BA&quot;, &quot;BA&quot;)
    'BABA'

    &gt;&gt;&gt; morgan_and_string(&quot;ZAX&quot;, &quot;ZAY&quot;)
    'ZAXZAY'
    &gt;&gt;&gt; morgan_and_string(&quot;ZAY&quot;, &quot;ZAX&quot;)
    'ZAXZAY'

    Proper prefix
    &gt;&gt;&gt; morgan_and_string(&quot;BABC&quot;, &quot;BA&quot;)
    'BABABC'
    &gt;&gt;&gt; morgan_and_string(&quot;CABC&quot;, &quot;CA&quot;)
    'CABCAC'
    &gt;&gt;&gt; morgan_and_string(&quot;BAAC&quot;, &quot;BA&quot;)
    'BAABAC'
    &quot;&quot;&quot;
    return &quot;&quot;.join(morgan(a, b))

if __name__ == '__main__':
    import doctest
    doctest.testmod()