Beispiel #1
0
def test_intersects__yes():
    left = LinkedList([1, 2, 3, 4, 5])
    element = left[3]

    right = LinkedList([1, 2])
    right.append(element)

    assert intersects(left, right) == element
Beispiel #2
0
def test_has_loop__yes():
    ll = LinkedList([1, 2, 3, 4, 5])
    element = ll[4]
    element.next = ll[1]

    assert has_loop(ll) == ll[1]
    assert ll[5] == ll[1]
Beispiel #3
0
def test_remove_dupes__with_dupes():
    s = set([1, 2, 3, 4, 5, 1, 2, 3, 4, 5])
    ll = LinkedList(s)

    s_no_dupes = set([1, 2, 3, 4, 5])
    assert set(remove_dupes__using_set(ll).values) == s_no_dupes
    assert set(remove_dupes__no_buffer(ll).values) == s_no_dupes
Beispiel #4
0
def remove_dupes__no_buffer(ll):
    """
    Without using the hash, sorting in-place is the way to do it.

    Just using built-in sort here, O(n log n) overall.
    """
    sll = LinkedList(sorted(ll.values))
    current = sll.head
    while current.next is not None:
        if current.value == current.next.value:
            current.next = current.next.next
        else:
            current = current.next

    return sll
Beispiel #5
0
def partition(ll, p):
    """
    Admittedly, much of the implementation magic here is making sure that the
    basic dunder method __add__ to join two linked lists works correctly.  I
    also rewrote the LinkedList initializer slightly to make use of a new
    append method that appends an Element to the end of a LinkedList and
    adjusts the prev/next pointers and the tail pointer correctly.
    """
    left = LinkedList([])
    right = LinkedList([])
    for value in ll.values:
        element = Element(value)
        if value < p:
            left.append(element)
        else:
            right.append(element)

    return left + right
Beispiel #6
0
def test_sum__not_reversed_zero():
    left = LinkedList([0])
    right = LinkedList([0])
    assert list(sum(left, right, reverse=False).values) == [0]
Beispiel #7
0
def test_partition__one():
    ll = partition(LinkedList([1]), 1)
    assert validate(ll, 1)
Beispiel #8
0
def test_partition__no_left_side():
    ll = partition(LinkedList([5, 6, 7, 8, 9, 10]), 4)
    assert validate(ll, 4)
Beispiel #9
0
def test_is_palindrome__solo():
    assert is_palindrome(LinkedList('z'))
Beispiel #10
0
def test_is_palindrome__no():
    assert not is_palindrome(LinkedList('this is a palindrome'))
Beispiel #11
0
def test_sum__reverse_nothing():
    left = LinkedList([])
    right = LinkedList([])
    assert list(sum(left, right).values) == []
Beispiel #12
0
def sum(left, right, reverse=True):
    """
    Summation of digits may "carry over" a value to the next digit place.

    When evaluating the linked list, it's simple to just take the carry along
    the traversal of both left and right in tandem, and apply it to the next
    digit place.  If one list terminates before the other, the carry gets
    applied just the same until the traversal ends for the longer list.  This
    algorithm runs in O(M+N) time where M, N is the length of left, right
    respectively.  The sum of each individual element can be applied into a new
    element and just appended to a new linked list.

    The non-reversed case is a bit trickier, and requires special handling for
    the possibility of non-equal list lengths, as we can't assume the first
    elements are the same digit place.  Once we determine the maximum length,
    we can use a hash to store each digit place keyed by power of 10.  Using
    the hash allows us to keep the runtime to O(M+N) at the cost of
    O(max(M, N)) space.  Other methods involve complicated back-tracking with
    pointers, or using a stack which is essentially the first method.

    The non-reserved solution avoids fun workarounds like reversing the linked
    list and running the first algorithm, or converting the LinkedList into
    numbers, summing those, and then converting the number into a string and
    then passing it directly into LinkedList... :rolling_on_the_floor_laughing:
    """
    result = LinkedList([])
    if reverse:
        current_left = left.head
        current_right = right.head

        carry = 0
        while current_left is not None and current_right is not None:
            left_value = 0
            if current_left is not None:
                left_value = current_left.value
                current_left = current_left.next

            right_value = 0
            if current_right is not None:
                right_value = current_right.value
                current_right = current_right.next

            total = left_value + right_value + carry
            carry = total // 10
            digit = total % 10
            result.append(Element(digit))

        if carry > 0:
            result.append(Element(carry))
    else:
        # this is needed here in case there is carry past the max digit place
        places = defaultdict(lambda: 0)

        for ll in [left, right]:
            for index, element in enumerate(ll):
                place = len(ll) - index - 1
                places[place] += element.value

        for place in sorted(places.keys()):
            carry = places[place] // 10
            places[place] %= 10
            if carry > 0:
                places[place + 1] += carry

        for place in sorted(places.keys(), reverse=True):
            result.append(Element(places[place]))

    return result
