From 88e977a88f81ea6d4b60ebe0fa5853e6d37c4547 Mon Sep 17 00:00:00 2001 From: Vaibhav Singh <45447817+itsvaibhav01@users.noreply.github.com> Date: Thu, 26 Mar 2020 20:42:05 +0530 Subject: [PATCH 01/11] With all suggested changes :white_check_mark: possibly covered all the recommended guidelines --- .../stacks/next_greater_element.py | 66 ++++++++++++++++--- 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/data_structures/stacks/next_greater_element.py b/data_structures/stacks/next_greater_element.py index 29a039b9698b..e4ecf3f49f07 100644 --- a/data_structures/stacks/next_greater_element.py +++ b/data_structures/stacks/next_greater_element.py @@ -1,13 +1,11 @@ -def printNGE(arr): +def next_greatest_element_slow(arr): """ - Function to print element and Next Greatest Element (NGE) pair for all elements of list - NGE - Maximum element present afterwards the current one which is also greater than current one + Function to get Next Greatest Element (NGE) pair for all elements of list + Maximum element present afterwards the current one which is also greater than current one >>> printNGE([11,13,21,3]) - 11 -- 13 - 13 -- 21 - 21 -- -1 - 3 -- -1 + [13,21,-1,-1] """ + result = [] for i in range(0, len(arr), 1): next = -1 @@ -15,10 +13,60 @@ def printNGE(arr): if arr[i] < arr[j]: next = arr[j] break + result.append(next) + + return result + +def next_greatest_element(arr): + """ + Function to get Next Greatest Element (NGE) pair for all elements of list + Maximum element present afterwards the current one which is also greater than current one + + Naive way to solve this is to take two loops and check for the next bigger number but that will make the + time complexity as O(n^2). The better way to solve this would be to use a stack to keep track of maximum + number givig a linear time complex solution. + + >>> printNGE([11,13,21,3]) + [13,21,-1,-1] + """ + stack = [] + result = [-1]*len(arr) + + for index in reversed(range(len(arr))): + if len(stack): + while stack[-1] <= arr[index]: + stack.pop() + if len(stack) == 0: + break + + if len(stack) != 0: + result[index] = stack[-1] + + stack.append(arr[index]) + + return result - print(str(arr[i]) + " -- " + str(next)) # Driver program to test above function arr = [11, 13, 21, 3] -printNGE(arr) +next_greatest_element_slow(arr) +next_greatest_element(arr) + +# To check for speed differnce lets give our function much more complex array +import numpy as np +import time + +l = np.random.randint(10**5 , size = 10**5) + +start = time.time() +next_greatest_element_slow(l) +end = time.time() + +print(end - start) + +start = time.time() +next_greatest_element(l) +end = time.time() + +print(end - start) From 7e11335e04b515e929a8f3a45148ca7d97a5a919 Mon Sep 17 00:00:00 2001 From: Vaibhav Singh <45447817+itsvaibhav01@users.noreply.github.com> Date: Thu, 26 Mar 2020 20:46:53 +0530 Subject: [PATCH 02/11] Updated with both slow and faster algorithms possibally covered all the recomendations --- data_structures/stacks/next_greater_element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/stacks/next_greater_element.py b/data_structures/stacks/next_greater_element.py index e4ecf3f49f07..79a1211ac00f 100644 --- a/data_structures/stacks/next_greater_element.py +++ b/data_structures/stacks/next_greater_element.py @@ -57,7 +57,7 @@ def next_greatest_element(arr): import numpy as np import time -l = np.random.randint(10**5 , size = 10**5) +l = np.random.randint(10**1 , size = 10**1) start = time.time() next_greatest_element_slow(l) From ea8ad6ba6b073ec87a1f66b5e45fa11e896cc1f5 Mon Sep 17 00:00:00 2001 From: Vaibhav Singh <45447817+itsvaibhav01@users.noreply.github.com> Date: Fri, 27 Mar 2020 09:16:00 +0530 Subject: [PATCH 03/11] removed the time comparision part! --- data_structures/stacks/next_greater_element.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/data_structures/stacks/next_greater_element.py b/data_structures/stacks/next_greater_element.py index 79a1211ac00f..0c26b7a5ff0d 100644 --- a/data_structures/stacks/next_greater_element.py +++ b/data_structures/stacks/next_greater_element.py @@ -52,21 +52,3 @@ def next_greatest_element(arr): arr = [11, 13, 21, 3] next_greatest_element_slow(arr) next_greatest_element(arr) - -# To check for speed differnce lets give our function much more complex array -import numpy as np -import time - -l = np.random.randint(10**1 , size = 10**1) - -start = time.time() -next_greatest_element_slow(l) -end = time.time() - -print(end - start) - -start = time.time() -next_greatest_element(l) -end = time.time() - -print(end - start) From d73abb133d059bc377c9ae06a7665be78b4641ca Mon Sep 17 00:00:00 2001 From: Vaibhav Singh <45447817+itsvaibhav01@users.noreply.github.com> Date: Fri, 27 Mar 2020 10:23:02 +0530 Subject: [PATCH 04/11] Update data_structures/stacks/next_greater_element.py Co-Authored-By: Christian Clauss --- data_structures/stacks/next_greater_element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/stacks/next_greater_element.py b/data_structures/stacks/next_greater_element.py index 0c26b7a5ff0d..352a88ed4415 100644 --- a/data_structures/stacks/next_greater_element.py +++ b/data_structures/stacks/next_greater_element.py @@ -2,7 +2,7 @@ def next_greatest_element_slow(arr): """ Function to get Next Greatest Element (NGE) pair for all elements of list Maximum element present afterwards the current one which is also greater than current one - >>> printNGE([11,13,21,3]) + >>> next_greatest_element_slow([11,13,21,3]) [13,21,-1,-1] """ result = [] From f043b0f1b31c05b56e22b24361fb7cdcf886c9bd Mon Sep 17 00:00:00 2001 From: Vaibhav Singh <45447817+itsvaibhav01@users.noreply.github.com> Date: Fri, 27 Mar 2020 10:23:23 +0530 Subject: [PATCH 05/11] Update data_structures/stacks/next_greater_element.py Co-Authored-By: Christian Clauss --- data_structures/stacks/next_greater_element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/stacks/next_greater_element.py b/data_structures/stacks/next_greater_element.py index 352a88ed4415..b4b33e7fbd83 100644 --- a/data_structures/stacks/next_greater_element.py +++ b/data_structures/stacks/next_greater_element.py @@ -3,7 +3,7 @@ def next_greatest_element_slow(arr): Function to get Next Greatest Element (NGE) pair for all elements of list Maximum element present afterwards the current one which is also greater than current one >>> next_greatest_element_slow([11,13,21,3]) - [13,21,-1,-1] + [13, 21, -1, -1] """ result = [] for i in range(0, len(arr), 1): From 850ef0eba4a06b1626a30278a1041b22adab30a1 Mon Sep 17 00:00:00 2001 From: Vaibhav Singh <45447817+itsvaibhav01@users.noreply.github.com> Date: Fri, 27 Mar 2020 10:23:40 +0530 Subject: [PATCH 06/11] Update data_structures/stacks/next_greater_element.py Co-Authored-By: Christian Clauss --- data_structures/stacks/next_greater_element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/stacks/next_greater_element.py b/data_structures/stacks/next_greater_element.py index b4b33e7fbd83..7ebf5097c32d 100644 --- a/data_structures/stacks/next_greater_element.py +++ b/data_structures/stacks/next_greater_element.py @@ -27,7 +27,7 @@ def next_greatest_element(arr): number givig a linear time complex solution. >>> printNGE([11,13,21,3]) - [13,21,-1,-1] + [13, 21, -1, -1] """ stack = [] result = [-1]*len(arr) From 39d93d0f89f399fa8463c57ae7fa6909c9c2128b Mon Sep 17 00:00:00 2001 From: Vaibhav Singh <45447817+itsvaibhav01@users.noreply.github.com> Date: Fri, 27 Mar 2020 10:23:51 +0530 Subject: [PATCH 07/11] Update data_structures/stacks/next_greater_element.py Co-Authored-By: Christian Clauss --- data_structures/stacks/next_greater_element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/stacks/next_greater_element.py b/data_structures/stacks/next_greater_element.py index 7ebf5097c32d..b61fd6279f2b 100644 --- a/data_structures/stacks/next_greater_element.py +++ b/data_structures/stacks/next_greater_element.py @@ -26,7 +26,7 @@ def next_greatest_element(arr): time complexity as O(n^2). The better way to solve this would be to use a stack to keep track of maximum number givig a linear time complex solution. - >>> printNGE([11,13,21,3]) + >>> next_greatest_element([11,13,21,3]) [13, 21, -1, -1] """ stack = [] From e767f9c26a4968a971f635019d98db3aa2e64fb9 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 27 Mar 2020 06:30:41 +0100 Subject: [PATCH 08/11] Add benchmark using timeit https://docs.python.org/3/library/timeit.html The performance delta between these two implementation is quite small... ``` next_greatest_element_slow(): 1.843442126 next_greatest_element(): 1.828941414 ``` --- .../stacks/next_greater_element.py | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/data_structures/stacks/next_greater_element.py b/data_structures/stacks/next_greater_element.py index b61fd6279f2b..3ac6f7b43d6c 100644 --- a/data_structures/stacks/next_greater_element.py +++ b/data_structures/stacks/next_greater_element.py @@ -2,7 +2,7 @@ def next_greatest_element_slow(arr): """ Function to get Next Greatest Element (NGE) pair for all elements of list Maximum element present afterwards the current one which is also greater than current one - >>> next_greatest_element_slow([11,13,21,3]) + >>> next_greatest_element_slow([11, 13, 21, 3]) [13, 21, -1, -1] """ result = [] @@ -26,7 +26,7 @@ def next_greatest_element(arr): time complexity as O(n^2). The better way to solve this would be to use a stack to keep track of maximum number givig a linear time complex solution. - >>> next_greatest_element([11,13,21,3]) + >>> next_greatest_element([11, 13, 21, 3]) [13, 21, -1, -1] """ stack = [] @@ -47,8 +47,16 @@ def next_greatest_element(arr): return result +if __name__ == "__main__": + from timeit import timeit -# Driver program to test above function -arr = [11, 13, 21, 3] -next_greatest_element_slow(arr) -next_greatest_element(arr) + arr = [11, 13, 21, 3] + print(next_greatest_element_slow(arr)) + print(next_greatest_element(arr)) + + setup = ("from __main__ import arr, next_greatest_element_slow, " + "next_greatest_element") + print("next_greatest_element_slow():", + timeit("next_greatest_element_slow(arr)", setup=setup)) + print(" next_greatest_element():", + timeit("next_greatest_element(arr)", setup=setup)) From 06a5f514167f2737fbc2d6d1ac6a51d48f2d8563 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 27 Mar 2020 07:54:28 +0100 Subject: [PATCH 09/11] Optimize slow() to create fast() - Three algorithms in the race Three algorithms in the race --- .../stacks/next_greater_element.py | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/data_structures/stacks/next_greater_element.py b/data_structures/stacks/next_greater_element.py index 3ac6f7b43d6c..abb131a9c06e 100644 --- a/data_structures/stacks/next_greater_element.py +++ b/data_structures/stacks/next_greater_element.py @@ -7,16 +7,34 @@ def next_greatest_element_slow(arr): """ result = [] for i in range(0, len(arr), 1): - next = -1 for j in range(i + 1, len(arr), 1): if arr[i] < arr[j]: next = arr[j] break result.append(next) - return result + +def next_greatest_element_fast(arr): + """ + Like next_greatest_element_slow() but changes the loops to use + enumerate() instead of range(len()) for the outer loop and + for in a slice of arr in the inner loop. + >>> next_greatest_element_fast([11, 13, 21, 3]) + [13, 21, -1, -1] + """ + result = [] + for i, outer in enumerate(arr): + next = -1 + for inner in arr[i + 1:]: + if outer < inner: + next = inner + break + result.append(next) + return result + + def next_greatest_element(arr): """ Function to get Next Greatest Element (NGE) pair for all elements of list @@ -50,13 +68,16 @@ def next_greatest_element(arr): if __name__ == "__main__": from timeit import timeit - arr = [11, 13, 21, 3] + arr = [-10, -5, 0, 5, 5.1, 11, 13, 21, 3, 4, -21, -10, -5, -1, 0] print(next_greatest_element_slow(arr)) + print(next_greatest_element_fast(arr)) print(next_greatest_element(arr)) setup = ("from __main__ import arr, next_greatest_element_slow, " "next_greatest_element") print("next_greatest_element_slow():", timeit("next_greatest_element_slow(arr)", setup=setup)) + print("next_greatest_element_fast():", + timeit("next_greatest_element_fast(arr)", setup=setup)) print(" next_greatest_element():", timeit("next_greatest_element(arr)", setup=setup)) From b28b4ef4cd17b2773b62936747d74bd542c977db Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 27 Mar 2020 08:03:52 +0100 Subject: [PATCH 10/11] Use a bigger test array with floats, negatives, zero --- data_structures/stacks/next_greater_element.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/data_structures/stacks/next_greater_element.py b/data_structures/stacks/next_greater_element.py index abb131a9c06e..0316d8784b69 100644 --- a/data_structures/stacks/next_greater_element.py +++ b/data_structures/stacks/next_greater_element.py @@ -1,9 +1,11 @@ +arr = [-10, -5, 0, 5, 5.1, 11, 13, 21, 3, 4, -21, -10, -5, -1, 0] + def next_greatest_element_slow(arr): """ Function to get Next Greatest Element (NGE) pair for all elements of list Maximum element present afterwards the current one which is also greater than current one - >>> next_greatest_element_slow([11, 13, 21, 3]) - [13, 21, -1, -1] + >>> next_greatest_element_slow(arr) + [-5, 0, 5, 5.1, 11, 13, 21, -1, 4, -1, -10, -5, -1, 0, -1] """ result = [] for i in range(0, len(arr), 1): @@ -21,8 +23,8 @@ def next_greatest_element_fast(arr): Like next_greatest_element_slow() but changes the loops to use enumerate() instead of range(len()) for the outer loop and for in a slice of arr in the inner loop. - >>> next_greatest_element_fast([11, 13, 21, 3]) - [13, 21, -1, -1] + >>> next_greatest_element_fast(arr) + [-5, 0, 5, 5.1, 11, 13, 21, -1, 4, -1, -10, -5, -1, 0, -1] """ result = [] for i, outer in enumerate(arr): @@ -44,8 +46,8 @@ def next_greatest_element(arr): time complexity as O(n^2). The better way to solve this would be to use a stack to keep track of maximum number givig a linear time complex solution. - >>> next_greatest_element([11, 13, 21, 3]) - [13, 21, -1, -1] + >>> next_greatest_element(arr) + [-5, 0, 5, 5.1, 11, 13, 21, -1, 4, -1, -10, -5, -1, 0, -1] """ stack = [] result = [-1]*len(arr) @@ -66,9 +68,10 @@ def next_greatest_element(arr): if __name__ == "__main__": + from doctest import testmod from timeit import timeit - arr = [-10, -5, 0, 5, 5.1, 11, 13, 21, 3, 4, -21, -10, -5, -1, 0] + testmod() print(next_greatest_element_slow(arr)) print(next_greatest_element_fast(arr)) print(next_greatest_element(arr)) From b46513bbcdb3b5f7254865b3009bb7c91160af16 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 27 Mar 2020 08:09:48 +0100 Subject: [PATCH 11/11] Setup import next_greatest_element_fast --- data_structures/stacks/next_greater_element.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data_structures/stacks/next_greater_element.py b/data_structures/stacks/next_greater_element.py index 0316d8784b69..4b400334e75e 100644 --- a/data_structures/stacks/next_greater_element.py +++ b/data_structures/stacks/next_greater_element.py @@ -22,7 +22,7 @@ def next_greatest_element_fast(arr): """ Like next_greatest_element_slow() but changes the loops to use enumerate() instead of range(len()) for the outer loop and - for in a slice of arr in the inner loop. + for in a slice of arr for the inner loop. >>> next_greatest_element_fast(arr) [-5, 0, 5, 5.1, 11, 13, 21, -1, 4, -1, -10, -5, -1, 0, -1] """ @@ -77,7 +77,7 @@ def next_greatest_element(arr): print(next_greatest_element(arr)) setup = ("from __main__ import arr, next_greatest_element_slow, " - "next_greatest_element") + "next_greatest_element_fast, next_greatest_element") print("next_greatest_element_slow():", timeit("next_greatest_element_slow(arr)", setup=setup)) print("next_greatest_element_fast():",