Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Data_Structures_Answers.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,40 @@ Add your answers to the questions below.

1. What is the runtime complexity of your ring buffer's `append` method?

It's **O(1)** because each append just overwrites the element of an internal
array stored in a **current** buffer position.

2. What is the space complexity of your ring buffer's `append` function?

It's **O(1)** based on code, or **O(n)** to be more precise, where **n** is the
length of an input. We do not store any additional data, only overwrite the
array at the specific index with the input data. Can be **O(1)** if we assume
that the input has always the fixed size.

3. What is the runtime complexity of your ring buffer's `get` method?

It's **O(1)** when we do not filter out the data. Then we always return the
entire structure, so the pointer to the very beginning of this structure and we
can do it in constant time. With the required filtering of `None` values (e.g.
when we did not insert enough data to make the buffer full), it's **O(n)**.

4. What is the space complexity of your ring buffer's `get` method?

It's **O(1)**. We only return the buffer that is **n**-elements long, no other
allocated memory there.

5. What is the runtime complexity of the provided code in `names.py`?

It's **O(n^2)** as we have two nested for loops.

6. What is the space complexity of the provided code in `names.py`?

It's **O(n)** memory-wise. We store the data in an array.

7. What is the runtime complexity of your optimized code in `names.py`?

It's **O(n)** for the normal task, **O(n log n)** for stretch.

8. What is the space complexity of your optimized code in `names.py`?

It's **O(n)** where `n` is the length of input.
13 changes: 13 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]
pylint = "*"
autopep8 = "*"

[packages]

[requires]
python_version = "3.7"
129 changes: 129 additions & 0 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

163 changes: 161 additions & 2 deletions names/names.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,56 @@
import time
from collections import Counter


class BinarySearchTree:
def __init__(self, value):
self.value = value
self.left = None
self.right = None

def insert(self, value):
if self.value == None:
self.value == value
elif value < self.value:
if self.left == None:
self.left = BinarySearchTree(value)
else:
self.left.insert(value)
else:
if self.right == None:
self.right = BinarySearchTree(value)
else:
self.right.insert(value)

def contains(self, target):
if self.value == target:
return True
elif target < self.value:
if self.left != None:
return self.left.contains(target)
else:
return False
else:
if self.right != None:
return self.right.contains(target)
else:
return False

def get_max(self):
if self.right == None:
return self.value
else:
return self.right.get_max()

def for_each(self, cb):
cb(self.value)
if self.left != None:
self.left.for_each(cb)
if self.right != None:
self.right.for_each(cb)


# original solution
start_time = time.time()

f = open('names_1.txt', 'r')
Expand All @@ -17,6 +68,114 @@
duplicates.append(name_1)

end_time = time.time()
print (f"{len(duplicates)} duplicates:\n\n{', '.join(duplicates)}\n\n")
print (f"runtime: {end_time - start_time} seconds")
print(f"{len(duplicates)} duplicates:\n\n{', '.join(duplicates)}\n\n")
print(f"runtime: {end_time - start_time} seconds")

# first pass solution
start_time = time.time()

f = open('names_1.txt', 'r')
names_1 = f.read().split("\n") # List containing 10000 names
f.close()

f = open('names_2.txt', 'r')
names_2 = f.read().split("\n") # List containing 10000 names
f.close()

counts = dict()
for elem in names_1:
if elem not in counts:
counts[elem] = 1
continue
counts[elem] += 1
for elem in names_2:
if elem not in counts:
counts[elem] = 1
continue
counts[elem] += 1
duplicates = [key for key, value in counts.items() if value > 1]

end_time = time.time()
print(f"{len(duplicates)} duplicates:\n\n{', '.join(duplicates)}\n\n")
print(f"runtime: {end_time - start_time} seconds")


# second pass solution with BST
start_time = time.time()

f = open('names_1.txt', 'r')
names_1 = f.read().split("\n") # List containing 10000 names
f.close()

f = open('names_2.txt', 'r')
names_2 = f.read().split("\n") # List containing 10000 names
f.close()

bts_names_2 = BinarySearchTree(names_2[0])

for name_1 in names_2[1:]:
bts_names_2.insert(name_1)

duplicates = []

for name_1 in names_1:
if bts_names_2.contains(name_1):
duplicates.append(name_1)

end_time = time.time()
print(f"{len(duplicates)} duplicates:\n\n{', '.join(duplicates)}\n\n")
print(f"runtime: {end_time - start_time} seconds")

# stretch
start_time = time.time()

f = open('names_1.txt', 'r')
names_1 = f.read().split("\n") # List containing 10000 names
f.close()

f = open('names_2.txt', 'r')
names_2 = f.read().split("\n") # List containing 10000 names
f.close()

names_2.sort()


def sub(arr, x):
L = 0
R = len(arr)
m = -1
while L < R:
m = (L+R)//2
if x <= arr[m]:
R = m
else:
L = m + 1
return arr[L] == x


duplicates = []

for elem in names_1:
if sub(names_2, elem):
duplicates.append(elem)

end_time = time.time()
print(f"{len(duplicates)} duplicates:\n\n{', '.join(duplicates)}\n\n")
print(f"runtime: {end_time - start_time} seconds")

# stretch 2
start_time = time.time()

f = open('names_1.txt', 'r')
names_1 = f.read().split("\n") # List containing 10000 names
f.close()

f = open('names_2.txt', 'r')
names_2 = f.read().split("\n") # List containing 10000 names
f.close()

duplicates = list((Counter(names_1) & Counter(names_2)))

end_time = time.time()
print(f"{len(duplicates)} duplicates:\n\n{', '.join(duplicates)}\n\n")
print(f"runtime: {end_time - start_time} seconds")
17 changes: 9 additions & 8 deletions ring_buffer/ring_buffer.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
class RingBuffer:
def __init__(self, capacity):
self.capacity = capacity
self.current = 0
self.storage = [None]*capacity
def __init__(self, capacity):
self.capacity = capacity
self.current = 0
self.storage = [None]*capacity

def append(self, item):
pass
def append(self, item):
self.storage[self.current] = item
self.current = (self.current+1) % self.capacity

def get(self):
pass
def get(self):
return [x for x in self.storage if x != None]