-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path1143-longest_common_subsequence.py
153 lines (120 loc) · 4.84 KB
/
1143-longest_common_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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
"""
https://leetcode.com/problems/longest-common-subsequence/
Applications:
"Finding the longest common subsequence between two strings is useful for
checking the difference between two files (diffing). Git needs to do this
when merging branches. It's also used in genetic analysis (combined with
other algorithms) as a measure of similarity between two genetic codes."
Note:
Should be able to use the built-in cache instead of memoing
(only works in python3 ???). import supposed to be:
# from functools import lru_cache
then
@lru_cache(maxsize=None)
# def lcs(idx1, idx2):
....
^doesn't work, check https://stackoverflow.com/questions/45819563/python-importerror-name-lru-cache
"""
class Solution(object):
"""
Recursive top-down attempt (dict to memoize)
Stats: O(len(text1) * len(text2)) aka O(n * m) time
Runtime: 2436 ms, faster than 5.16% of Python online submissions for Longest Common Subsequence.
Memory Usage: 151.2 MB, less than 5.04% of Python online submissions for Longest Common Subsequence.
"""
def longestCommonSubsequence(self, text1, text2):
"""
:type text1: str
:type text2: str
:rtype: int
"""
len1 = len(text1)
len2 = len(text2)
def lcs(idx1, idx2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
#iterated through one (or both) of the string(s)
if idx1 == len1 or idx2 == len2:
return 0
if memo.get((idx1, idx2)) > -1:
return memo[(idx1, idx2)]
#recursive cases
answer = 0
if text1[idx1] == text2[idx2]:
#chars matches
answer = 1 + lcs(idx1 + 1, idx2 + 1)
else:
#chars don't match, determine which string to move along on
call1 = lcs(idx1 + 1, idx2)
call2 = lcs(idx1, idx2 + 1)
answer = max(call1, call2)
#memoize the answer
memo[(idx1, idx2)] = answer
return answer
#--------------end helper function--------------
#don't know why 2d arrays to store answers don't work:
# memo = [[-1] * len(text2)] * len(text1)
# memo = [[-1] for _ in range(len2) for _ in range(len1)]
#use a dictionary for now, which works just as well
memo = {}
return lcs(0, 0)
"""
Bottom-up tabulation with 2d array
Stats: O(n * m) time, O(n * m) space
Runtime: 356 ms, faster than 66.86% of Python online submissions for Longest Common Subsequence.
Memory Usage: 21.5 MB, less than 26.95% of Python online submissions for Longest Common Subsequence.
"""
def longestCommonSubsequence(self, text1, text2):
"""
:type text1: str
:type text2: str
:rtype: int
"""
len1 = len(text1) + 1
len2 = len(text2) + 1
memo = [[0 for i in range(len2)] for j in range(len1)]
# memo = [[0] * (len2)] * (len1)
#for some reason, ^ doesn't work for some cases...
for i in range(1, len1):
for j in range(1, len2):
if text1[i - 1] == text2[j - 1]:
memo[i][j] = memo[i - 1][j - 1] + 1
else:
memo[i][j] = max(memo[i][j - 1], memo[i - 1][j])
return memo[-1][-1]
"""
Bottom-up tabulation with 1d array
Inspired by: https://leetcode.com/problems/longest-common-subsequence/discuss/473089/Python-DP-with-T(n)-O(nm)-and-S(n)-O(m)
Note:
The array will be allocated with length of the shorter word
iceberg vs pine --> 7 x 4
Stats: O(n * m) time, O(min(n, m))
Runtime: 300 ms, faster than 92.66% of Python online submissions for Longest Common Subsequence.
Memory Usage: 12.7 MB, less than 97.13% of Python online submissions for Longest Common Subsequence.
"""
def longestCommonSubsequence(self, text1, text2):
"""
:type text1: str
:type text2: str
:rtype: int
"""
#puts the shorter text in text2
if len(text1) < len(text2):
text1, text2 = text2, text1
len1 = len(text1) + 1
len2 = len(text2) + 1
memo = [0] * len2
for i in range(1, len1):
prev_diagonal = 0
for j in range(1, len2):
temp = memo[j]
if text1[i - 1] == text2[j - 1]:
memo[j] = prev_diagonal + 1
else:
memo[j] = max(memo[j - 1], memo[j])
prev_diagonal = temp
# print(memo)
return memo[-1]