包含来自给定集合的所有字符串的最佳字符串作为子字符串

时间:2012-04-23 18:16:01

标签: c string algorithm optimization

我正在使用一些需要大(常量)位数组的代码。由于它包含大的常量跨度(全0或全1),我将其分解为两级表,允许重复跨度(常量或其他),如:

bitn = table2[table1[n/256]+n%256/8]&1<<n%8

此时,table1的条目都是32(256位)的倍数,但我想知道通过允许table2中的跨度重叠可以实现显着的节省。所以我的问题是(以摘要形式陈述):

给定长度为K的N个字符串{S_n:n = 1..N},是否有一种有效的方法来找到最短长度的字符串S,使得每个S_n是S的子字符串?

(注意,因为我可能想让我的位数组保持8位对齐,我对该问题的特定应用可能会处理8位字节的字符串而不是字符串的字符串,但问题在任何问题上都有意义字符感 - 位,字节或其他。)

2 个答案:

答案 0 :(得分:1)

首先,这个问题可以表述为TSP。我们有一组节点(每个字符串都是一个节点),我们需要找到访问所有节点的路径。字符串x和y之间的距离定义为len(xy)+ len(y),其中xy是具有x和y的最佳字符串,并且以x开头(例如,x = 000111,y = 011100,xy = 0001100 ,距离(x,y)= 8-6 = 2)。

注意,这也服从三角不等式(距离(x,z)&lt; =距离(x,y)+距离(y,z))。距离是从1到k的整数。此外,距离是不对称的。

此版本的TSP称为(1,B)-ATSP。有关此类问题和近似解决方案的分析,请参阅http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.20.3439

答案 1 :(得分:1)

与具有大部分常量的大型常量位数组有关,这里是设计表的另一种方法供您考虑(我不知道您的确切需求,所以我不能说它是否会有所帮助或不是)。

考虑类似radix tree的内容。为了便于解释,让我定义get函数:

#define TYP_CONST
#define TYP_ARRAY

struct node {
    unsigned min;
    unsigned max;
    int typ;
    union {
        char *bits;
        int constant;
    } d;
    struct node *left;
    struct node *right;
}

struct bit_array {
    unsigned length;
    struct node *root;
}

int get(struct bit_array *b, unsigned ix)
{
    struct node *n = b->root;
    if (ix >= b->length)
        return -1;
    while (n) {
        if (ix > n->max) {
            n = n->right;
            continue;
        } else if (ix < n->min) {
            n = n->left;
            continue;
        }
        if (n->typ == TYP_CONST)
            return n->d.constant;
        ix -= n->min;
        return !!(n->d.bits[ix/8] & (1 << ix%8));
    }
    return -1;
}

从人类的角度来说,你想在树上寻找你的位。每个节点都负责一系列位,您可以通过范围进行二进制搜索,以找到所需的范围。

找到范围后,有两个选项:常量或数组。如果不变,只需返回常量(为您节省大量内存)。如果是数组,则在位数组中进行数组查找。

你将有O(log n)查询时间而不是O(1)....虽然它应该仍然非常快。

这里的困难在于设置适当的数据结构很烦人且容易出错。但是你说阵列是不变的,所以这可能不是问题。