| 3305 | def longest_common_subword(self,other): |
| 3306 | r""" |
| 3307 | Returns a longest subword of ``self`` and ``other``. |
| 3308 | |
| 3309 | For more information, see |
| 3310 | :wikipedia:`Longest_common_subsequence_problem`. |
| 3311 | |
| 3312 | INPUT: |
| 3313 | |
| 3314 | - ``other`` -- a word |
| 3315 | |
| 3316 | ALGORITHM: |
| 3317 | |
| 3318 | For any indices `i,j'`, we compute the longest common subword ``lcs[i,j]`` of |
| 3319 | `self[:i]` and `other[:j]`. This can be easily obtained as the maximum |
| 3320 | of |
| 3321 | |
| 3322 | - ``lcs[i-1,j]`` |
| 3323 | |
| 3324 | - ``lcs[i,j-1]`` |
| 3325 | |
| 3326 | - ``lcs[i-1,j-1]+1`` if ``self[i]==other[j]`` |
| 3327 | |
| 3328 | EXAMPLE:: |
| 3329 | |
| 3330 | sage: w1 = Word("1010101010101010101010101010101010101010") |
| 3331 | sage: w2 = Word("0011001100110011001100110011001100110011") |
| 3332 | sage: w1.longest_common_subword(w2) |
| 3333 | word: 00110011001100110011010101010 |
| 3334 | |
| 3335 | TESTS:: |
| 3336 | |
| 3337 | sage: Word().longest_common_subword(Word()) |
| 3338 | word: |
| 3339 | |
| 3340 | .. SEEALSO:: |
| 3341 | |
| 3342 | :meth:`is_subword_of` |
| 3343 | """ |
| 3344 | from sage.combinat.words.word import Word |
| 3345 | if len(self) == 0 or len(other) == 0: |
| 3346 | return Word() |
| 3347 | |
| 3348 | w2 = list(other) |
| 3349 | |
| 3350 | # In order to avoid storing lcs[i,j] for each pair i,j of indices, we |
| 3351 | # only store the lcs[i,j] for two consecutive values of i. At any step |
| 3352 | # of the algorithm, lcs[i,j] is stored at lcs[0][j] and lcs[-1,j] is |
| 3353 | # stored at lcs[1][j] |
| 3354 | l1 = self[0] |
| 3355 | |
| 3356 | # The weird +1 that follows exists to make sure that lcs[i,-1] returns |
| 3357 | # the empty word |
| 3358 | lcs = [[[] for i in range(len(w2)+1)] for j in range(2)] |
| 3359 | |
| 3360 | for i,l1 in enumerate(self): |
| 3361 | for j,l2 in enumerate(other): |
| 3362 | lcs[0][j] = max(lcs[0][j-1],lcs[1][j],lcs[1][j-1] + ([l1] if l1==l2 else []),key=len) |
| 3363 | |
| 3364 | # Maintaining the meaning of lcs for the next loop |
| 3365 | lcs.pop(1) |
| 3366 | lcs.insert(0,[[] for i in range(len(w2)+1)]) |
| 3367 | |
| 3368 | return Word(lcs[1][-2]) |
| 3369 | |