def question_1(): print('##### Sorted Merge #####\n') def version_1(test): ((A, size_A, B), expected) = test ix_A = size_A - 1 ix_B = len(B) - 1 ix_merged = ix_A + ix_B + 1 # or size_A + len(B) - 1 while ix_B >= 0: if (ix_A >= 0) and (A[ix_A] > B[ix_B]): A[ix_merged] = A[ix_A] ix_A -= 1 else: A[ix_merged] = B[ix_B] ix_B -= 1 ix_merged -= 1 return A == expected tests = [ (([1, 2, 3, None, None, None], 3, [4, 5, 6]), [1, 2, 3, 4, 5, 6]), (([4, 5, 6, None, None, None], 3, [1, 2, 3]), [1, 2, 3, 4, 5, 6]), (([1, 4, 5, 19, None, None, None], 4, [2, 13, 30]), [1, 2, 4, 5, 13, 19, 30]) ] for test in tests: for version in range(1, 2): test_question("version %d => {} merged with {} equals to {}" % version, [test[0][0][0 : test[0][1]], test[0][2], test[1]], locals()['version_%d' % version](test)) print()
def question_4(): print('##### Queue via Stacks #####\n') # time: O(N); space: O(N) def version_1(test): forward_stack = Stack() backward_stack = Stack() for t in test: forward_stack.push(t) while not forward_stack.is_empty(): backward_stack.push(forward_stack.pop()) result = ''.join(backward_stack.to_array()) return test == result tests = [ '', 'abcdefghijklmnopqrstuvwxyz', 'abcdefghijklmnopqrstuvwxyza', 'aabbcc', 'mdifnafanfa', 'aifasoid', 'zyxvwutsrqponmlkjihgfedcba' ] for test in tests: for version in range(1, 2): test_question("version %d => '{}' inserted in queue" % version, [test], locals()['version_%d' % version](test)) print()
def question_1(): print('##### Is Unique #####\n') # time: O(N**2); space: O(1) # no additional structures used def version_1(test): (given, expected) = test size = len(given) for i in range(size): for j in range(i + 1, size): if given[i] == given[j]: return expected == False return expected == True # time: O(N); space: O(N) # using a hash set def version_2(test): (given, expected) = test chars = set() for t in given: if t in chars: return expected == False chars.add(t) return expected == True # time: O(N); space: O(1) # using a bit mask (hint 117; considers only lowercase letters) def version_3(test): (given, expected) = test mask = 0 for t in given: vector = 1 << (ord(t) - 97) if (mask & vector) == vector: return expected == False mask = mask | vector return expected == True tests = [('', True), ('abcdefghijklmnopqrstuwvxyz', True), ('abcdefghijklmnopqrstuwvxyza', False), ('aabbcc', False), ('mdifnafanfa', False), ('aifasoid', False), ('zyxvwutsrqponmlkjihgfedcba', True)] for test in tests: for version in range(1, 4): test_question("version %d => '{}' is {}unique" % version, [test[0], '' if test[1] else 'NOT '], locals()['version_%d' % version](test)) print()
def question_2(): print('##### Stack Min #####\n') # time: O(N); space: O(N) def version_1(test): class ItemWithMin(Item): def __init__(self, value): super(ItemWithMin, self).__init__(value) self.my_min = value def check_min(self): if self.below and self.below.my_min < self.my_min: self.my_min = self.below.my_min class StackWithMin(Stack): def __init__(self): super(StackWithMin, self).__init__() def push(self, value): super(StackWithMin, self).push(value, constructor=ItemWithMin) self.top.check_min() def min(self): if self.is_empty(): return None return self.top.my_min (given_seq, num_pops, expected) = test stack = StackWithMin() for s in given_seq: stack.push(s) for _ in range(num_pops): stack.pop() return stack.min() == expected tests = [ (list(), 1, None), ([-5, -4, -3, -2, -1, 0, 1, 2, 3, 4], 0, -5), ([4, 3, 2, 1, 0, -1, -2, -3, -4, -5], 0, -5), ([-2, -3, 4, 0, 3, 1, -1, 2, -4, -5], 1, -4), ([-2, -3, 4, 0, 3, 1, -1, 2, -4, -5], 2, -3) ] for test in tests: for version in range(1, 2): test_question("version %d => {}, after {} pops, min is {}" % version, [test[0], test[1], test[2]], locals()['version_%d' % version](test)) print()
def question_5(): print('##### Sum Lists #####\n') # time: O(N) (where N is the longer input); space O(N) def version_1(test): (given, expected) = test (A, _) = create_linked_list( given[0]) # not considered in the O(.) function calculation (B, _) = create_linked_list( given[1]) # not considered in the O(.) function calculation carry_on = 0 head_C = tail_C = None while True: val_A = A.value if A else 0 val_B = B.value if B else 0 result = val_A + val_B + carry_on carry_on = 0 if result > 9: result = result - 10 carry_on = 1 # has something to insert? if result > 0 or carry_on > 0: if tail_C: tail_C.next = LinkedListNode(result) tail_C = tail_C.next else: head_C = tail_C = LinkedListNode(result) else: break if A: A = A.next if B: B = B.next C = reduce_linked_list_to_list( head_C) # not considered in the O(.) function calculation return C == expected tests = [(([7, 1, 6], [5, 9, 2]), [2, 1, 9]), (([7, 8, 9], [5, 9, 2]), [2, 8, 2, 1]), (([7, 8, 8, 4], [5, 9, 7]), [2, 8, 6, 5])] for test in tests: for version in range(1, 2): test_question("version %d => {} + {} = {}" % version, [test[0][0], test[0][1], test[1]], locals()['version_%d' % version](test)) print()
def question_2(): print('##### Check Permutation #####\n') # time: O(A*logA + B*logB); space: O(A + B) # Python uses Timsort, with worst cases: O(N*logN) and O(N) for time and space, respectively def version_1(test): (A, B, expected) = test if len(A) != len(B): return expected == False return expected == (sorted(A) == sorted(B)) # time: O(len(A)); space: O(len(A)) # worst case complexity only happens when A and B have the same length def version_2(test): (A, B, expected) = test if len(A) != len(B): return expected == False stats_A = dict() stats_B = dict() for i in range(len(A)): A_i = A[i] if A_i not in stats_A: stats_A[A_i] = 0 stats_A[A_i] += 1 B_i = B[i] if B_i not in stats_B: stats_B[B_i] = 0 stats_B[B_i] += 1 return expected == (stats_A == stats_B) tests = [('', '', True), ('aabbcc', 'abc', False), ('abcaa', 'abcaa', True), ('abc', 'bca', True), ('abc', 'bda', False), ('aabccc', 'aabccccccc', False)] for test in tests: for version in range(1, 3): test_question( "version %d => '{}' is {}permutation of '{}'" % version, [test[0], '' if test[2] else 'NOT ', test[1]], locals()['version_%d' % version](test)) print()
def question_2(): print('##### Group Anagrams #####\n') # time: # O(N*W*logW) (N = #word and W = avg size of a word) def version_1(test): (given, expected) = test anagrams = dict() # O(N*W*logW) for word in given: # O(N) sorted_word = list(word) merge_sort(sorted_word) # O(W*logW) sorted_word = ''.join(sorted_word) if sorted_word in anagrams: anagrams[sorted_word].append(word) else: anagrams[sorted_word] = [word] keys = list(anagrams.keys()) merge_sort(keys) sorted_words = list() # O(N*W*logW) for key in keys: # O(1..N/p..N) (#keys <= N and p = #words/key) merge_sort(anagrams[key]) # O(W*logW) for word in anagrams[key]: # O(N..p..1) (p = #words/key) sorted_words.append(word) return sorted_words == expected tests = [ (['anagram', 'arara', 'aaagmnr', 'nagaram', 'arraa', 'ate', 'eta', 'eat'], ['aaagmnr', 'anagram', 'nagaram', 'arara', 'arraa', 'ate', 'eat', 'eta']), (['listen', 'admirer', 'silent', 'paternal', 'parental', 'married'], ['parental', 'paternal', 'admirer', 'married', 'listen', 'silent']) ] for test in tests: for version in range(1, 2): test_question("version %d => {} sorted to {}" % version, [test[0], test[1]], locals()['version_%d' % version](test)) print()
def question_1(): print('##### Remove Dups #####\n') # time: O(N); space: O(N) def version_1(test): given = test[0] expected = test[1] (head, _) = create_linked_list( given) # not considered in the O(.) function calculation chars = set() if head: chars.add(head.value) prev = head node = head.next while node: if node.value in chars: # 1st time prev.next = node.next else: chars.add(node.value) prev = node node = node.next output = reduce_linked_list_to_str( head) # not considered in the O(.) function calculation return output == expected tests = [('', ''), ('abcdee', 'abcde'), ('abcddefacdlkasdlk', 'abcdeflks'), ('abcdefghijklmnopqrstuvwxyz', 'abcdefghijklmnopqrstuvwxyz'), ('abcdeyzabcd', 'abcdeyz')] for test in tests: for version in range(1, 2): test_question("version %d => '{}' becomes '{}'" % version, [test[0], test[1]], locals()['version_%d' % version](test)) print()
def question_2(): print('##### Run Kth to Last #####\n') # time: O(N); space O(1) def version_1(test): given = test[0] k = test[1] expected = test[2] (head, _) = create_linked_list( given) # not considered in the O(.) function calculation node = head num_nodes = 0 while node: num_nodes += 1 node = node.next node = None if 0 < k <= num_nodes: num_nodes = num_nodes - k node = head while num_nodes > 0: node = node.next num_nodes -= 1 return node.value == expected return node == expected tests = [(list(), 1, None), ([1, 2, 3], 3, 1), ([1, 2, 3], 0, None), ([4, 3, 2, 1], 1, 1), ([4, 3, 2, 1], 4, 4), ([4, 3, 2, 1], 5, None)] for test in tests: for version in range(1, 2): test_question("version %d => k = {}, in list {} is {}" % version, [test[1], test[0], test[2]], locals()['version_%d' % version](test)) print()
def question_3(): print('##### Delete Middle Node #####\n') # time: O(N); space: O(1) def version_1(test): given = test[0] value = test[1] expected = test[2] (head, _) = create_linked_list( given) # not considered in the O(.) function calculation if head: prev = head node = head.next while node: if node.value == value and node.next: # node.next avoids matching the tail prev.next = node.next break prev = node node = node.next output = reduce_linked_list_to_str( head) # not considered in the O(.) function calculation return output == expected tests = [('', 'a', ''), ('abcdef', 'c', 'abdef'), ('abcdef', 'a', 'abcdef'), ('abcdef', 'f', 'abcdef'), ('abbbf', 'b', 'abbf')] for test in tests: for version in range(1, 2): test_question( "version %d => '{}' after removal of '{}' becomes '{}'" % version, [test[0], test[1], test[2]], locals()['version_%d' % version](test)) print()
def question_0(): print('##### Merge Sort #####\n') def version_1(test): (given, expected) = test sorted_given = given[:] # doesn't enter in the O(.) calculation merge_sort(sorted_given) return sorted_given == expected tests = [ ([6, 3, 1, 7, 2, 8, 5, 4], [1, 2, 3, 4, 5, 6, 7, 8]), ([1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7, 8]), ([8, 7, 6, 5, 4, 3, 2, 1], [1, 2, 3, 4, 5, 6, 7, 8]) ] for test in tests: for version in range(1, 2): test_question("version %d => {} sorted to {}" % version, [test[0], test[1]], locals()['version_%d' % version](test)) print()
def question_6(): print('##### String Compression #####\n') # time: O(N) or O(N*d), where O(d) is the order to turn int into string; space: O(N) def version_1(test): given = test[0] expected = test[1] compressed = '' cur = prev = given[0] i = freq = 0 while i <= len(given): cur = given[i] if i < len(given) else None if i < len(given) and cur == prev: freq += 1 else: compressed = '{}{}{}'.format(compressed, prev, freq) freq = 1 prev = cur i += 1 final = compressed if len(compressed) < len(given) else given return final == expected tests = [('abc', 'abc'), ('aabbcc', 'aabbcc'), ('aabbccc', 'a2b2c3'), ('aabcccccaaa', 'a2b1c5a3')] for test in tests: for version in range(1, 2): test_question("version %d => '{}' is compressed to '{}'" % version, [test[0], test[1]], locals()['version_%d' % version](test)) print()
def question_9(): print('##### String Rotation #####\n') # time: O(N); space: O(N) (considering the indexed strings must be copied) def version_1(test): given = test[0] rotated = test[1] expected = test[2] if len(given) != len(rotated): return False == expected for i in range(len(given)): i_comp = len(rotated) - i if given[i:] == rotated[:i_comp] and rotated[i_comp:] == given[:i]: return True == expected return False == expected def version_2(test): given = test[0] rotated = test[1] expected = test[2] if len(given) != len(rotated): return False == expected i = j = 0 found_first_equal = False while j < len(rotated): g = given[i] e = rotated[j] i = (i + 1) % len(given) if g == e: found_first_equal = True j += 1 if j > len(given): return False == expected if found_first_equal and (g != e): return False == expected return True == expected tests = [('waterbottle', 'erbottlewat', True), ('waterbottle', 'erbottlehov', False), ('waterbottle', 'bottlewater', True), ('waterbottle', 'bottlehover', False), ('waterbottle', 'bottlewaters', False), ('waterbottle', 'erbottlewaterbottlewat', False), ('erbottlewaterbottlewat', 'waterbottle', False), ('erbottlewaterbottlewat', 'erbottlewat', False)] for test in tests: for version in range(1, 3): test_question( "version %d => '{}' is {}a rotation of '{}'" % version, [test[0], '' if test[2] else 'NOT ', test[1]], locals()['version_%d' % version](test)) print()
def question_3(): print('##### Stack of Plates #####\n') class SetOfStacks(object): def __init__(self, threshold): self.threshold = threshold self.stacks = list() self.cur_stack_index = -1; def push(self, value): if self.cur_stack_index < 0: self.stacks.append(Stack()) self.cur_stack_index = 0 cur_stack = self.stacks[self.cur_stack_index] if cur_stack.size == self.threshold: cur_stack = Stack() self.stacks.append(cur_stack) self.cur_stack_index += 1 cur_stack.push(value) def pop(self): if self.cur_stack_index < 0: return None cur_stack = self.stacks[self.cur_stack_index] value = cur_stack.pop() if cur_stack.is_empty(): self.stacks.remove(cur_stack) self.cur_stack_index -= 1 return value def to_array_list(self): arrays = list() for stack in self.stacks: arrays.append(stack.to_array()) return arrays # time: O(?); space: O(N) def version_1(test): (given_seq, threshold, num_pops, expected) = test set_of_stacks = SetOfStacks(threshold) for s in given_seq: set_of_stacks.push(s) for _ in range(num_pops): set_of_stacks.pop() return set_of_stacks.to_array_list() == expected tests = [ (range(1, 11), 3, 0, [[3, 2, 1], [6, 5, 4], [9, 8, 7], [10]]), (range(1, 11), 5, 0, [[5, 4, 3, 2, 1], [10, 9, 8, 7, 6]]), (range(1, 11), 3, 2, [[3, 2, 1], [6, 5, 4], [8, 7]]) ] for test in tests: for version in range(1, 2): test_question("version %d => {} stacked into {} stacks of max size {} and equal to {} after {} pops" % version, [list(test[0]), len(test[3]), test[1], test[3], test[2]], locals()['version_%d' % version](test)) print()
def question_7(): print('##### Rotate Matrix #####\n') def version_1(test): given = test[0] expected = test[1] size = len(given) middled = int(size / 2) end = size - 1 for i in range(middled): for j in range(i, end - i): upper_left_line = i upper_left_column = j % size upper_left_value = given[upper_left_line][upper_left_column] bottom_left_line = end - j bottom_left_column = i % size given[upper_left_line][upper_left_column] = given[ bottom_left_line][bottom_left_column] bottom_right_line = end - i bottom_right_column = end - j given[bottom_left_line][bottom_left_column] = given[ bottom_right_line][bottom_right_column] upper_right_line = j upper_right_column = end - i given[bottom_right_line][bottom_right_column] = given[ upper_right_line][upper_right_column] given[upper_right_line][upper_right_column] = upper_left_value return given == expected tests = [([['1-1']], [['1-1']]), ([['1-1', '1-2', '1-3', '1-4'], ['2-1', '2-2', '2-3', '2-4'], ['3-1', '3-2', '3-3', '3-4'], ['4-1', '4-2', '4-3', '4-4']], [['4-1', '3-1', '2-1', '1-1'], ['4-2', '3-2', '2-2', '1-2'], ['4-3', '3-3', '2-3', '1-3'], ['4-4', '3-4', '2-4', '1-4']]), ([['1-1', '1-2', '1-3', '1-4', '1-5'], ['2-1', '2-2', '2-3', '2-4', '2-5'], ['3-1', '3-2', '3-3', '3-4', '3-5'], ['4-1', '4-2', '4-3', '4-4', '4-5'], ['5-1', '5-2', '5-3', '5-4', '5-5']], [['5-1', '4-1', '3-1', '2-1', '1-1'], ['5-2', '4-2', '3-2', '2-2', '1-2'], ['5-3', '4-3', '3-3', '2-3', '1-3'], ['5-4', '4-4', '3-4', '2-4', '1-4'], ['5-5', '4-5', '3-5', '2-5', '1-5']])] for test in tests: for version in range(1, 2): test_question( "version %d =>\nmatrix\n\n {}\nrotated to\n\n {}\n" % version, [show_matrix(test[0]), show_matrix(test[1])], locals()['version_%d' % version](test)) print()
def question_5(): print('##### One Away #####\n') # time: O(N), where N is the size of the smaller string; space: O(1) def version_1(test): original = test[0] edited = test[1] expected = test[2] diff_len = len(original) - len(edited) if diff_len == 0: # possible replace num_diffs = 0 # time: O(N) for i in range(len(original)): if original[i] != edited[i]: num_diffs += 1 if num_diffs > 1: return False == expected return True == expected elif diff_len == 1: # possible removal i = j = 0 # time: O(N), where N is the length of edited while (i < len(original)) and (j < len(edited)): if original[i] == edited[j]: j += 1 i += 1 if i - j == 2: return False == expected return True == expected elif diff_len == -1: # possible insertion i = j = 0 # time: O(N), where N is the length of original while (i < len(original)) and (j < len(edited)): if original[i] == edited[j]: i += 1 j += 1 if i - j == -2: return False == expected return True == expected return False == expected # time: O(N), where N is the size of the smaller string; space: O(1) def version_2(test): original = test[0] edited = test[1] expected = test[2] diff_len = len(original) - len(edited) if diff_len == 0: # possible replace num_diffs = 0 # time: O(N) for i in range(len(original)): if original[i] != edited[i]: num_diffs += 1 if num_diffs > 1: return False == expected return True == expected elif (diff_len == 1) or (diff_len == -1): # possible removal or insertion i = j = 0 while (i < len(original)) and (j < len(edited)): if original[i] == edited[j]: i += 1 j += 1 else: if diff_len == 1: i += 1 else: j += 1 if (diff_len == 1 and i - j == 2) or (diff_len == -1 and i - j == -2): return False == expected return True == expected return False == expected # time: O(N), where N is the size of the smaller string; space: O(1) def version_3(test): original = test[0] edited = test[1] expected = test[2] diff_len = len(original) - len(edited) if diff_len < -1 or diff_len > 1: return False == expected num_diffs = i = j = 0 while (i < len(original)) and (j < len(edited)): if diff_len == 0: if original[i] != edited[i]: num_diffs += 1 if num_diffs > 1: return False == expected i += 1 j += 1 else: if original[i] == edited[j]: i += 1 j += 1 else: if diff_len == 1: i += 1 else: j += 1 if (diff_len == 1 and i - j == 2) or (diff_len == -1 and i - j == -2): return False == expected return True == expected tests = [('pale', 'ple', True), ('pales', 'pale', True), ('pales', 'bale', False), ('pale', 'bale', True), ('pale', 'bake', False), ('ball', 'balls', True), ('ball', 'ballss', False), ('ball', 'calls', False), ('ball', 'cball', True), ('ball', 'cballss', False), ('ball', 'call', True)] for test in tests: for version in range(1, 4): test_question("version %d => '{}' is {}one way to '{}'" % version, [test[0], '' if test[2] else 'NOT ', test[1]], locals()['version_%d' % version](test)) print()
def question_4(): print('##### Palindrome Permutation #####\n') # time: O(N); space: O(N) # using hash sets def version_1(test): (given, expected) = test odds = set() evens = set() given = given.lower() # O(N) for t in given: c = ord(t) if ord('a') <= c <= ord('z'): if c in odds: odds.remove(c) evens.add(c) elif c in evens: evens.remove(c) odds.add(c) else: # 1st time odds.add(c) return (len(odds) <= 1) == expected # time: O(N); space: O(1) # using bit masks def version_2(test): (given, expected) = test odds = 0 evens = 0 given = given.lower() # O(N) for t in given: c = ord(t) if ord('a') <= c <= ord('z'): vec = 1 << (c - 97) if (odds & vec) == vec: odds = odds ^ vec evens = evens | vec elif (evens & vec) == vec: evens = evens ^ vec odds = odds | vec else: odds = odds | vec num_odds_bits = 0 for i in range(ord('z') - ord('a') + 1): vec = 1 << i if (odds & vec) == vec: num_odds_bits += 1 if num_odds_bits > 1: return False == expected return (num_odds_bits <= 1) == expected tests = [('Tact Coa', True), ('arara', True), ('casa', False), ('', True), ('palindrome', False), ('Madam I\'m Adam', True), ('Madam I am Adam', False), ('coco', True)] for test in tests: for version in range(1, 3): test_question( "version %d => '{}' does {}have palindrome permutation" % version, [test[0], '' if test[1] else 'NOT '], locals()['version_%d' % version](test)) print()
def question_3(): print('##### URLify #####\n') # time: O(length); space: O(N) def version_1(test): chars = list(test[0]) # doesn't count in the O(.) calculation length = test[1] expected = test[2] output = [''] * len(chars) j = 0 for i in range(length): c = chars[i] if c == ' ': output[j] = '%' output[j + 1] = '2' output[j + 2] = '0' j += 3 else: output[j] = c j += 1 chars = ''.join(output) # doesn't count in the O(.) calculation return chars == expected # time: O(length); space: O(1) # replaces ' ' by '%20' in place (assuming it has enough space after the word) def version_2(test): chars = list(test[0]) # doesn't count in the O(.) calculation length = test[1] expected = test[2] i = length - 1 j = len(chars) - 1 while i >= 0: c = chars[i] if c == ' ': chars[j] = '0' chars[j - 1] = '2' chars[j - 2] = '%' j -= 3 else: chars[j] = c j -= 1 i -= 1 chars = chars[j + 1:] chars = ''.join(chars) # doesn't count in the O(.) calculation return chars == expected tests = [('Mr John Smith ', 13, 'Mr%20John%20Smith'), (' Mr John Smith ', 18, '%20Mr%20%20%20John%20Smith%20%20'), (' ', 2, '%20%20'), (' ', 0, ''), ('Mr John Smith ', 15, 'Mr%20%20%20John%20Smith')] for test in tests: for version in range(1, 3): test_question( "version %d => '{}' URLfied first {} chars to '{}'" % version, [test[0], test[1], test[2]], locals()['version_%d' % version](test)) print()
def question_5(): print('##### Sort Stack #####\n') # just use insertion sort # time: O(N^2); space: O(N) def version_1(test): (given, expected) = test original_stack = Stack() sorted_stack = Stack() for g in given: original_stack.push(g) # starts here while not original_stack.is_empty(): pivot = original_stack.pop() while (not sorted_stack.is_empty()) and (pivot < sorted_stack.peek()): original_stack.push(sorted_stack.pop()) sorted_stack.push(pivot) # sorts in reverse order (smallest on top) while not sorted_stack.is_empty(): original_stack.push(sorted_stack.pop()) given_str = ''.join(original_stack.to_array()) # doesn't count in the O(.) calculation return given_str == expected # time: O(N^2); space: O(N) def version_2(test): (given, expected) = test original_stack = Stack() sorted_stack = Stack() for g in given: original_stack.push(g) # starts here num_eltos = original_stack.size for i in range(num_eltos): pivot = original_stack.pop() num_swaps = 0 while (not sorted_stack.is_empty()) and (pivot < sorted_stack.peek()): original_stack.push(sorted_stack.pop()) num_swaps += 1 sorted_stack.push(pivot) for _ in range(num_swaps): sorted_stack.push(original_stack.pop()) # sorts in reverse order (smallest on top) while not sorted_stack.is_empty(): original_stack.push(sorted_stack.pop()) given_str = ''.join(original_stack.to_array()) # doesn't count in the O(.) calculation return given_str == expected tests = [ ('', ''), ('abcdefghijklmnopqrstuvwxyz', 'abcdefghijklmnopqrstuvwxyz'), ('zyxvwutsrqponmlkjihgfedcba', 'abcdefghijklmnopqrstuvwxyz'), ('wqhrgacdzbmsnlvukjfpteixoy', 'abcdefghijklmnopqrstuvwxyz') ] for test in tests: for version in range(1, 3): test_question("version %d => '{}' sorted as '{}'" % version, [test[0], test[1]], locals()['version_%d' % version](test)) print()
def question_8(): print('##### Loop Detection #####\n') # time: O(N); space: O(N) def version_1(test): (given, point, expected) = test (head, tail) = create_linked_list(given) if point: node = head cur = 0 while cur < point: node = node.next cur += 1 tail.next = point = node # begins here visited = set() node = head while node: if node in visited: return True == expected visited.add(node) node = node.next return False == expected # time: O(N); space: O(1) def version_2(test): (given, point, expected) = test (head, tail) = create_linked_list(given) if point: node = head cur = 0 while cur < point: node = node.next cur += 1 tail.next = point = node # begins here node_A = node_B = head while node_A and node_B: if (node_A == node_B) and (node_A != head): return True == expected node_A = node_A.next node_B = node_B.next if node_B: node_B = node_B.next return False == expected tests = [(['A', 'B', 'C', 'D', 'E', 'F'], None, False), (['A', 'B', 'C', 'D', 'E'], 2, True)] for test in tests: for version in range(1, 3): test_question("version %d => {} is {}circular" % version, [test[0], '' if test[2] else 'NOT '], locals()['version_%d' % version](test)) print()