diff --git a/pydatastructs/linear_data_structures/__init__.py b/pydatastructs/linear_data_structures/__init__.py index 5f36a8ae8..64fbbfb3b 100644 --- a/pydatastructs/linear_data_structures/__init__.py +++ b/pydatastructs/linear_data_structures/__init__.py @@ -35,6 +35,7 @@ longest_common_subsequence, is_ordered, upper_bound, - lower_bound + lower_bound, + longest_increasing_subsequence ) __all__.extend(algorithms.__all__) diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index a82abbdc7..0a2d6de7a 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -15,9 +15,10 @@ 'cocktail_shaker_sort', 'quick_sort', 'longest_common_subsequence', + 'is_ordered', 'upper_bound', 'lower_bound', - 'is_ordered' + 'longest_increasing_subsequence' ] def _merge(array, sl, el, sr, er, end, comp): @@ -978,3 +979,62 @@ def lower_bound(array, value, **kwargs): index = mid inclusive_end = mid - 1 return index + +def longest_increasing_subsequence(array): + """ + Returns the longest increasing subsequence (as a OneDimensionalArray) that + can be obtained from a given OneDimensionalArray. A subsequence + of an array is an ordered subset of the array's elements having the same + sequential ordering as the original array. Here, an increasing + sequence stands for a strictly increasing sequence of numbers. + + Parameters + ========== + + array: OneDimensionalArray + The given array in the form of a OneDimensionalArray + + Returns + ======= + + output: OneDimensionalArray + Returns the longest increasing subsequence that can be obtained + from the given array + + Examples + ======== + + >>> from pydatastructs import lower_bound, OneDimensionalArray as ODA + >>> from pydatastructs import longest_increasing_subsequence as LIS + >>> array = ODA(int, [2, 5, 3, 7, 11, 8, 10, 13, 6]) + >>> longest_inc_subsequence = LIS(array) + >>> longest_inc_subsequence + [2, 3, 7, 8, 10, 13] + >>> array2 = ODA(int, [3, 4, -1, 5, 8, 2, 2 ,2, 3, 12, 7, 9, 10]) + >>> longest_inc_subsequence = LIS(array2) + >>> longest_inc_subsequence + [-1, 2, 3, 7, 9, 10] + """ + n = len(array) + dp = [0]*n + parent = [-1]*n + length = 0 + for i in range(1, n): + if array[i] <= array[dp[0]]: + dp[0] = i + elif array[dp[length]] < array[i]: + length += 1 + dp[length] = i + parent[i] = dp[length - 1] + else: + curr_array = [array[dp[i]] for i in range(length)] + ceil = lower_bound(curr_array, array[i]) + dp[ceil] = i + parent[i] = dp[ceil - 1] + ans = [] + + last_index = dp[length] + while last_index != -1: + ans[:0] = [array[last_index]] + last_index = parent[last_index] + return ans diff --git a/pydatastructs/linear_data_structures/tests/test_algorithms.py b/pydatastructs/linear_data_structures/tests/test_algorithms.py index a0b98bb6a..bd1cad837 100644 --- a/pydatastructs/linear_data_structures/tests/test_algorithms.py +++ b/pydatastructs/linear_data_structures/tests/test_algorithms.py @@ -1,8 +1,10 @@ from pydatastructs import ( merge_sort_parallel, DynamicOneDimensionalArray, OneDimensionalArray, brick_sort, brick_sort_parallel, - heapsort, matrix_multiply_parallel, counting_sort, bucket_sort, cocktail_shaker_sort, quick_sort, longest_common_subsequence, - is_ordered, upper_bound, lower_bound) + heapsort, matrix_multiply_parallel, counting_sort, bucket_sort, + cocktail_shaker_sort, quick_sort, longest_common_subsequence, is_ordered, + upper_bound, lower_bound, longest_increasing_subsequence) + from pydatastructs.utils.raises_util import raises import random @@ -241,3 +243,31 @@ def test_lower_bound(): output = lower_bound(arr8, 6, end=3, comp=lambda x, y: x > y) expected_result = 1 assert expected_result == output + +def test_longest_increasing_subsequence(): + ODA = OneDimensionalArray + + arr1 = ODA(int, [2, 5, 3, 7, 11, 8, 10, 13, 6]) + output = longest_increasing_subsequence(arr1) + expected_result = [2, 3, 7, 8, 10, 13] + assert expected_result == output + + arr2 = ODA(int, [3, 4, -1, 5, 8, 2, 2, 2, 3, 12, 7, 9, 10]) + output = longest_increasing_subsequence(arr2) + expected_result = [-1, 2, 3, 7, 9, 10] + assert expected_result == output + + arr3 = ODA(int, [6, 6, 6, 19, 9]) + output = longest_increasing_subsequence(arr3) + expected_result = [6, 9] + assert expected_result == output + + arr4 = ODA(int, [5, 4, 4, 3, 3, 6, 6, 8]) + output = longest_increasing_subsequence(arr4) + expected_result = [3, 6, 8] + assert expected_result == output + + arr5 = ODA(int, [7, 6, 6, 6, 5, 4, 3]) + output = longest_increasing_subsequence(arr5) + expected_result = [3] + assert expected_result == output