-
Notifications
You must be signed in to change notification settings - Fork 1
/
longest_increasing_subsequence.py
128 lines (104 loc) · 4.39 KB
/
longest_increasing_subsequence.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
from typing import List
class Solution:
"""
Given an integer array nums, return the length of the longest strictly increasing subsequence.
A subsequence is a sequence that can be derived from an array by deleting some or no elements without changing the
order of the remaining elements. For example, [3,6,2,7] is a subsequence of the array [0,3,1,6,2,2,7].
"""
def __init__(self):
"""
Initialise the solution.
"""
self.max_length = 0
def lengthOfLIS_naive_memo(self, nums: List[int]) -> int:
"""
Given an integer array nums, return the length of the longest strictly increasing subsequence.
This is the brute force approach with memoization.
:param nums: The input array.
:type nums: List[Int].
:return: The longest increasing subsequence.
:rtype: Int.
The time complexity is N^2 where N is the length of the nums. This solution results in time limit exceeded.
The space complexity is O(N) for the memoization array. This solution results in time limit exceeded.
"""
LIS = 0
for i in range(len(nums)):
LIS = max(LIS, self.dfs(i, nums, [0] * len(nums)))
return LIS
def dfs(self, i: int, nums: List[int], memo: List[int]) -> int:
"""
A helper method to find the length of the longest increasing subsequence.
:param i: The current index.
:type i: Int.
:param nums: The input array.
:type nums: List[Int].
:param memo: The memoization array.
:type memo: List[Int].
:return: The LIS at this index.
:rtype: Int.
"""
# base case
if i == len(nums):
return 0
# use the cache
if memo[i] > 0:
return memo[i]
LIS = 0
for j in range(i + 1, len(nums)):
if nums[i] < nums[j]:
LIS = max(LIS, self.dfs(j, nums, memo))
memo[i] = LIS + 1
return LIS + 1
def lengthOfLIS_naive(self, nums: List[int]) -> int:
"""
Given an integer array nums, return the length of the longest strictly increasing subsequence.
This is the brute force approach.
:param nums: The input array.
:type nums: List[Int].
:return: The longest increasing subsequence.
:rtype: Int.
The time complexity is 2^N where N is the length of the nums. This solution results in time limit exceeded.
The space complexity is O(N) for the current_list. This solution results in time limit exceeded.
"""
# consider the substring beginning at each index
for i in range(len(nums)):
self.dfs_naive(nums, [nums[i]], i)
return self.max_length
def dfs_naive(self, nums: List[int], current_list: List[int], i: int):
"""
A helper method to find the length of the longest increasing subsequence.
:param nums: The input array.
:type nums: List[Int].
:param current_list: The current list.
:type current_list: List[Int].
:param i: The index that the current list starts from.
:type i: Int.
:return: NoneType.
:rtype: NoneType.
"""
self.max_length = max(len(current_list), self.max_length)
if i == len(nums):
return
# consider the rest of the string starting at i
for j in range(i + 1, len(nums)):
# at every index we can add or not add the value
if nums[i] < nums[j]:
current_list.append(nums[j])
self.dfs_naive(nums, current_list, j)
current_list.remove(nums[j])
def lengthOfLIS_iterative(self, nums: List[int]) -> int:
"""
Given an integer array nums, return the length of the longest strictly increasing subsequence.
:param nums: The input array.
:type nums: List[Int].
:return: The longest increasing subsequence.
:rtype: Int.
The time complexity is O(N^2) as we use a nested for loop. Faster than 53.67% of solutions.
The space complexity is O(N) to hold the LIS array. Less memory than 45.00% of solutions.
"""
LIS = [1] * len(nums)
for i in range(len(nums) - 1, -1, -1):
for j in range(i + 1, len(nums)):
if nums[i] < nums[j]:
LIS[i] = max(LIS[i], 1 + LIS[j])
return max(LIS)