我试图找出如何使用golang对齐稍微不完美的二进制切片。以下四个切片均正确对齐不同的偏移量。但是,并非每个位都相同(标记如下),所以我不能只比较原始块。
func main() {
// Match all three slices up (ignoring occasional errors)
s1 := []int16{0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1}
s2 := []int16{ /* */ 0, 1, 1, 0, 0, 0, 1, 1, 1, 1}
// ^ ^
s3 := []int16{0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1}
// ^
s4 := []int16{ /* */ 0, 0, 0, 1, 1, 1, 0, 0}
slices := make([][]int16, 3)
slices = append(slices, s1, s2, s3, s4)
offsets := forgivingSyncHere(slices)
}
答案 0 :(得分:2)
这取决于你的成本"功能是,您的目标是最大限度地降低成本"。
成本函数可能是这样的。这个想法是"不匹配"比没有任何东西可以匹配更昂贵,我们称之为超支" (说成本高两倍)。取a[i] != b[i + offset]
a
和b
等于s1
,s2
,s3
,s4
并加倍的案例数量它。然后将每个配对的每个offset
的绝对值(在这种情况下为4个数组的6个配对)添加到开头的超出数量。然后在最后加上超支。
样本成本函数:
func cost(sn [][]int16, offsets [][]int) int {
// cost accumulator
c := 0.0
// the factor of how much more costly a mismatch is than an overrun
mismatchFactor := 2.0
// define what you want, but here is an example of what I said above
for i1:=0;i1<len(sn);i++ {
for i2:=i1+1;i2<len(sn);i2++ {
c += mismatchFactor * diff(sn[i1], sn[i2], offsets[i1][i2])
c += math.Abs(offsets[i1][i2])
c += math.Abs(len(sn[i1]) + offsets[i1][i2] - len(sn[i2]))
}
}
}
// offset of the offset of s1 wrt s2
func diff(s1 []int16, s2 []int16, offset int) int {
// index, index, diff total
i1,i2,d := 0,0,0
if offset >= 0 {
i1 += offset
} else {
i2 -= offset
}
while i1<len(s1) && i2<len(s2) {
if s1[i1] != s2[i2] {
d++
}
i1++
i2++
}
return d
}
根据需要制作成本函数,这只是一个例子。但是,假设您具有成本函数,则很容易想出一个强力算法。您可以尝试优化算法,但:)。有很多想法。这与字符串搜索算法非常相似,具有编辑距离。维基百科和谷歌有很多结果。
免责声明:所有这些都是未经测试的:),但它应该让你开始
答案 1 :(得分:0)
可以使用Levenshtein距离来描述相似性,也就是编辑距离 - 字符串必须经历的插入,删除和突变的数量才能成为另一个。
这允许您定量地讨论相似度,例如,编辑距离与两个字符串长度中较短的长度的比率可能是一个合理的度量,但这取决于您的确切意思相似。< / p>
从那里你可以找到每个要比较的字符串中相同子串的长度和数量的下限。在你的情况下,通过观察你的例子,看起来像4比特你认为匹配。 IOW,如果你使用4位块,并检查给定序列对的完全匹配,匹配块的数量会告诉你它们的相似性是什么?
如果你对足够小的子串做了精确的比较,你可以保证至少有几个匹配,即使差异是均匀的间隔(如果它们是聚类的,较大的部分将具有完全匹配,所以较短的长度)字符串除以最大编辑距离。)
考虑到相似性位置的字符串的通用近似匹配的精确解决方案是计算密集型的(并且相关且经过充分研究的问题是最长的公共子序列),并且还必须应用于每对序列比较,而不是每个序列独立。相反,选择适当的块大小并通过其可能的子串索引每个字符串仅取决于每个字符串的独立性,并且可以提供近似的答案。你当然可以注意到这个位置并进一步限制它。
总结一下,你所描述的问题的一个天真的解决方案可能是难以处理的,并且在实践中,序列对齐和近似字符串匹配是通过解决一个更简单的问题来完成的,然后用一个双重检查这些解决方案。更天真/更昂贵的方法。
Rabin指纹识别是将字符串分解为子串而不是n-gram(滑动窗口)的更复杂的方法,但它是随机方法并且导致可变大小的字符串(但是确定性的字符串),因此计算边界是更多参与。