├── .gitignore
├── .idea
├── .gitignore
├── algoexpert.iml
├── dictionaries
│ └── josancamon19.xml
├── inspectionProfiles
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── 1.0. two-number-sum.py
├── 1.1. closest-bst-value.py
├── 1.2. bst-construction.py
├── 1.3. is_palindrome.py
├── 1.4. doubly- linked-list-construction.py
├── 1.5. fibonacci.py
├── 1.6. binary_search.py
├── 1.7. depth-first-search.py
├── 1.8. product-sum.py
├── 1.9. three-largest-sum.py
├── 2.0. bubble-sort.py
├── 2.1. bst-traversal.py
├── 2.2. breadth-first-search.py
├── 2.3. insertion-sort.py
├── 2.4. validate-bst.py
├── 2.5. selection-sort.py
├── 2.6. caesar-cipher-encryptor.py
├── 2.7. permutations.py
├── 2.8. smallest-difference.py
├── 2.9. three-number-sum.py
├── 3.0. merge-sort.py
├── 3.1. quicksort.py
├── 3.2. suffix-tree-construction.py
├── 3.3. reverse-linked-list.py
├── 3.4. shifted-binary-search.py
├── 3.5. balanced-brackets.py
├── 3.6. validate-bst.py
├── 3.7. powerset.py
├── 3.8. min-max-stack.py
└── 3.9. longest-palindromic-substring.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Project exclude paths
2 | /venv/
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /workspace.xml
--------------------------------------------------------------------------------
/.idea/algoexpert.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/dictionaries/josancamon19.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | algo
5 | encryptor
6 | logn
7 | nlogn
8 | powerset
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/1.0. two-number-sum.py:
--------------------------------------------------------------------------------
1 | def two_number_sum(array, target_sum):
2 | for n in array:
3 | residual = target_sum - n
4 | if residual in array and residual != n:
5 | return sorted([residual, n])
6 | return []
7 |
8 |
9 | if __name__ == '__main__':
10 | print(two_number_sum([3, 5, -4, 8, 11, 1, -1, 6], 10))
11 |
--------------------------------------------------------------------------------
/1.1. closest-bst-value.py:
--------------------------------------------------------------------------------
1 | def findClosestValueInBst(tree, target):
2 | closest_value = float('inf')
3 | node = tree
4 | while node:
5 | if abs(target - closest_value) > abs(target - node.value):
6 | closest_value = node.value
7 |
8 | if node.value > target:
9 | if node.left is None:
10 | return closest_value
11 | node = node.left
12 |
13 | elif node.value < target:
14 | if node.right is None:
15 | return closest_value
16 | node = node.right
17 |
18 | else:
19 | return node.value
20 |
--------------------------------------------------------------------------------
/1.2. bst-construction.py:
--------------------------------------------------------------------------------
1 | def traverse_list(node):
2 | visit_order = list()
3 | if node:
4 | visit_order.append(node.value)
5 | visit_order += traverse_list(node.left)
6 | visit_order += traverse_list(node.right)
7 | return visit_order
8 |
9 |
10 | def traverse(node):
11 | visit_order = list()
12 | if node:
13 | visit_order.append(node)
14 | visit_order += traverse(node.left)
15 | visit_order += traverse(node.right)
16 | return visit_order
17 |
18 |
19 | def get_min_node_value(node):
20 | while node.left:
21 | node = node.left
22 | return node.value
23 |
24 |
25 | class BST:
26 | def __init__(self, value):
27 | self.value = value
28 | self.left = None
29 | self.right = None
30 |
31 | def compare(self, target):
32 | if self.value > target:
33 | return -1
34 | elif self.value < target:
35 | return 1
36 | else:
37 | return 0
38 |
39 | def insert(self, value):
40 |
41 | node = self
42 | while True:
43 | comparision = node.compare(value)
44 | if comparision == -1:
45 | if node.left:
46 | node = node.left
47 | else:
48 | node.left = BST(value)
49 | break
50 | else: # comparision == 1 or equals
51 | if node.right:
52 | node = node.right
53 | else:
54 | node.right = BST(value)
55 | break
56 |
57 | return self
58 |
59 | def contains(self, value):
60 | node = self
61 | while node:
62 | comparision = node.compare(value)
63 | if comparision == -1:
64 | node = node.left
65 | elif comparision == 1:
66 | node = node.right
67 | else:
68 | return True
69 |
70 | return False
71 |
72 | def remove(self, value, parent_node=None):
73 | node = self
74 | while True:
75 | comparision = node.compare(value)
76 | if comparision == -1:
77 | if node.left:
78 | parent_node = node
79 | node = node.left
80 | else:
81 | print('Value not found')
82 | break
83 | elif comparision == 1:
84 | if node.right:
85 | parent_node = node
86 | node = node.right
87 | else:
88 | print('Value not found')
89 | break
90 | else:
91 | if node.left and node.right: # node with left and child
92 | node.value = get_min_node_value(node.right)
93 | node.right.remove(node.value, node)
94 | elif parent_node is None: # parent node
95 | if node.left:
96 | node.value = node.left.value
97 | node.right = node.left.right
98 | node.left = node.left.left
99 | elif node.right:
100 | node.value = node.right.value
101 | node.left = node.right.left
102 | node.right = node.right.right
103 | else: # parent node with no children
104 | node.value = None
105 |
106 | elif parent_node.left == node: # found in the left node with right None
107 | parent_node.left = node.left if node.left else node.right
108 | elif parent_node.right == node: # found in the right node with left None
109 | parent_node.right = node.left if node.left else node.right
110 | break
111 |
112 | return self
113 |
114 |
115 | if __name__ == '__main__':
116 | # tree = BST(10)
117 | # tree.insert(5)
118 | # tree.insert(8)
119 | # tree.insert(3)
120 | # tree.insert(4)
121 | # tree.insert(1)
122 | # tree.insert(2)
123 | # tree.insert(0)
124 | # print(traverse_list(tree))
125 | #
126 | # tree.remove(5)
127 | # print(traverse_list(tree))
128 | test = BST(10).insert(5).insert(7).insert(2).remove(10)
129 | print(traverse_list(test))
130 |
--------------------------------------------------------------------------------
/1.3. is_palindrome.py:
--------------------------------------------------------------------------------
1 | def is_palindrome(string):
2 | # Write your code here.
3 | for i in range(len(string) // 2):
4 | if string[i] != string[len(string) - 1 - i]:
5 | return False
6 | return True
7 |
--------------------------------------------------------------------------------
/1.4. doubly- linked-list-construction.py:
--------------------------------------------------------------------------------
1 | # Feel free to add new properties and methods to the class.
2 | # noinspection PyPep8Naming
3 | class Node:
4 | def __init__(self, value):
5 | self.value = value
6 | self.next = None
7 | self.prev = None
8 |
9 | def __repr__(self):
10 | return str(self.value)
11 |
12 | def get_prev_value(self):
13 | if self.prev is None:
14 | return 'None'
15 | return str(self.prev.value)
16 |
17 | def get_next_value(self):
18 | if self.next is None:
19 | return 'None'
20 | return str(self.next.value)
21 |
22 | def __str__(self):
23 | return 'Node(prev:' + self.get_prev_value() + ', this:' + str(
24 | self.value) + ', next:' + self.get_next_value() + ')'
25 |
26 | def __eq__(self, other):
27 | if other:
28 | return self.value == other.value
29 | return self is None
30 |
31 |
32 | # noinspection PyPep8Naming
33 | class DoublyLinkedList:
34 | def __init__(self):
35 | self.head = None
36 | self.tail = None
37 |
38 | def setHead(self, node):
39 | # Write your code here.
40 | if self.head is None:
41 | self.head = node
42 | self.tail = node
43 | return
44 |
45 | self.insertBefore(self.head, node)
46 |
47 | def setTail(self, node):
48 | # Write your code here.
49 |
50 | if self.tail is None:
51 | self.setHead(node)
52 | return
53 |
54 | self.insertAfter(self.tail, node)
55 |
56 | def append(self, node):
57 | if self.head is None:
58 | self.setHead(node)
59 | return
60 |
61 | current = self.head
62 | while current.next is not None:
63 | current = current.next
64 |
65 | node.prev = current
66 | current.next = node
67 |
68 | def insertBefore(self, node, nodeToInsert):
69 | # Write your code here.
70 | if nodeToInsert == self.head and nodeToInsert == self.tail:
71 | return
72 |
73 | nodeToInsert.prev = node.prev
74 | nodeToInsert.next = node
75 |
76 | if node.prev is None:
77 | self.head = nodeToInsert
78 | else:
79 | node.prev.next = nodeToInsert
80 | node.prev = nodeToInsert
81 |
82 | def insertAfter(self, node, nodeToInsert):
83 | # Write your code here.
84 | if nodeToInsert == self.head and nodeToInsert == self.tail:
85 | return
86 |
87 | nodeToInsert.prev = node
88 | nodeToInsert.next = node.next
89 |
90 | if node.next is None:
91 | self.tail = nodeToInsert
92 | else:
93 | node.next.prev = nodeToInsert
94 |
95 | node.next = nodeToInsert
96 |
97 | def insertAtPosition(self, position, nodeToInsert):
98 | # Write your code here.
99 | if position == 1:
100 | self.setHead(nodeToInsert)
101 | return
102 | current = self.head
103 | index = 1
104 | while current and position != index:
105 | index += 1
106 | current = current.next
107 |
108 | if current is None:
109 | self.setTail(nodeToInsert)
110 | else:
111 | self.insertBefore(current, nodeToInsert)
112 |
113 | def removeNodesWithValue(self, value):
114 | # Write your code here.
115 | current = self.head
116 | while current:
117 | nxt = current.next
118 | if current.value == value:
119 | self.remove(current)
120 |
121 | current = nxt
122 |
123 | def remove(self, node):
124 | # Write your code here.
125 |
126 | if node == self.head:
127 | self.head = self.head.next
128 |
129 | if node == self.tail:
130 | self.tail = self.tail.prev
131 |
132 | self.removeNode(node)
133 |
134 | def removeNode(self, node):
135 | if node.next:
136 | node.next.prev = node.prev
137 | if node.prev:
138 | node.prev.next = node.next
139 |
140 | del node
141 |
142 | def containsNodeWithValue(self, value):
143 | # Write your code here.
144 |
145 | current = self.head
146 | while current:
147 | if current.value == value:
148 | return True
149 | current = current.next
150 | return False
151 |
152 | def __repr__(self):
153 |
154 | if self.head is None:
155 | return '------'
156 |
157 | statement = ''
158 | current = self.head
159 | while current:
160 | statement += str(current)
161 | current = current.next
162 | if current:
163 | statement += ' ---> '
164 |
165 | return statement + ''
166 |
167 | # Initial Wrong solution
168 | # class DoublyLinkedList:
169 | # def __init__(self):
170 | # self.head = None
171 | # self.tail = None
172 | #
173 | # def setHead(self, node):
174 | # # Write your code here.
175 | #
176 | # if self.head is not None:
177 | # self.head.prev = node
178 | #
179 | # node.next = self.head
180 | # self.head = node
181 | #
182 | # def setTail(self, node):
183 | # # Write your code here.
184 | #
185 | # if self.head is None:
186 | # self.head = node
187 | #
188 | # if self.tail is not None:
189 | # self.tail.next = node
190 | #
191 | # node.prev = self.tail
192 | # self.tail = node
193 | # return self.head
194 | #
195 | # def append(self, node):
196 | # if self.head is None:
197 | # self.setHead(node)
198 | # return
199 | #
200 | # current = self.head
201 | # while current.next is not None:
202 | # current = current.next
203 | #
204 | # node.prev = current
205 | # current.next = node
206 | #
207 | # def insertBefore(self, node, nodeToInsert):
208 | # # Write your code here.
209 | # if node == self.head:
210 | # self.setHead(nodeToInsert)
211 | # return
212 | #
213 | # current = self.head
214 | # while current.next:
215 | # if current.next == node:
216 | # nodeToInsert.prev = current
217 | # nodeToInsert.next = current.next
218 | #
219 | # current.next.prev = nodeToInsert
220 | # current.next = nodeToInsert
221 | # break
222 | # current = current.next
223 | #
224 | # def insertAfter(self, node, nodeToInsert):
225 | # # Write your code here.
226 | # current = self.head
227 | # while current.next:
228 | # if current.next == node:
229 | # nodeToInsert.prev = current.next
230 | # nodeToInsert.next = current.next.next
231 | #
232 | # if current.next.next:
233 | # current.next.next.prev = nodeToInsert
234 | # current.next.next = nodeToInsert
235 | # break
236 | # current = current.next
237 | #
238 | # def insertAtPosition(self, position, nodeToInsert):
239 | # # Write your code here.
240 | # if position == 1:
241 | # self.setHead(nodeToInsert)
242 | # return
243 | # current = self.head
244 | # index = 1
245 | # while current:
246 | # if position == index + 1:
247 | # nodeToInsert.prev = current
248 | # nodeToInsert.next = current.next
249 | # if current.next:
250 | # current.next.prev = nodeToInsert
251 | # current.next = nodeToInsert
252 | # break
253 | # index += 1
254 | # current = current.next
255 | #
256 | # def removeNodesWithValue(self, value):
257 | # # Write your code here.
258 | # current = self.head
259 | # while current:
260 | # if current.value == value:
261 | # if current.prev:
262 | # current.prev.next = current.next
263 | # if current.next:
264 | # current.next.prev = current.prev
265 | #
266 | # current = current.next
267 | #
268 | # def remove(self, node):
269 | # # Write your code here.
270 | # current = self.head
271 | # while current:
272 | # if current == node:
273 | # if current.prev:
274 | # current.prev.next = current.next
275 | # if current.next:
276 | # current.next.prev = current.prev
277 | # break
278 | #
279 | # current = current.next
280 | #
281 | # def containsNodeWithValue(self, value):
282 | # # Write your code here.
283 | # if self.head is None:
284 | # return False
285 | #
286 | # current = self.head
287 | # while current:
288 | # if current.value == value:
289 | # return True
290 | # current = current.next
291 | # return False
292 | #
293 | # def __repr__(self):
294 | # if self.head is None:
295 | # return '------'
296 | #
297 | # statement = ''
298 | # current = self.head
299 | # while current:
300 | # statement += str(current)
301 | # current = current.next
302 | # if current:
303 | # statement += ' ---> '
304 | #
305 | # return statement + ''
306 | #
307 | #
308 | # if __name__ == '__main__':
309 | # doubly = DoublyLinkedList()
310 | #
311 | # doubly.append(Node(1))
312 | # doubly.append(Node(2))
313 | # doubly.append(Node(4))
314 | # # print(doubly)
315 | #
316 | # doubly.insertBefore(Node(4), Node(3))
317 | # # print(doubly)
318 | #
319 | # doubly.insertAfter(Node(4), Node(5))
320 | # # print(doubly)
321 | #
322 | # doubly.remove(Node(3))
323 | # # print(doubly)
324 | #
325 | # doubly.append(Node(2))
326 | # doubly.append(Node(2))
327 | # # print(doubly)
328 | #
329 | # doubly.removeNodesWithValue(2)
330 | # print(doubly)
331 | #
332 | # doubly.insertAtPosition(2, Node(2))
333 | # print(doubly)
334 | #
335 | # doubly.insertAtPosition(3, Node(3))
336 | # print(doubly)
337 | #
338 | # doubly.insertAtPosition(6, Node(6))
339 | # print(doubly)
340 | #
341 | # doubly.insertAtPosition(2, Node(1.5))
342 | # print(doubly)
343 |
--------------------------------------------------------------------------------
/1.5. fibonacci.py:
--------------------------------------------------------------------------------
1 | def get_fib(n):
2 | # Write your code here.
3 | if n == 1:
4 | return 0
5 | if n == 2:
6 | return 1
7 |
8 | return get_fib(n - 2) + get_fib(n - 1)
9 |
10 |
11 | if __name__ == '__main__':
12 | print(get_fib(6))
13 |
--------------------------------------------------------------------------------
/1.6. binary_search.py:
--------------------------------------------------------------------------------
1 | def binarySearch(array, target):
2 | # Write your code here.
3 | first = 0
4 | last = len(array) - 1
5 | while True:
6 |
7 | mid_idx = (last + first) // 2
8 | mid_element = array[mid_idx]
9 |
10 | if mid_element == target:
11 | return mid_idx
12 | elif first == last or first > last:
13 | return -1
14 | elif mid_element > target:
15 | last = mid_idx
16 | else: # mid_element < target
17 | first = mid_idx + 1
18 |
19 |
20 | if __name__ == '__main__':
21 | a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
22 | print(binarySearch(a, 5))
23 |
--------------------------------------------------------------------------------
/1.7. depth-first-search.py:
--------------------------------------------------------------------------------
1 | class Node:
2 | def __init__(self, name):
3 | self.children = []
4 | self.name = name
5 |
6 | def __repr__(self):
7 | return str(self.name)
8 |
9 | def addChild(self, name):
10 | self.children.append(Node(name))
11 | return self
12 |
13 | def depthFirstSearch(self, array):
14 | array.append(self.name)
15 | for n in self.children:
16 | n.depthFirstSearch(array)
17 | return array
18 |
19 |
20 | if __name__ == '__main__':
21 | root = Node('A')
22 |
23 | root.addChild('B')
24 | root.addChild('C')
25 | root.addChild('D')
26 |
27 | # append to B node E and F
28 | root.children[0].addChild('E')
29 | root.children[0].addChild('F')
30 |
31 | # append to D node G and H
32 | root.children[2].addChild('G')
33 | root.children[2].addChild('H')
34 |
35 | # append to F node I and J
36 | root.children[0].children[1].addChild('I')
37 | root.children[0].children[1].addChild('J')
38 |
39 | # append K to G node
40 | root.children[2].children[0].addChild('K')
41 |
42 | print(root.depthFirstSearch([]))
43 |
--------------------------------------------------------------------------------
/1.8. product-sum.py:
--------------------------------------------------------------------------------
1 | def productSum(array):
2 | # Write your code here.
3 | return product_sum_with_depth(array)
4 |
5 |
6 | def product_sum_with_depth(array, depth=1):
7 | to_add = 0
8 | for item in array:
9 | if type(item) is list:
10 | to_add += (depth + 1) * product_sum_with_depth(item, depth + 1)
11 | else:
12 | to_add += item
13 | return to_add
14 |
15 |
16 | if __name__ == '__main__':
17 | print(productSum([5, 2, [7, -1], 3, [6, [-13, 8], 4]]))
18 | # print(productSum([6, [-13, 8], 4]))
19 |
--------------------------------------------------------------------------------
/1.9. three-largest-sum.py:
--------------------------------------------------------------------------------
1 | # def findThreeLargestNumbers(array):
2 | # # Write your code here.
3 | # return sorted(array)[-3:] # sorted -> O(logn)
4 | #
5 | # find_three_largest = lambda array: sorted(array)[-3:]
6 |
7 |
8 | # def findThreeLargestNumbers(array):
9 | # # Write your code here.
10 | # result = array[:3]
11 | # for n in array[3:]:
12 | # min_result = min(result)
13 | # if n > min_result:
14 | # result[result.index(min_result)] = n
15 | #
16 | # return sorted(result)
17 |
18 |
19 | # This solution works for n largest len of result
20 | def findThreeLargestNumbers(array):
21 | # Write your code here.
22 | result = [None for _ in range(3)]
23 | for number in array:
24 | for i in range(len(result)):
25 | idx = len(result) - 1 - i
26 | print(number, result)
27 | if result[idx] is None:
28 | result[idx] = number
29 | break
30 | elif result[idx] < number:
31 | this = result[idx]
32 | if idx > 0:
33 | # TODO here go idx --- 0 and swapping nodes throwing 0
34 | result[idx - 1] = result[idx]
35 | result[idx] = number
36 | break
37 |
38 | return result
39 |
40 |
41 | if __name__ == '__main__':
42 | print(findThreeLargestNumbers([141, 1, 17, -7, -17, -27, 18, 541, 8, 7, 7]))
43 | # print(findThreeLargestNumbers([1, 2, 3, 4]))
44 |
--------------------------------------------------------------------------------
/2.0. bubble-sort.py:
--------------------------------------------------------------------------------
1 | def bubbleSort(array):
2 | # Write your code here.
3 | for i in range(len(array) - 1):
4 | for j in range(len(array) - 1):
5 | if array[j] > array[j + 1]:
6 | array[j], array[j + 1] = array[j + 1], array[j]
7 | return array
8 |
9 |
10 | if __name__ == '__main__':
11 | print(bubbleSort([4, 3, 2, 1]))
12 | # print(bubbleSort([8, 5, 2, 9, 5, 6, 3]))
13 |
--------------------------------------------------------------------------------
/2.1. bst-traversal.py:
--------------------------------------------------------------------------------
1 | def inOrderTraverse(tree, array):
2 | # Write your code here.
3 | if tree:
4 | inOrderTraverse(tree.left, array)
5 | array.append(tree.value)
6 | inOrderTraverse(tree.right, array)
7 | return array
8 |
9 |
10 | def preOrderTraverse(tree, array):
11 | # Write your code here.
12 | if tree:
13 | array.append(tree.value)
14 | preOrderTraverse(tree.left, array)
15 | preOrderTraverse(tree.right, array)
16 | return array
17 |
18 |
19 | def postOrderTraverse(tree, array):
20 | # Write your code here.
21 | if tree:
22 | postOrderTraverse(tree.left, array)
23 | postOrderTraverse(tree.right, array)
24 | array.append(tree.value)
25 | return array
26 |
--------------------------------------------------------------------------------
/2.2. breadth-first-search.py:
--------------------------------------------------------------------------------
1 | class Node:
2 | def __init__(self, name):
3 | self.children = []
4 | self.name = name
5 |
6 | def addChild(self, name):
7 | self.children.append(Node(name))
8 | return self
9 |
10 | def breadthFirstSearch(self, array):
11 | queue = [self]
12 | while len(queue) > 0:
13 | node = queue.pop(-1)
14 | array.append(node.name)
15 | for child in node.children:
16 | queue.insert(0, child)
17 |
18 | return array
19 |
20 |
21 | if __name__ == '__main__':
22 | test1 = Node('A').addChild('B').addChild('C').addChild('D')
23 | test1.children[0].addChild('E').addChild('F')
24 | test1.children[2].addChild('G').addChild('H')
25 | test1.children[0].children[1].addChild('I').addChild('J')
26 | test1.children[2].children[0].addChild('K')
27 |
28 | print(test1.breadthFirstSearch([]))
29 |
--------------------------------------------------------------------------------
/2.3. insertion-sort.py:
--------------------------------------------------------------------------------
1 | # def insertionSort(array):
2 | # for i in range(0, len(array) - 1):
3 | # this_idx = i
4 | # next_idx = i + 1
5 | #
6 | # while this_idx >= 0 and array[next_idx] < array[this_idx]: # is next less than this
7 | # array[this_idx], array[next_idx] = array[next_idx], array[this_idx]
8 | # next_idx -= 1
9 | # this_idx -= 1
10 | # return array
11 |
12 | def insertionSort(array):
13 | for i in range(0, len(array) - 1):
14 | while i >= 0 and array[i + 1] < array[i]: # is next less than this
15 | array[i], array[i + 1] = array[i + 1], array[i]
16 | i -= 1
17 | return array
18 |
19 |
20 | if __name__ == '__main__':
21 | print(insertionSort([3, 2, 1, 0]))
22 |
--------------------------------------------------------------------------------
/2.4. validate-bst.py:
--------------------------------------------------------------------------------
1 | def compare(node_value, target):
2 | if node_value > target:
3 | return -1
4 | elif node_value < target:
5 | return 1
6 | else:
7 | return 0
8 |
9 |
10 | def validateBst(node):
11 | # Write your code here.
12 | if (node.left is None or node.value > node.left.value) and (node.right is None or node.value <= node.right.value):
13 | return validateBst()
--------------------------------------------------------------------------------
/2.5. selection-sort.py:
--------------------------------------------------------------------------------
1 | def get_min(array):
2 | # print('Array to get min:', array)
3 | min_element = None
4 | for idx, value in enumerate(array):
5 | if min_element is None or value < min_element[1]:
6 | min_element = idx, value
7 |
8 | # print('Getting min element', min_element)
9 | return min_element[0]
10 |
11 |
12 | def selectionSort(array):
13 | # Write your code here.
14 | for i in range(len(array)):
15 | min_idx = get_min(array[i:]) + i
16 | # print(array[i], array[min_idx], array)
17 | array[i], array[min_idx] = array[min_idx], array[i]
18 |
19 | return array
20 |
21 |
22 | if __name__ == '__main__':
23 | print(selectionSort([3, 2, 1, 0]))
24 |
--------------------------------------------------------------------------------
/2.6. caesar-cipher-encryptor.py:
--------------------------------------------------------------------------------
1 | def encode_char(char, key):
2 | # [ 97 - 122 ] --> [ a - z ]
3 | return str(chr(97 + (((ord(char) + key) - 97) % 26)))
4 |
5 |
6 | def caesarCipherEncryptor(string, key):
7 | # Write your code here.
8 | return ''.join([encode_char(char, key) for char in string])
9 |
10 |
11 | if __name__ == '__main__':
12 | print(caesarCipherEncryptor('abc', 52))
13 |
--------------------------------------------------------------------------------
/2.7. permutations.py:
--------------------------------------------------------------------------------
1 |
2 | def getPermutations(array):
3 | if len(array) == 0:
4 | return []
5 | elif len(array) == 1:
6 | return [array]
7 | permutations = []
8 |
9 | for i in range(len(array)):
10 | array.insert(0, array.pop(i))
11 | for perm in getPermutations(array[1:]):
12 | perm.insert(0, array[0])
13 | permutations.append(perm)
14 |
15 | return permutations
16 |
17 |
18 | if __name__ == '__main__':
19 | print(getPermutations([1, 2, 3, 4]))
20 |
--------------------------------------------------------------------------------
/2.8. smallest-difference.py:
--------------------------------------------------------------------------------
1 | # def smallestDifference(arrayOne, arrayTwo): # O(n2)
2 | # # Write your code here.
3 | # smallest = [float('inf'), float('-inf')]
4 | # for one in arrayOne:
5 | # for two in arrayTwo:
6 | # if abs(smallest[0] - smallest[1]) > abs(one - two):
7 | # smallest = [one, two]
8 | # return smallest
9 |
10 | def smallestDifference(arrayOne, arrayTwo):
11 | # Write your code here.
12 | arrayOne.sort()
13 | arrayTwo.sort()
14 |
15 | smallest = [float('inf'), float('-inf')]
16 | first_idx = 0
17 | second_idx = 0
18 | while True:
19 | first = arrayOne[first_idx]
20 | second = arrayTwo[second_idx]
21 | expected = abs(first - second)
22 |
23 | if abs(smallest[0] - smallest[1]) > expected:
24 | smallest = [first, second]
25 |
26 | if first == second:
27 | break
28 | elif first < second:
29 | if first_idx + 1 < len(arrayOne):
30 | first_idx += 1
31 | else:
32 | break
33 | else: # first > second
34 | if second_idx + 1 < len(arrayTwo):
35 | second_idx += 1
36 | else:
37 | break
38 |
39 | return smallest
40 |
41 |
42 | if __name__ == '__main__':
43 | smallestDifference([1, 2, 3, 4], [3, 2, 1])
44 |
--------------------------------------------------------------------------------
/2.9. three-number-sum.py:
--------------------------------------------------------------------------------
1 | def threeNumberSum(array, targetSum):
2 | array.sort() # nlogn
3 | results = []
4 | for current in range(len(array)):
5 | left = current + 1
6 | right = len(array) - 1
7 | while left < right:
8 | result = array[current] + array[left] + array[right]
9 | if result == targetSum:
10 | results.append([array[current], array[left], array[right]])
11 | left += 1
12 | right -= 1
13 | elif result < targetSum:
14 | left += 1
15 | else:
16 | right -= 1
17 | return results
18 |
19 |
20 | if __name__ == '__main__':
21 | print(threeNumberSum([12, 3, 1, 2, -6, 5, -8, 6], 0))
22 | print(threeNumberSum([1, 2, 3, 4, 5, 6, 7, 8, 9, 15], 33))
23 | print(threeNumberSum([1], 10))
24 | print(threeNumberSum([1, 2, 3, 7, 0], 10))
25 |
--------------------------------------------------------------------------------
/3.0. merge-sort.py:
--------------------------------------------------------------------------------
1 | def mergeSort(array):
2 | for i, item in enumerate(array):
3 | array[i] = [item]
4 |
5 | print(array)
6 |
7 |
8 | def divide_array(array):
9 | pass
10 |
11 |
12 | def sort_pair_arrays(array1, array2):
13 | if array1 is None or len(array1) == 0:
14 | return array2
15 | if array2 is None or len(array2) == 0:
16 | return array1
17 |
18 | new_array = []
19 | first_idx, second_idx = 0, 0
20 | while first_idx < len(array1) or second_idx < len(array2):
21 |
22 | if first_idx >= len(array1):
23 | new_array += array2[second_idx:]
24 | break
25 |
26 | if second_idx >= len(array2):
27 | new_array += array1[first_idx:]
28 | break
29 |
30 | first = array1[first_idx]
31 | second = array2[second_idx]
32 |
33 | if first <= second:
34 | new_array.append(first)
35 | first_idx += 1
36 | elif second < first:
37 | new_array.append(second)
38 | second_idx += 1
39 |
40 | return new_array
41 |
42 |
43 | if __name__ == '__main__':
44 | print(mergeSort([8, 2, 5, 9, 5, 6, 3]))
45 | # print(sort_pair_arrays([1], [2]))
46 |
--------------------------------------------------------------------------------
/3.1. quicksort.py:
--------------------------------------------------------------------------------
1 | # def quickSort(arr):
2 | # if len(arr) <= 1:
3 | # return arr
4 | #
5 | # def sort(array, pivot_idx, right_idx):
6 | # left_idx = pivot_idx + 1
7 | # while right_idx >= left_idx:
8 | # pivot = array[pivot_idx]
9 | # left = array[left_idx]
10 | # right = array[right_idx]
11 | #
12 | # if left > pivot > right:
13 | # swap(array, left_idx, right_idx)
14 | # if left <= pivot:
15 | # left_idx += 1
16 | # if right >= pivot:
17 | # right_idx -= 1
18 | #
19 | # # print(left_idx, right_idx, array)
20 | # swap(array, pivot_idx, right_idx)
21 | # # print(array)
22 | # # now right idx is ok lets do the same for array[:right_idx] and array[right_idx + 1:]
23 | # return quickSort(array[:right_idx]) + [array[right_idx]] + quickSort(array[right_idx + 1:])
24 | #
25 | # # print('------')
26 | # return sort(arr, 0, len(arr) - 1)
27 |
28 | def quickSort(arr):
29 | sort_last_as_pivot(arr, 0, len(arr) - 1)
30 | return arr
31 |
32 |
33 | def sort_first_as_pivot(array, start_idx, end_idx): # sort using the first index as pivot
34 | if start_idx >= end_idx:
35 | return
36 |
37 | pivot_idx = start_idx
38 | left_idx = pivot_idx + 1
39 | right_idx = end_idx
40 |
41 | while right_idx >= left_idx:
42 | pivot = array[pivot_idx]
43 | left = array[left_idx]
44 | right = array[right_idx]
45 |
46 | if left > pivot > right:
47 | swap(array, left_idx, right_idx)
48 | if left <= pivot:
49 | left_idx += 1
50 | if right >= pivot:
51 | right_idx -= 1
52 |
53 | swap(array, pivot_idx, right_idx)
54 |
55 | # print(pivot_idx, start_idx, left_idx, right_idx, end_idx)
56 | left_smaller = right_idx - 1 - start_idx < end_idx - (right_idx + 1)
57 | if left_smaller:
58 | sort_first_as_pivot(array, start_idx, right_idx - 1)
59 | sort_first_as_pivot(array, right_idx + 1, end_idx)
60 | else:
61 | sort_first_as_pivot(array, right_idx + 1, end_idx)
62 | sort_first_as_pivot(array, start_idx, right_idx - 1)
63 |
64 |
65 | def sort_last_as_pivot(array, start_idx, end_idx): # sort using the last index as pivot
66 | if start_idx >= end_idx:
67 | return
68 |
69 | pivot_idx = end_idx
70 | left_idx = start_idx
71 | right_idx = pivot_idx - 1
72 |
73 | while right_idx >= left_idx:
74 | pivot = array[pivot_idx]
75 | left = array[left_idx]
76 | right = array[right_idx]
77 |
78 | if left > pivot > right:
79 | swap(array, left_idx, right_idx)
80 | if left <= pivot:
81 | left_idx += 1
82 | if right >= pivot:
83 | right_idx -= 1
84 |
85 | swap(array, pivot_idx, left_idx)
86 |
87 | # print(array)
88 |
89 | left_smaller = right_idx - 1 - start_idx < end_idx - (right_idx + 1)
90 | if left_smaller:
91 | sort_last_as_pivot(array, start_idx, left_idx - 1)
92 | sort_last_as_pivot(array, left_idx + 1, end_idx)
93 | else:
94 | sort_last_as_pivot(array, left_idx + 1, end_idx)
95 | sort_last_as_pivot(array, start_idx, left_idx - 1)
96 |
97 |
98 | def swap(array, i, j):
99 | array[i], array[j] = array[j], array[i]
100 |
101 |
102 | if __name__ == '__main__':
103 | # print(quickSort([-2, 3, 2, 4, - 1, 1, 0, -1, 9, -10]))
104 | print(quickSort([-1, 8, 5, 2, 9, 5, 6, 3]))
105 |
--------------------------------------------------------------------------------
/3.2. suffix-tree-construction.py:
--------------------------------------------------------------------------------
1 | # Do not edit the class below except for the
2 | # populateSuffixTrieFrom and contains methods.
3 | # Feel free to add new properties and methods
4 | # to the class.
5 |
6 | # AlgoExpert solution is too inefficient
7 | # I think this one is better
8 | class SuffixTrie:
9 | def __init__(self, string):
10 | self.root = {}
11 | self.endSymbol = "*"
12 | self.populateSuffixTrieFrom(string)
13 |
14 | def populateSuffixTrieFrom(self, string):
15 | # Write your code here.
16 | node = self.root
17 | for char in string:
18 | if char not in node:
19 | node[char] = {}
20 | node = node[char]
21 | node["*"] = True
22 |
23 | def contains(self, string):
24 | # Write your code here.
25 | node = self.root
26 | for char in string:
27 | if char not in node:
28 | return False
29 | node = node[char]
30 |
31 | # print(node)
32 | return '*' in node
33 |
34 | def get_prefix_node(self, prefix):
35 | # Write your code here.
36 | node = self.root
37 | for char in prefix:
38 | if char not in node:
39 | return None
40 | node = node[char]
41 |
42 | return node
43 |
44 | def get_suffixes(self, prefix):
45 | node = self.get_prefix_node(prefix)
46 | return suffixes_from_node(node, '')
47 |
48 |
49 | def suffixes_from_node(node, previous):
50 | results = []
51 | for key, child in node.items():
52 | if type(child) == dict:
53 | if '*' in child:
54 | results.append(previous + key)
55 | results += suffixes_from_node(child, previous + key)
56 | return results
57 |
58 |
59 | if __name__ == '__main__':
60 | test1 = SuffixTrie('test')
61 | test1.populateSuffixTrieFrom('test2')
62 | test1.populateSuffixTrieFrom('testsito')
63 | print(test1.get_suffixes('te'))
64 |
--------------------------------------------------------------------------------
/3.3. reverse-linked-list.py:
--------------------------------------------------------------------------------
1 | def reverseLinkedList(head):
2 | # Write your code here.
3 | previous = None
4 | current = head
5 | while current:
6 | nxt = current.next
7 | current.next = previous
8 | previous = current
9 | if nxt is None:
10 | break
11 | current = nxt
12 | return current
13 |
--------------------------------------------------------------------------------
/3.4. shifted-binary-search.py:
--------------------------------------------------------------------------------
1 | def shiftedBinarySearch(array, target):
2 | # Write your code here.
3 | pivot = find_pivot(array, 0, len(array) - 1)
4 | if target == array[pivot]:
5 | return pivot
6 | elif target < array[0]:
7 | array = array[pivot + 1:]
8 | idx = binary_search(array, 0, len(array) - 1, target)
9 | if idx != -1:
10 | idx += pivot + 1
11 | return idx
12 | array = array[: pivot]
13 | return binary_search(array, 0, len(array) - 1, target)
14 |
15 |
16 | def find_pivot(array, left_idx, right_idx):
17 | mid_idx = (left_idx + right_idx) // 2
18 | mid = array[mid_idx]
19 |
20 | if mid_idx + 1 >= len(array):
21 | return -1
22 |
23 | if array[mid_idx + 1] < mid:
24 | return mid_idx
25 | elif array[mid_idx - 1] > mid:
26 | return mid_idx - 1
27 | elif array[left_idx] > mid:
28 | return find_pivot(array, left_idx, mid_idx - 1)
29 | return find_pivot(array, mid_idx + 1, right_idx)
30 |
31 |
32 | def binary_search(array, left_idx, right_idx, target):
33 | if left_idx > right_idx:
34 | return -1
35 |
36 | mid_idx = (left_idx + right_idx) // 2
37 | mid = array[mid_idx]
38 |
39 | if mid == target:
40 | return mid_idx
41 | elif mid < target:
42 | return binary_search(array, mid_idx + 1, right_idx, target)
43 | return binary_search(array, left_idx, mid_idx - 1, target)
44 |
45 |
46 | if __name__ == '__main__':
47 | # print(shiftedBinarySearch([1, 2, 3], 4))
48 | print(shiftedBinarySearch([73, 0, 1, 21, 33, 45, 45, 61, 71, 72], 70))
49 |
--------------------------------------------------------------------------------
/3.5. balanced-brackets.py:
--------------------------------------------------------------------------------
1 | def balancedBrackets(string):
2 | # Write your code here.
3 | stack = []
4 | for bracket in string:
5 | if len(stack) == 0:
6 | stack.append(bracket)
7 | elif bracket in '()[]{}':
8 | stack.pop(-1) if is_reversed(stack[-1], bracket) else stack.append(bracket)
9 |
10 | return len(stack) == 0
11 |
12 |
13 | def is_reversed(b1, b2):
14 | if b1 == '(' and b2 == ')':
15 | return True
16 | elif b1 == '[' and b2 == ']':
17 | return True
18 | elif b1 == '{' and b2 == '}':
19 | return True
20 | else:
21 | return False
22 |
--------------------------------------------------------------------------------
/3.6. validate-bst.py:
--------------------------------------------------------------------------------
1 | def validateBst(node, less_than=float('inf'), greater_than=float('-inf')):
2 | if node is None:
3 | return True
4 | if greater_than <= node.value < less_than:
5 | left_validation = validateBst(node.left, node.value, greater_than)
6 | right_validation = validateBst(node.right, less_than, node.value)
7 | return left_validation and right_validation
8 | return False
9 |
--------------------------------------------------------------------------------
/3.7. powerset.py:
--------------------------------------------------------------------------------
1 | def powerset(array):
2 | pass
--------------------------------------------------------------------------------
/3.8. min-max-stack.py:
--------------------------------------------------------------------------------
1 | class MinMaxStack:
2 | def __init__(self):
3 | self.values = []
4 | self.min_max = [[float('inf'), float('-inf')]]
5 |
6 | def pop(self):
7 | self.min_max.pop()
8 | return self.values.pop()
9 |
10 | def push(self, number):
11 | prev_min, prev_max = self.min_max[-1]
12 | new_min, new_max = min(prev_min, number), max(prev_max, number)
13 | self.min_max.append([new_min, new_max])
14 | self.values.append(number)
15 |
16 | def peek(self): return self.values[-1] if len(self.values) > 0 else None
17 |
18 | def getMin(self): return self.min_max[-1][0]
19 |
20 | def getMax(self): return self.min_max[-1][1]
21 |
--------------------------------------------------------------------------------
/3.9. longest-palindromic-substring.py:
--------------------------------------------------------------------------------
1 | # def longestPalindromicSubstring(string):
2 | # # Write your code here.
3 | # max_palindrome = ''
4 | # for i in range(len(string)):
5 | # for j in range(len(string)):
6 | # w = string[i: len(string) - j]
7 | # if is_palindrome(w):
8 | # if len(w) > len(max_palindrome):
9 | # max_palindrome = w
10 | #
11 | # return max_palindrome
12 | #
13 | #
14 | # def is_palindrome(string):
15 | # for i in range(len(string) // 2):
16 | # if string[i] != string[-i - 1]:
17 | # return False
18 | # return True
19 |
20 | # def is_palindrome2(string):
21 | # if len(string) <= 1:
22 | # return True
23 | #
24 | # stack = []
25 | # for char in string:
26 | # if len(stack) == 0:
27 | # stack.append(char)
28 | # else:
29 | # if len(stack) > 1 and stack[-2] == char:
30 | # stack.pop()
31 | # stack.pop()
32 | # elif stack[-1] == char:
33 | # stack.pop()
34 | # else:
35 | # stack.append(char)
36 | # return len(stack) == 0
37 | #
38 |
39 |
40 | def longestPalindromicSubstring(string):
41 | # Write your code here.
42 | if len(string) <= 1:
43 | return string
44 | longest = ''
45 | for i, char in enumerate(string):
46 | pass
47 |
48 |
49 | def largest_palindrome_from_center(string, center_idx):
50 | if len(string) == 1:
51 | return string
52 | if center_idx == len(string) - 1:
53 | if string[center_idx - 1] == string[center_idx]:
54 | return string[center_idx - 1: center_idx + 1]
55 | else:
56 | return string[center_idx]
57 | elif center_idx == 0:
58 | if string[center_idx + 1] == string[center_idx]:
59 | return string[center_idx: center_idx + 1]
60 | else:
61 | return string[center_idx]
62 | return search_palindrome(string, center_idx - 1, center_idx + 1)
63 |
64 |
65 | def search_palindrome(string, left_idx, right_idx):
66 | for i in range((left_idx + right_idx) // 2):
67 | left = left_idx - i
68 | right = right_idx + i
69 |
70 | print(left, right)
71 |
72 | if string[left] != string[right]:
73 | odd_palindrome = search_palindrome(string, left_idx - 1, right_idx)
74 | even_palindrome = string[left + 1:right]
75 | return max(even_palindrome, odd_palindrome, key=lambda x: len(x))
76 | elif right == len(string) - 1 or left <= 0:
77 | return string[left:right + 1]
78 | return ''
79 |
80 |
81 | if __name__ == '__main__':
82 | # print(largest_palindrome_from_center('aabaa', 2))
83 | # print(largest_palindrome_from_center('aba', 1))
84 | # print(largest_palindrome_from_center('abba', 2))
85 | # print(largest_palindrome_from_center('aaa', 1))
86 | # print(largest_palindrome_from_center('aa', 1))
87 | print(largest_palindrome_from_center('aab', 0))
88 |
--------------------------------------------------------------------------------