Beispiel #13
0
def test_delete__next_to_head():
    s = set([1, 2, 3, 4, 5])
    ll = LinkedList(s)
    element = ll[1]
    delete(ll, element)
    assert set(ll.values) == set([1, 3, 4, 5])
Beispiel #14
0
def test_delete__middle():
    s = set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
    ll = LinkedList(s)
    element = ll[6]
    delete(ll, element)
    assert set(ll.values) == set([1, 2, 3, 4, 5, 6, 8, 9, 10])
Beispiel #15
0
def test_intersects__no():
    left = LinkedList([1, 2, 3, 4, 5])
    right = LinkedList([1, 2, 3, 4, 5])

    assert intersects(left, right) is None
Beispiel #16
0
def test_sum__not_reversed_example():
    left = LinkedList([6, 1, 7])
    right = LinkedList([2, 9, 5])
    assert list(sum(left, right, reverse=False).values) == [9, 1, 2]
Beispiel #17
0
def test_sum__not_reversed_plus_carry():
    left = LinkedList([6, 1, 9])
    right = LinkedList([9, 9, 5])
    assert list(sum(left, right, reverse=False).values) == [1, 6, 1, 4]
Beispiel #18
0
def test_remove_dupes__no_dupes():
    s = set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
    ll = LinkedList(s)
    assert set(remove_dupes__using_set(ll).values) == s
    assert set(remove_dupes__no_buffer(ll).values) == s
Beispiel #19
0
def test_is_palindrome__yes():
    assert is_palindrome(LinkedList('doomanevildeedlivenamood'))
    assert is_palindrome(LinkedList('drabasafoolaloofasabard'))
Beispiel #20
0
def remove_dupes__using_set(ll):
    """
    The naive approach is to use a set to add values and then just return the
    values from the set.  This is O(n).
    """
    return LinkedList(set(ll.values))
Beispiel #21
0
def test_is_palindrome__empty():
    assert is_palindrome(LinkedList(''))
Beispiel #22
0
def test_sum__reverse_zero():
    left = LinkedList([0])
    right = LinkedList([0])
    assert list(sum(left, right).values) == [0]
Beispiel #23
0
def test_partition__example():
    ll = partition(LinkedList([3, 5, 8, 5, 10, 2, 1]), 5)
    assert validate(ll, 5)
Beispiel #24
0
def test_sum__reverse_example():
    left = LinkedList([7, 1, 6])
    right = LinkedList([5, 9, 2])
    assert list(sum(left, right).values) == [2, 1, 9]
Beispiel #25
0
def test_partition__no_right_side():
    ll = partition(LinkedList([1, 2, 3, 4, 5, 6]), 7)
    assert validate(ll, 7)
Beispiel #26
0
def test_sum__reverse_plus_carry():
    left = LinkedList([9, 1, 6])
    right = LinkedList([5, 9, 9])
    assert list(sum(left, right).values) == [4, 1, 6, 1]
Beispiel #27
0
def test_partition__none():
    ll = partition(LinkedList([]), 0)
    assert len(ll) == 0
Beispiel #28
0
def test_has_loop__no():
    ll = LinkedList([1, 2, 3, 4, 5])

    assert has_loop(ll) is None