算法 - 区分一组给定二进制数的最小位数

时间:2016-05-18 08:52:27

标签: algorithm

假设我们有K个不同的二进制数,每个二进制数的长度为NN可能很大)。是否有一种有效的算法来确定将这些数字相互区分所需的最小位数?

例如:

鉴于110011,我们只需检查第一个(或最后一个)位以区分它们,因此最小数字为1

鉴于1000010000100001,我们需要检查至少三位来区分,因此最小数字为3

鉴于0000010010001100,我们只需检查前两位,因此最小数字为2。< / p>

跟进:输出要检查的相应索引。

编辑:假设这些二进制数表示为a1[0,1,…,N-1],...,aK[0,1,…,N-1]。此问题等同于查找[i,j,…,m]的最小子序列[0,1,…,N-1],以便a1[i,j,…,m],...,aK[i,j,…,m]是不同的数字。

4 个答案:

答案 0 :(得分:1)

Set Cover是根据集合 U U 子集的 S 集合定义的。 U 中的每个元素必须由 S 中的(至少)一个集合覆盖。

如果您可以解决Set Cover,也可以解决此问题。假设您构建了一个 U 集合,其中每个条目 u i,j (其中 i&lt; j ),对应于 k 数字的对(i,j)(j,i)(因此 | U | = k (k - 1)/ 2 )。现在构建 n 集, S 1 ,...,S n ,对应 n 可能的位置。设置 S j 是对应于位置 j 的所有元素的子集。也就是说,如果数字 k,l 的位置 j 不同,则设置 u k,l ∈S j

因此,simple greedy algorithm for set cover可以给出最小位数的有界近似值。不幸的是,它不会为您提供最小位数。正如@augurar在评论中指出的那样,这个问题是NP-Hard的减少,因此,可能没有可行的精确最优算法。

答案 1 :(得分:0)

编辑:误解了这个问题,方案无效。

你想要做的是某种异或。但不是简单地完全删除所有数字。但是如果你能产生一个二进制数,当它是一个相关的位时,它就是1,如果这个位是不相关的,那么就是0。无关的位是总是具有相同值的位,无论数字是什么:您不需要它来区分数字。例如:

11001
01001
10101
-----
11100

第一位和第二位无关,因为它们总是具有相同的值。

怎么做

为此你需要从你的集合中计算两个二进制数。第一个是所有数字之间的逻辑或。仍为0的位无关紧要,很容易看到。第二个数字是集合中所有数字的逻辑AND。留给1的位是无关紧要的,它也很容易看到。现在,将这两个数字混合在一起。这是你的结果。应用于前一个示例:

11001 | 01001 | 10101 = 11101
11001 & 01001 & 10101 = 00001
11101 ^ 00001 = 11100 // Here is your result, the first 3 bits are relevant

答案 2 :(得分:0)

解决方案必须位于[log2(K), K-1]范围内。 log2(K)是最好的情况。所以一个强力方法可能是迭代这个范围,每次迭代都采用每个可能的位组合,直到它区分所有K个字符串。但时间复杂度可能是指数级的。

答案 3 :(得分:0)

我在创建哈希映射算法(https://github.com/robert-king/my-hash-map

时解决了这个问题

我的解决方案是使用线性整数编程。如果第i位重要则让Xi为1,否则为零。然后对于具有第i位和第i位的每一对数字A和B,我们需要Sum(Xi,Ai!= Bi)> = 1,这样我们就可以区分A和B.目标函数是最小化Sum( Xi),从而最小化位数。

性能:对于最多100个随机数,它需要一秒钟。 150个随机数,需要10-20秒。 (不记得它们是32位还是64位数字。)

  package algorithms

import (
    "github.com/draffensperger/golp"
    "fmt"
)

const numOnes = uint64(19)
const ones = uint64(1 << numOnes - 1)

func diffBit(a, b, i uint64) bool {
    return (a >> i) & 1 != (b >> i) & 1
}

func differentBits(a, b uint64) (ints []uint64) {
    if a < b {
        a,b = b,a
    }
    for i := uint64(0); a >> i > 0; i++ {
        if diffBit(a, b, i) {
            ints = append(ints, i)
        }
    }
    return ints
}

func checkBitsDistinguishNums(nums []uint64, bits []uint16) bool {
    offsets := make(map[uint16]bool)
    for _, num := range nums {
        offset := bitScore(num, bits)
        _, ok := offsets[offset]
        if ok {
            return false
        }
        offsets[offset] = true
    }
    return true
}

func minimumDistinguishingBits(nums []uint64) (bits []uint16) {
    if len(nums) == 1 {
        return bits
    }

    var likelySolutions = [][]uint16{
        []uint16{0},
        []uint16{1},
        []uint16{2},
        []uint16{3},
        []uint16{4},
        []uint16{0,1},
        []uint16{0,2},
        []uint16{5},
        []uint16{1,2},
        []uint16{0,3},
        []uint16{6},
        []uint16{7},
        []uint16{8},
        []uint16{0,4},
        []uint16{1,3},
        []uint16{1,4},
        []uint16{2,3},
        []uint16{0,5},
        []uint16{2,4},
        []uint16{1,5},
        []uint16{0,1,2},
        []uint16{0,1,3},
        []uint16{2,5},
        []uint16{0,6},
        []uint16{0,7},
        []uint16{9},
        []uint16{0,2,3},
        []uint16{2,6},
        []uint16{1,7},
        []uint16{1,6},
        []uint16{3,5},
        []uint16{2,7},
        []uint16{10},
        []uint16{1,3,8},
        []uint16{4,7},
        []uint16{3,6},
        []uint16{0,2,11},
        []uint16{3,8},
        []uint16{1,2,5},
        []uint16{0,3,4},
        []uint16{0,1,12},
        []uint16{0,1,2,5},
        []uint16{4,6},
        []uint16{3,4},
        []uint16{0,10},
        []uint16{0,8},
        []uint16{0,1,4},
        []uint16{11},
        []uint16{1,2,3},
        []uint16{0,2,4},
        []uint16{1,2,9},
        []uint16{3,12},
    }

    for _, likelySolution := range likelySolutions {
        if checkBitsDistinguishNums(nums, likelySolution) {
            return likelySolution
        }
    }

    var equations [][]golp.Entry
    maxDiffBit := uint64(0)
    for i := range nums {
        for j := 0; j < i; j++ {
            var equation []golp.Entry
            for _, bit := range differentBits(nums[i], nums[j]) {
                if bit > maxDiffBit {
                    maxDiffBit = bit
                }
                equation = append(equation, golp.Entry{int(bit), 1})
            }
            equations = append(equations, equation)
        }
    }
    lp := golp.NewLP(0, int(maxDiffBit)+1)
    for _, equation := range equations {
        lp.AddConstraintSparse(equation, golp.GE, 1)
    }
    var objFn []float64
    for i := 0; i <= int(maxDiffBit); i++ {
        lp.SetInt(i, true)
        objFn = append(objFn, float64(i))
    }
    lp.SetObjFn(objFn)
    lp.Solve()
    for i, bit := range lp.Variables() {
        if bit == 1 {
            bits = append(bits, uint16(i))
        }
    }

    fmt.Println("Likely solution not found but found ", bits)

    return bits
}