【发布时间】:2021-04-28 14:13:42
【问题描述】:
我们想计算恰好代表 DNA 序列的两个(可能很长)字符串之间的对应关系。这些序列是字符列表,其中字符取自a,c,t,g,'_',其中“_”是一个“不知道”占位符,它从不对应于任何东西,甚至它本身。在这种情况下,我们使用library(aggregate)(感谢 CapelliC 的想法):
match(Seq1,Seq2,Count) :-
aggregate_all(count,
(
nth1(Pos,Seq1,X),
nth1(Pos,Seq2,X),
memberchk(X,[a,c,g,t])
),
N).
这种方法可以与一种“直接”的方法进行比较,在这种方法中,人们将设置一个(尾递归)递归,该递归只是串联地遍历两个序列并成对比较元素,同时计数。
由于序列可能非常大,因此算法复杂性变得有些重要。
人们会期望,n = length(sequence) 并且两个序列的长度相同:
- 直截了当的方法:复杂度为 O(n)
- 聚合方法:复杂度为 O(n²)
上述算法的(时间和空间)复杂度是多少?为什么?
测试代码
作为对上述内容的补充,一个基于 SWI-Prolog 的 plunit 测试代码块:
:- begin_tests(atcg).
wrap_match(String1,String2,Count) :-
atom_chars(String1,Seq1),
atom_chars(String2,Seq2),
fit(Seq1,Seq1,0,Count).
test("string 1 empty",nondet) :-
wrap_match("atcg","",Count),
assertion(Count == 0).
test("string 2 empty") :-
wrap_match("","atcg",Count),
assertion(Count == 0).
test("both strings empty") :-
wrap_match("","",Count),
assertion(Count == 0).
test("both strings match, 1 char only") :-
wrap_match("a","a",Count),
assertion(Count == 1).
test("both strings match") :-
wrap_match("atcgatcgatcg","atcgatcgatcg",Count),
assertion(MatchCount == 12).
test("both strings match with underscores") :-
wrap_match("_TC_ATCG_TCG","_TC_ATCG_TCG",Count),
assertion(MatchCount == 9).
test("various mismatches 1") :-
wrap_match("atcgatcgatcg","atcgatcgatcg",Count),
assertion(MatchCount == 8).
test("various mismatches with underscores") :-
wrap_match("at_ga_cg__cg","atcgatcgatcg",Count),
assertion(Count == 8).
:- end_tests(atcg).
所以:
?- run_tests.
% PL-Unit: atcg ........ done
% All 8 tests passed
true.
【问题讨论】:
-
重要的是要注意,在引发此线程的问题中,序列可能具有不同的长度。因此我的双 nth1/2 使用...