[Programming Pearls] Column 2 – Shift list

Problem:
(Right) shift given string by n characters.

Solution:
Case: Start with a concrete sample like “abcdefgh”, shift by 2 chars. Result will be like “ghabcdef”.

Model #1:
Note that “gh” will be finally at leftmost – so the process can be like
1. swap “gh” and “ab” => “ghcdefab”
2. shift “cdefab” by 2
Note that above process is recursive. Basically if we name “ab” as A, “cdef” as B, “gh” as C. Then the problem is to change ABC to CAB. So after step 1 we got CBA. Then the problem is converted to handle substring “BA” in same way – basically, separate “BA” to “B1B2A” where B1 and A have equivalent length, then swap to get AB2B1, and then the problem is on B2B1, etc.
There are some points that worth attention, like if we model the string to ABC (len(A) == len(C), what if len(A) > len(ABC) / 2?

Model #2:
Based on what’s being analyzed in model #1, if we model the string to AB then the problem is how to convert AB to BA. With the introduction of primitive ‘revert’ operation, it can be modelled like: revert AB to get B1A1, revert B1 and A1 one by one to get BA.

Code for model #2

def prog_2_B_shift(s, n):
    """
    >>> print(prog_2_B_shift('abcdefgh', 5))
    defghabc
    >>> print(prog_2_B_shift('abcdefgh', 2))
    ghabcdef
    >>> print(prog_2_B_shift('abcdefgh', 8))
    abcdefgh
    >>> print(prog_2_B_shift('abcdefgh', 11))
    fghabcde
    """
    def reverse(l, left, right):
        # TODO: check out of range
        # better use assertion since the expected caller will
        # be from internal
        while right > left:
            l[left], l[right] = l[right], l[left]
            left += 1
            right -= 1
    # TODO: check if l / s is empty
    # TODO: check if n < 0
    # better use if - return or if - throw because caller is
    # from outside - unless we got confirmation on the input data
    l = list(s)
    count = len(l)
    if (n > count): n = n - count
    reverse(l, 0, count - 1)
    reverse(l, 0, n - 1)
    reverse(l, n, count - 1)
    return ''.join(l)

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>