rosalind.info_problems_itwv_.png

1. 暴力滑窗+子序列验证【错误】

最最粗暴的方法就是使用 Finding Disjoint Motifs in a Gene - 图2时间生成motif1 + motif2的所有interwoven可能,然后再使用KMP在DNA中查找是否出现,单次两motif组合检查时间复杂度为 Finding Disjoint Motifs in a Gene - 图3,其中共有n个motif,两两组合大约有 Finding Disjoint Motifs in a Gene - 图4个,所以总时间复杂度为 Finding Disjoint Motifs in a Gene - 图5

我的想法:
使用长度为|u|+|t|的滑动窗口记录s子串字符出现个数cnt,若该窗口内字符出现个数等于u,t字符出现个数时,通过删除子序列u得到剩余字符组合后是否等于t 来判断。

  1. import sys
  2. from typing import List
  3. stdin = sys.stdin
  4. DNA = stdin.readline().strip()
  5. motifs = [motif.strip() for motif in stdin if motif.strip()]
  6. print(DNA, motifs)
  7. def check(s: str, motif1: str, motif2: str) -> bool:
  8. n, m = len(s), len(motif1)
  9. match = [True] * n
  10. i = j = 0
  11. while i < n and j < m:
  12. if s[i] == motif1[j]:
  13. j += 1
  14. match[i] = False # 其中一个使用删除它
  15. i += 1
  16. return j == m and ''.join(s[i] for i, v in enumerate(match) if v) == motif2
  17. def disjointMotifs(DNA: str, motifs: List[str]) -> int:
  18. """枚举motif组合,使用滑动窗口在DNA找这个可能组合,使用子序列验证"""
  19. n = len(motifs)
  20. ans = [[0] * n for _ in range(n)]
  21. from collections import Counter
  22. for i in range(n):
  23. for j in range(i, n):
  24. motif = Counter(motifs[i] + motifs[j])
  25. # 初始化长度为 K-1 的滑窗
  26. K = len(motifs[i]) + len(motifs[j])
  27. window = Counter()
  28. for k in range(K - 1):
  29. window[DNA[k]] += 1
  30. for k in range(K - 1, len(DNA)):
  31. window[DNA[k]] += 1 # 滑入 DNA[k] 元素
  32. # 检测该窗口字符是否是 Disjoint Motifs 组合
  33. if window == motif and check(DNA[k-K+1:k+1], motifs[i], motifs[j]):
  34. ans[i][j] = ans[j][i] = 1
  35. break
  36. window[DNA[k - K + 1]] -= 1 # 滑出 DNA[k - K + 1] 元素
  37. if 0 == window[DNA[k - K + 1]]: # 删除出现次数为零
  38. window.pop(DNA[k - K + 1])
  39. return ans
  40. for lst in disjointMotifs(DNA, motifs):
  41. for x in lst:
  42. print(x, end=' ')
  43. print()

但是上面判断子序列组成上出错了:例如s = 'CCACGCA', t = 'CCGC', u = 'CAA' 使用上面的check 函数输出为 False。下面在s串底部分别使用^, &表示其构成t, u串字符。

  1. 我的结果:
  2. C C A C G C A
  3. ^ ^ $ $ ^ ^ $
  4. 预期结果:
  5. C C A C G C A
  6. ^ $ $ ^ ^ ^ $

问题:上面check函数每次只取匹配的最左侧字符造成不匹配,难道需要枚举出所有位置组合的子序列挨个检测有效性吗?

paper: