diff --git a/Data_Structures_Answers.md b/Data_Structures_Answers.md index e39545492..3ce0fcb4f 100644 --- a/Data_Structures_Answers.md +++ b/Data_Structures_Answers.md @@ -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. diff --git a/Pipfile b/Pipfile new file mode 100644 index 000000000..28fab03db --- /dev/null +++ b/Pipfile @@ -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" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 000000000..3c6ed4415 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,129 @@ +{ + "_meta": { + "hash": { + "sha256": "5f7b0b9c5975fb1f502f64233df27d5ac29de15ca813ae730b59736f06aa18ca" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": {}, + "develop": { + "astroid": { + "hashes": [ + "sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4", + "sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4" + ], + "version": "==2.2.5" + }, + "autopep8": { + "hashes": [ + "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" + ], + "index": "pypi", + "version": "==1.4.4" + }, + "colorama": { + "hashes": [ + "sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", + "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48" + ], + "markers": "sys_platform == 'win32'", + "version": "==0.4.1" + }, + "isort": { + "hashes": [ + "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", + "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd" + ], + "version": "==4.3.21" + }, + "lazy-object-proxy": { + "hashes": [ + "sha256:159a745e61422217881c4de71f9eafd9d703b93af95618635849fe469a283661", + "sha256:23f63c0821cc96a23332e45dfaa83266feff8adc72b9bcaef86c202af765244f", + "sha256:3b11be575475db2e8a6e11215f5aa95b9ec14de658628776e10d96fa0b4dac13", + "sha256:3f447aff8bc61ca8b42b73304f6a44fa0d915487de144652816f950a3f1ab821", + "sha256:4ba73f6089cd9b9478bc0a4fa807b47dbdb8fad1d8f31a0f0a5dbf26a4527a71", + "sha256:4f53eadd9932055eac465bd3ca1bd610e4d7141e1278012bd1f28646aebc1d0e", + "sha256:64483bd7154580158ea90de5b8e5e6fc29a16a9b4db24f10193f0c1ae3f9d1ea", + "sha256:6f72d42b0d04bfee2397aa1862262654b56922c20a9bb66bb76b6f0e5e4f9229", + "sha256:7c7f1ec07b227bdc561299fa2328e85000f90179a2f44ea30579d38e037cb3d4", + "sha256:7c8b1ba1e15c10b13cad4171cfa77f5bb5ec2580abc5a353907780805ebe158e", + "sha256:8559b94b823f85342e10d3d9ca4ba5478168e1ac5658a8a2f18c991ba9c52c20", + "sha256:a262c7dfb046f00e12a2bdd1bafaed2408114a89ac414b0af8755c696eb3fc16", + "sha256:acce4e3267610c4fdb6632b3886fe3f2f7dd641158a843cf6b6a68e4ce81477b", + "sha256:be089bb6b83fac7f29d357b2dc4cf2b8eb8d98fe9d9ff89f9ea6012970a853c7", + "sha256:bfab710d859c779f273cc48fb86af38d6e9210f38287df0069a63e40b45a2f5c", + "sha256:c10d29019927301d524a22ced72706380de7cfc50f767217485a912b4c8bd82a", + "sha256:dd6e2b598849b3d7aee2295ac765a578879830fb8966f70be8cd472e6069932e", + "sha256:e408f1eacc0a68fed0c08da45f31d0ebb38079f043328dce69ff133b95c29dc1" + ], + "version": "==1.4.1" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "pycodestyle": { + "hashes": [ + "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", + "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c" + ], + "version": "==2.5.0" + }, + "pylint": { + "hashes": [ + "sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09", + "sha256:723e3db49555abaf9bf79dc474c6b9e2935ad82230b10c1138a71ea41ac0fff1" + ], + "index": "pypi", + "version": "==2.3.1" + }, + "six": { + "hashes": [ + "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", + "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" + ], + "version": "==1.12.0" + }, + "typed-ast": { + "hashes": [ + "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", + "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", + "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", + "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", + "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", + "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", + "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", + "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", + "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", + "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", + "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", + "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", + "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", + "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", + "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" + ], + "markers": "implementation_name == 'cpython'", + "version": "==1.4.0" + }, + "wrapt": { + "hashes": [ + "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" + ], + "version": "==1.11.2" + } + } +} diff --git a/names/names.py b/names/names.py index 586e8393e..3fe972e62 100644 --- a/names/names.py +++ b/names/names.py @@ -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') @@ -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") diff --git a/ring_buffer/ring_buffer.py b/ring_buffer/ring_buffer.py index 35fd33cac..bd88561be 100644 --- a/ring_buffer/ring_buffer.py +++ b/ring_buffer/ring_buffer.py @@ -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 \ No newline at end of file + def get(self): + return [x for x in self.storage if x != None]