From 7c8e8fa25b6d57b030db3cd816630545338ba358 Mon Sep 17 00:00:00 2001 From: FamALouiz Date: Mon, 10 Mar 2025 20:43:36 +0100 Subject: [PATCH 1/9] Added longest alternating subsequence to linear algorithms --- .../linear_data_structures/algorithms.rst | 4 +- .../linear_data_structures/__init__.py | 3 +- .../linear_data_structures/algorithms.py | 69 ++++++++++++++++++- 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/docs/source/pydatastructs/linear_data_structures/algorithms.rst b/docs/source/pydatastructs/linear_data_structures/algorithms.rst index 7ab521cfd..a66dc33bb 100644 --- a/docs/source/pydatastructs/linear_data_structures/algorithms.rst +++ b/docs/source/pydatastructs/linear_data_structures/algorithms.rst @@ -45,4 +45,6 @@ Algorithms .. autofunction:: pydatastructs.jump_search -.. autofunction:: pydatastructs.intro_sort \ No newline at end of file +.. autofunction:: pydatastructs.intro_sort + +.. autofunction:: pydatastructs.longest_increasing_subsequence \ No newline at end of file diff --git a/pydatastructs/linear_data_structures/__init__.py b/pydatastructs/linear_data_structures/__init__.py index 057adc169..034702aaf 100644 --- a/pydatastructs/linear_data_structures/__init__.py +++ b/pydatastructs/linear_data_structures/__init__.py @@ -47,6 +47,7 @@ jump_search, selection_sort, insertion_sort, - intro_sort + intro_sort, + longest_alternating_subsequence, ) __all__.extend(algorithms.__all__) diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index 792bce855..3773ad023 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -30,7 +30,8 @@ 'jump_search', 'selection_sort', 'insertion_sort', - 'intro_sort' + 'intro_sort', + 'longest_alternating_subsequence', ] def _merge(array, sl, el, sr, er, end, comp): @@ -1850,3 +1851,69 @@ def partition(array, lower, upper): intro_sort(array, start=p+1, end=upper, maxdepth=maxdepth-1, ins_threshold=ins_threshold) return array + +def longest_alternating_subsequence(array: OneDimensionalArray, **kwargs) -> OneDimensionalArray: + """ + Finds the longest alternating subsequence in the given array. + An alternating sequence is one in which the elements are in alternating order, + i.e., a sequence where the differences between consecutive elements alternate + between positive and negative. + + Parameters + ========== + + array: OneDimensionalArray + The array from which the longest alternating subsequence is to be found. + backend: pydatastructs.Backend + The backend to be used. + Optional, by default, the best available backend is used. + + Returns + ======= + + output: OneDimensionalArray + The longest alternating subsequence. + + Examples + ======== + + >>> from pydatastructs import OneDimensionalArray, longest_alternating_subsequence + >>> arr = OneDimensionalArray(int, [1, 5, 4]) + >>> las = longest_alternating_subsequence(arr) + >>> str(las) + '[1, 5, 4]' + >>> arr = OneDimensionalArray(int, [1, 5, 4, 3, 2, 6, 7]) + >>> las = longest_alternating_subsequence(arr) + >>> str(las) + '[1, 5, 4, 6, 2, 7]' + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Longest_alternating_subsequence + + Note + ==== + + The data types of elements in the array should be comparable. + """ + raise_if_backend_is_not_python( + longest_alternating_subsequence, kwargs.get('backend', Backend.PYTHON)) + + increasing = 1 + decreasing = 1 + n = len(array) + + # Iterate from second element + for i in range(1, n): + + # Increasing changes if decreasing changes + if (array[i] > array[i-1]): + increasing = decreasing + 1 + + # Decreasing changes if increasing changes + elif (array[i] < array[i-1]): + decreasing = increasing + 1 + + # Return the maximum length + return max(increasing, decreasing) From 642999ed9d6ad748ba14e2249b22264ebbc7bcda Mon Sep 17 00:00:00 2001 From: FamALouiz Date: Mon, 10 Mar 2025 21:20:24 +0100 Subject: [PATCH 2/9] Fixed function return type --- pydatastructs/linear_data_structures/algorithms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index 3773ad023..959da979b 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -1852,7 +1852,7 @@ def partition(array, lower, upper): return array -def longest_alternating_subsequence(array: OneDimensionalArray, **kwargs) -> OneDimensionalArray: +def longest_alternating_subsequence(array: OneDimensionalArray, **kwargs) -> int: """ Finds the longest alternating subsequence in the given array. An alternating sequence is one in which the elements are in alternating order, From d594f682fc3a050af66f3fc834d3af481d223d95 Mon Sep 17 00:00:00 2001 From: FamALouiz Date: Mon, 10 Mar 2025 21:20:39 +0100 Subject: [PATCH 3/9] Added tests for longest alternating subsequence algorithm --- .../tests/test_algorithms.py | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/pydatastructs/linear_data_structures/tests/test_algorithms.py b/pydatastructs/linear_data_structures/tests/test_algorithms.py index 46609544b..87b6eb52b 100644 --- a/pydatastructs/linear_data_structures/tests/test_algorithms.py +++ b/pydatastructs/linear_data_structures/tests/test_algorithms.py @@ -5,7 +5,7 @@ cocktail_shaker_sort, quick_sort, longest_common_subsequence, is_ordered, upper_bound, lower_bound, longest_increasing_subsequence, next_permutation, prev_permutation, bubble_sort, linear_search, binary_search, jump_search, - selection_sort, insertion_sort, intro_sort, Backend) + selection_sort, insertion_sort, intro_sort, longest_alternating_subsequence, Backend) from pydatastructs.utils.raises_util import raises import random @@ -414,3 +414,32 @@ def test_binary_search(): def test_jump_search(): _test_common_search(jump_search) _test_common_search(jump_search, backend=Backend.CPP) + + +def test_longest_alternating_subsequence(): + ODA = OneDimensionalArray + + arr1 = ODA(int, [-4, 3, -5, 9, 10, 12, 2, -1]) + output: OneDimensionalArray = longest_alternating_subsequence(arr1) + expected_result = [3, -5, 9, 2, -1] + assert len(expected_result) == output + + arr2 = ODA(int, [10, 22, 9, 33, 49, 50, 31, 60]) + output: OneDimensionalArray = longest_alternating_subsequence(arr2) + expected_result = [10, 22, 9, 33, 31, 60] + assert len(expected_result) == output + + arr3 = ODA(int, [1, 2, 3, 4, 5, 6, 7, 8, 9]) + output: OneDimensionalArray = longest_alternating_subsequence(arr3) + expected_result = [1, 2] + assert len(expected_result) == output + + arr4 = ODA(int, [9, 8, 7, 6, 5, 4, 3, 2, 1]) + output: OneDimensionalArray = longest_alternating_subsequence(arr4) + expected_result = [9, 8] + assert len(expected_result) == output + + arr5 = ODA(int, [1, 5, 4, 3, 2, 1, 6, 7, 8, 9]) + output: OneDimensionalArray = longest_alternating_subsequence(arr5) + expected_result = [1, 5, 4, 6] + assert len(expected_result) == output From 97f4396a0839cc63b217801a6961b4ea8fa92378 Mon Sep 17 00:00:00 2001 From: FamALouiz Date: Mon, 10 Mar 2025 22:48:57 +0100 Subject: [PATCH 4/9] Fixed error with function docstring --- pydatastructs/linear_data_structures/algorithms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index 959da979b..3189ad62a 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -1881,11 +1881,11 @@ def longest_alternating_subsequence(array: OneDimensionalArray, **kwargs) -> int >>> arr = OneDimensionalArray(int, [1, 5, 4]) >>> las = longest_alternating_subsequence(arr) >>> str(las) - '[1, 5, 4]' + 3 >>> arr = OneDimensionalArray(int, [1, 5, 4, 3, 2, 6, 7]) >>> las = longest_alternating_subsequence(arr) >>> str(las) - '[1, 5, 4, 6, 2, 7]' + 7 References ========== From 09945c0de704ad45df938071c11559ed52afcb6b Mon Sep 17 00:00:00 2001 From: FamALouiz Date: Mon, 10 Mar 2025 22:56:34 +0100 Subject: [PATCH 5/9] Fixed function docstring --- pydatastructs/linear_data_structures/algorithms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index 3189ad62a..d86e1607f 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -1880,11 +1880,11 @@ def longest_alternating_subsequence(array: OneDimensionalArray, **kwargs) -> int >>> from pydatastructs import OneDimensionalArray, longest_alternating_subsequence >>> arr = OneDimensionalArray(int, [1, 5, 4]) >>> las = longest_alternating_subsequence(arr) - >>> str(las) + >>> las 3 >>> arr = OneDimensionalArray(int, [1, 5, 4, 3, 2, 6, 7]) >>> las = longest_alternating_subsequence(arr) - >>> str(las) + >>> las 7 References From b24544ec436213ca8a46f453d01350bbd25ca809 Mon Sep 17 00:00:00 2001 From: Fam Shihata <88089745+FamALouiz@users.noreply.github.com> Date: Mon, 10 Mar 2025 23:06:26 +0100 Subject: [PATCH 6/9] Updated longest_alternating_subsequence docstring --- pydatastructs/linear_data_structures/algorithms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index d86e1607f..38c55b464 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -1885,7 +1885,7 @@ def longest_alternating_subsequence(array: OneDimensionalArray, **kwargs) -> int >>> arr = OneDimensionalArray(int, [1, 5, 4, 3, 2, 6, 7]) >>> las = longest_alternating_subsequence(arr) >>> las - 7 + 4 References ========== From 98e153805726a351decd34f88125f68d4611c7bb Mon Sep 17 00:00:00 2001 From: FamALouiz Date: Mon, 10 Mar 2025 23:11:52 +0100 Subject: [PATCH 7/9] Updated expected return type in LAS test --- .../linear_data_structures/tests/test_algorithms.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pydatastructs/linear_data_structures/tests/test_algorithms.py b/pydatastructs/linear_data_structures/tests/test_algorithms.py index 87b6eb52b..3e0e1ebcc 100644 --- a/pydatastructs/linear_data_structures/tests/test_algorithms.py +++ b/pydatastructs/linear_data_structures/tests/test_algorithms.py @@ -420,26 +420,26 @@ def test_longest_alternating_subsequence(): ODA = OneDimensionalArray arr1 = ODA(int, [-4, 3, -5, 9, 10, 12, 2, -1]) - output: OneDimensionalArray = longest_alternating_subsequence(arr1) + output: int = longest_alternating_subsequence(arr1) expected_result = [3, -5, 9, 2, -1] assert len(expected_result) == output arr2 = ODA(int, [10, 22, 9, 33, 49, 50, 31, 60]) - output: OneDimensionalArray = longest_alternating_subsequence(arr2) + output: int = longest_alternating_subsequence(arr2) expected_result = [10, 22, 9, 33, 31, 60] assert len(expected_result) == output arr3 = ODA(int, [1, 2, 3, 4, 5, 6, 7, 8, 9]) - output: OneDimensionalArray = longest_alternating_subsequence(arr3) + output: int = longest_alternating_subsequence(arr3) expected_result = [1, 2] assert len(expected_result) == output arr4 = ODA(int, [9, 8, 7, 6, 5, 4, 3, 2, 1]) - output: OneDimensionalArray = longest_alternating_subsequence(arr4) + output: int = longest_alternating_subsequence(arr4) expected_result = [9, 8] assert len(expected_result) == output arr5 = ODA(int, [1, 5, 4, 3, 2, 1, 6, 7, 8, 9]) - output: OneDimensionalArray = longest_alternating_subsequence(arr5) + output: int = longest_alternating_subsequence(arr5) expected_result = [1, 5, 4, 6] assert len(expected_result) == output From 8c006f8ef524f213b95cd98f8f2171e9da506663 Mon Sep 17 00:00:00 2001 From: FamALouiz Date: Tue, 11 Mar 2025 12:44:06 +0100 Subject: [PATCH 8/9] Updated longest alternating subsequence to return actual subsequence --- .../linear_data_structures/algorithms.py | 21 +++++--- .../tests/test_algorithms.py | 49 ++++++++++++------- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index 38c55b464..1ac3c5d12 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -1881,11 +1881,11 @@ def longest_alternating_subsequence(array: OneDimensionalArray, **kwargs) -> int >>> arr = OneDimensionalArray(int, [1, 5, 4]) >>> las = longest_alternating_subsequence(arr) >>> las - 3 + [1, 5, 4] >>> arr = OneDimensionalArray(int, [1, 5, 4, 3, 2, 6, 7]) >>> las = longest_alternating_subsequence(arr) >>> las - 4 + [1, 5, 2, 7] References ========== @@ -1900,8 +1900,12 @@ def longest_alternating_subsequence(array: OneDimensionalArray, **kwargs) -> int raise_if_backend_is_not_python( longest_alternating_subsequence, kwargs.get('backend', Backend.PYTHON)) - increasing = 1 - decreasing = 1 + # Edge case + if len(array) == 0: + return OneDimensionalArray(int, []) + + increasing = [array[0]] + decreasing = [array[0]] n = len(array) # Iterate from second element @@ -1909,11 +1913,14 @@ def longest_alternating_subsequence(array: OneDimensionalArray, **kwargs) -> int # Increasing changes if decreasing changes if (array[i] > array[i-1]): - increasing = decreasing + 1 + increasing = decreasing + [array[i]] # Decreasing changes if increasing changes elif (array[i] < array[i-1]): - decreasing = increasing + 1 + decreasing = increasing + [array[i]] # Return the maximum length - return max(increasing, decreasing) + if len(increasing) > len(decreasing): + return OneDimensionalArray(int, increasing) + else: + return OneDimensionalArray(int, decreasing) diff --git a/pydatastructs/linear_data_structures/tests/test_algorithms.py b/pydatastructs/linear_data_structures/tests/test_algorithms.py index 3e0e1ebcc..acdf9090a 100644 --- a/pydatastructs/linear_data_structures/tests/test_algorithms.py +++ b/pydatastructs/linear_data_structures/tests/test_algorithms.py @@ -420,26 +420,41 @@ def test_longest_alternating_subsequence(): ODA = OneDimensionalArray arr1 = ODA(int, [-4, 3, -5, 9, 10, 12, 2, -1]) - output: int = longest_alternating_subsequence(arr1) - expected_result = [3, -5, 9, 2, -1] - assert len(expected_result) == output + output: OneDimensionalArray = longest_alternating_subsequence(arr1) + expected_result = [-4, 3, -5, 12, -1] + assert str(expected_result) == str(output) arr2 = ODA(int, [10, 22, 9, 33, 49, 50, 31, 60]) - output: int = longest_alternating_subsequence(arr2) - expected_result = [10, 22, 9, 33, 31, 60] - assert len(expected_result) == output + output: OneDimensionalArray = longest_alternating_subsequence(arr2) + expected_result = [10, 22, 9, 50, 31, 60] + assert str(expected_result) == str(output) arr3 = ODA(int, [1, 2, 3, 4, 5, 6, 7, 8, 9]) - output: int = longest_alternating_subsequence(arr3) - expected_result = [1, 2] - assert len(expected_result) == output + output: OneDimensionalArray = longest_alternating_subsequence(arr3) + expected_result = [1, 9] + assert str(expected_result) == str(output) arr4 = ODA(int, [9, 8, 7, 6, 5, 4, 3, 2, 1]) - output: int = longest_alternating_subsequence(arr4) - expected_result = [9, 8] - assert len(expected_result) == output - - arr5 = ODA(int, [1, 5, 4, 3, 2, 1, 6, 7, 8, 9]) - output: int = longest_alternating_subsequence(arr5) - expected_result = [1, 5, 4, 6] - assert len(expected_result) == output + output: OneDimensionalArray = longest_alternating_subsequence(arr4) + expected_result = [9, 1] + assert str(expected_result) == str(output) + + arr5 = ODA(int, [1, 5, 4, 3, 2, 6, 7]) + output: OneDimensionalArray = longest_alternating_subsequence(arr5) + expected_result = [1, 5, 2, 7] + assert str(expected_result) == str(output) + + arr6 = ODA(int, [1, 5, 4]) + output: OneDimensionalArray = longest_alternating_subsequence(arr6) + expected_result = [1, 5, 4] + assert str(expected_result) == str(output) + + arr7 = ODA(int, []) + output: OneDimensionalArray = longest_alternating_subsequence(arr7) + expected_result = [] + assert str(expected_result) == str(output) + + arr8 = ODA(int, [1]) + output: OneDimensionalArray = longest_alternating_subsequence(arr8) + expected_result = [1] + assert str(expected_result) == str(output) From 74a1a80cee34125f0e1b5d1e3736fba64aebcaa8 Mon Sep 17 00:00:00 2001 From: FamALouiz Date: Tue, 11 Mar 2025 12:52:31 +0100 Subject: [PATCH 9/9] Updated example in function docstring --- pydatastructs/linear_data_structures/algorithms.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index 1ac3c5d12..a9c0708f7 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -1880,12 +1880,12 @@ def longest_alternating_subsequence(array: OneDimensionalArray, **kwargs) -> int >>> from pydatastructs import OneDimensionalArray, longest_alternating_subsequence >>> arr = OneDimensionalArray(int, [1, 5, 4]) >>> las = longest_alternating_subsequence(arr) - >>> las - [1, 5, 4] + >>> str(las) + '[1, 5, 4]' >>> arr = OneDimensionalArray(int, [1, 5, 4, 3, 2, 6, 7]) >>> las = longest_alternating_subsequence(arr) - >>> las - [1, 5, 2, 7] + >>> str(las) + '[1, 5, 2, 7]' References ==========