def test_solve(self): """Test solve Args: self: TestReverseLinkedListWithGroupSize Returns: None Raises: None """ # Given elements_list = [1, 5, 7, 9, 15] input_list = LinkedList() for i in range(len(elements_list)): input_list.append(Node(elements_list[i])) reverse_linked_list_problem = ReverseLinkedListWithGroupSize( input_list, 3) # When output_list = reverse_linked_list_problem.solve() # Then self.assertEqual(output_list, [7, 5, 1, 9, 15])
def test_solve(self): """Test solve Args: self: TestSwapNodesInPairs Returns: None Raises: None """ # Given elements_list = [1, 5, 7, 9, 15] input_list = LinkedList() for i in range(len(elements_list)): input_list.append(Node(elements_list[i])) swap_nodes_problem = SwapNodesInPairs(input_list) # When output_list = swap_nodes_problem.solve() # Then self.assertEqual(output_list, [5, 1, 9, 7, 15])
def test_solve_overflow(self): """Test solve (overflow) Args: self: AddTwoNumbers Returns: None Raises: None """ # Given elements_list1 = [2, 4, 3] input_list1 = LinkedList() for i in range(len(elements_list1)): input_list1.append(Node(elements_list1[i])) elements_list2 = [5, 6, 4, 3] input_list2 = LinkedList() for i in range(len(elements_list2)): input_list2.append(Node(elements_list2[i])) add_two_numbers_problem = AddTwoNumbers(input_list1, input_list2) # When total = add_two_numbers_problem.solve() # Then self.assertEqual(total, [3, 8, 0, 7])
def merge_two_sorted_linked_lists(node1, node2): """Merge K Sorted Linked Lists Divide and Conquer Args: node1: First node node2: Second node Returns: Node Raises: None """ merged_list = LinkedList() # iterate over both the lists and append the smallest while node1 is not None and node2 is not None: if node1.data < node2.data: merged_list.append(Node(node1.data)) node1 = node1.next_node else: merged_list.append(Node(node2.data)) node2 = node2.next_node # append the remaining elements from the second list if node1 is None: while node2 is not None: merged_list.append(Node(node2.data)) node2 = node2.next_node # append the remaining elements from the first list if node2 is None: while node1 is not None: merged_list.append(Node(node1.data)) node1 = node1.next_node return merged_list.head
def solve(self): """Solve the problem Note: O(n) (runtime) solution works by simultaneously iterating over both the list and taking the carry to the digit. Args: Returns: list Raises: None """ print("Solving {} problem ...".format(self.PROBLEM_NAME)) node1 = self.input_linked_list1.head node2 = self.input_linked_list2.head carry = 0 sum_list = LinkedList() while node1 is not None and node2 is not None: digit1 = node1.data digit2 = node2.data digit_sum = digit1 + digit2 + carry if digit_sum > 9: carry = 1 else: carry = 0 sum_list.append(Node(digit_sum % 10)) node1 = node1.next_node node2 = node2.next_node node = None if node1 is None and node2 is not None: node = node2 elif node1 is not None and node2 is None: node = node1 while node is not None: digit_sum = node.data + carry if digit_sum > 9: carry = 1 sum_list.append(Node(digit_sum % 10)) node = node.next_node return list(reversed(sum_list.output_list()))
def __init__(self, hash_table_size=DEFAULT_HASH_TABLE_SIZE): """Init Args: hash_table_size: Hash table size Returns: None Raises: None """ super().__init__() self.hash_table_size = hash_table_size self.buckets = [LinkedList() for _ in range(hash_table_size)] self.keys = {}
def test_construct(self): """Test for construct Args: self: TestLinkedList Returns: None Raises: None """ # Given input_linked_list = LinkedList() input_linked_list.append(Node(1)) input_linked_list.append(Node(2)) input_linked_list.append(Node(3)) input_linked_list.append(Node(4)) input_linked_list.append(Node(5)) # Then self.assertEqual(input_linked_list.output_list(), [1, 2, 3, 4, 5])
def test_solve(self): """Test solve Args: self: TestCopyListWithRandomPointer Returns: None Raises: None """ # Given input_linked_list = LinkedList() input_linked_list.append(Node(1)) input_linked_list.append(Node(2)) input_linked_list.append(Node(3)) input_linked_list.append(Node(4)) input_linked_list.append(Node(5)) # 1's random points to 3 input_linked_list.head.random = input_linked_list.head.next_node.next_node # 2's random points to 1 input_linked_list.head.next_node.random = input_linked_list.head # 3's random points to 5 input_linked_list.head.next_node.next_node.random = input_linked_list.head.next_node.next_node.next_node.next_node # 4's random points to 5 input_linked_list.head.next_node.next_node.next_node.random = input_linked_list.head.next_node.next_node.next_node.next_node # 5's random points to 2 input_linked_list.head.next_node.next_node.next_node.next_node.random = input_linked_list.head.next_node copy_list_with_random_pointer_problem = CopyListWithRandomPointer(input_linked_list) # When output_list = copy_list_with_random_pointer_problem.solve() # Then self.assertEqual(output_list, [1, 2, 3, 4, 5])
def solve(self): """Solve the problem Note: O(n) (runtime) and O(1) (space) solution works by: i. Inserting a clone node between two nodes. ii. Updating the random pointer of the cloned nodes. iii. Detaching original and cloned nodes. Args: Returns: list Raises: None """ print("Solving {} problem ...".format(self.PROBLEM_NAME)) # i. Insert cloned node between two nodes for all the nodes current_node = self.input_linked_list.head while current_node is not None: next_node = current_node.next_node new_node = Node(current_node.data) current_node.next_node = new_node new_node.next_node = next_node current_node = next_node # ii. Update the random pointer of the cloned node using the random pointer's clone of the original node. current_node = self.input_linked_list.head while current_node is not None: new_node = current_node.next_node new_node.random = current_node.random.next_node current_node = current_node.next_node.next_node # iii. Detach original and cloned nodes current_node = self.input_linked_list.head cloned_node = current_node.next_node while current_node is not None: tmp = current_node.next_node if current_node.next_node is not None: current_node.next_node = current_node.next_node.next_node current_node = tmp return LinkedList(cloned_node).output_list()
def solve(self): """Solve the problem Note: i. Brute force solution would work by comparing two lists at a time for k times. The total runtime complexity would be O(nk^2) = 2n + 3n + 4n + ... + kn = n(k(k+1)/2 -1). The solution will only require a constant space O(1). ii. Heap has a complexity of O(log k) to order based on the heap property. We could maintain a heap of size k with smallest element from each list. After removing a element from the list, the next element is placed in the heap. With nk elements, the overall runtime complexity is O(nk logk) and a space complexity of O(k). iii. Divide and conquer works by merging two different lists at the same time (begin and end), and finally merging two combined lists. Compared to brute force with k merges O(nk^2), the runtime complexity is O(nk logk) and the space complexity of O(1). Args: Returns: list Raises: None """ print("Solving {} problem ...".format(self.PROBLEM_NAME)) if len(self.input_linked_lists_list) == 0: return [] input_linked_lists_list = [] for k in range(len(self.input_linked_lists_list)): input_linked_lists_list.append( self.input_linked_lists_list[k].head) end = len(self.input_linked_lists_list) - 1 while end > 0: begin = 0 while begin < end: input_linked_lists_list[ begin] = self.merge_two_sorted_linked_lists( input_linked_lists_list[begin], input_linked_lists_list[end]) begin = begin + 1 end = end - 1 return LinkedList(input_linked_lists_list[0]).output_list()
def test_solve(self): """Test solve Args: self: MergeKSortedLinkedListsPriorityQueue Returns: None Raises: None """ # Given elements_list1 = [1, 5, 7, 9, 15, 17] input_list1 = LinkedList() for i in range(len(elements_list1)): input_list1.append(Node(elements_list1[i])) elements_list2 = [2, 3, 3, 6] input_list2 = LinkedList() for i in range(len(elements_list2)): input_list2.append(Node(elements_list2[i])) elements_list3 = [4, 6, 8, 10, 12, 14, 16, 18] input_list3 = LinkedList() for i in range(len(elements_list3)): input_list3.append(Node(elements_list3[i])) input_linked_lists_list = [input_list1, input_list2, input_list3] merge_k_linked_lists_problem = MergeKSortedLinkedListsPriorityQueue(input_linked_lists_list) # When output_list = merge_k_linked_lists_problem.solve() # Then self.assertEqual(output_list, [1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 10, 12, 14, 15, 16, 17, 18])
def test_reverse(self): """Test for reverse Args: self: TestLinkedList Returns: None Raises: None """ # Given input_linked_list = LinkedList() input_linked_list.append(Node(1)) input_linked_list.append(Node(2)) input_linked_list.append(Node(3)) input_linked_list.append(Node(4)) input_linked_list.append(Node(5)) # When input_linked_list.reverse() # Then self.assertEqual(input_linked_list.output_list(), [5, 4, 3, 2, 1])
def solve(self): """Solve the problem Note: O(n) (runtime) and O(1) (space) solution works by iterating over both the linked lists and appending the smallest one to the merged_list. Args: Returns: list Raises: None """ print("Solving {} problem ...".format(self.PROBLEM_NAME)) merged_list = LinkedList() node1 = self.input_linked_list1.head node2 = self.input_linked_list2.head # iterate over both the lists and append the smallest while node1 is not None and node2 is not None: if node1.data < node2.data: merged_list.append(Node(node1.data)) node1 = node1.next_node else: merged_list.append(Node(node2.data)) node2 = node2.next_node # append the remaining elements from the second list if node1 is None: while node2 is not None: merged_list.append(Node(node2.data)) node2 = node2.next_node # append the remaining elements from the first list if node2 is None: while node1 is not None: merged_list.append(Node(node1.data)) node1 = node1.next_node return merged_list.output_list()