回 帖 发 新 帖 刷新版面

主题:又一个比较难的问题 ,有谁来挑战

有一个字符串数组String []a元素个数为(N=1000000左右)
比如a[0]=abs|fgh (其中|是分隔符)
    a[1]=afg|afadfas|jf
    .
    .
    .
    a[i]=fgh|abs|mnb|ad
    a[i+1]=fdafdaf|fadfa|xyz
    .
    .
    .
    a[N-1]=xyz|fadfa...

如果第i个元素的字符串(以|为分隔符号)包含其他N-1个元素,则去掉a[i]元素.

比如a[i]中有fgh,abs, mnb,ad,包含了a【0】中的元素abs,fgh;则去掉a[i]元素
a[i+1]中有fdafdaf,fadfa,xyz,包含了a[N-1]中的元素xyz,fadfa,则去掉a[i+1]个元素.

这个题目的时间复杂度最小为多少,具体如何实现. 我做得为O(n^2) ,但导师说不是最小,谁能看看

回复列表 (共8个回复)

沙发

这个题目中,字符串的个数比较大,如果用常规的方法:需要
 1。通过查找|,切分字符串,生成一个字符串表。
 2。比较所有字符串中是否有重复的串,则这个代价太大了。

  一个更好的方法,写一个hash函数,对每个字符串求出键值,建立一个hash表,则相同的字符串其键值一定相同,查找重复串可以在键值相同的串中进行,这样速度将大大提高。


板凳

我有点不懂,比如a[0]=abs|fgh,a[i]=fgh|abs|mnb|ad
a[i]包括a[0]中所有的元素,他们的hash值不一定相同

3 楼

用hash的话,一次遍历就行了!very good!

下面是云风wiki上给的一段字符串hash算法:
unsigned long hash(const char *name,size_t len)
{
    unsigned long h=(unsigned long)len;
    size_t step = (len>>5)+1;
    for (size_t i=len; i>=step; i-=step)
        h = h ^ ((h<<5)+(h>>2)+(unsigned long)name[i-1]);
    return h;
}

4 楼

我有点不懂,比如a[0]=abs|fgh,a[i]=fgh|mnb|ad|abs
a[i]包括a[0]中所有的元素,他们的hash值不一定相同

能不能弄点完整的代码,这个代码还是不太明白啊

5 楼

这个和你前面问的那个题差不多嘛,一般的思路是,取一个元素出来,然后从其它的元素中一个一个试着找满足条件的情况以决定是否删掉当前这个元素,这样做复杂度都是O(n*n),实际上不用这样做,为每个元素设一个访问标记v[]以表示集合S={a[i]|v[i]==0},一开始v[]全为0表示所有元素都在S中,然后循环执行:
1,从S中取一个元素a[i],考查每一个S中剩余的元素a[k],如果a[i]|a[k](|为一个偏序关系,包括整数的整除关系,字符串的包含关系等都是)那就从S中去掉a[k],也就是1->v[k]
2,一直到S中所有元素都考虑完,S就是所求.
这样做复杂度就会有所下降

6 楼


如果所有的元素都没有包含关系,还是O(n^2)啊

7 楼

int hashtab[LIMIT] = {0};
char tmpstr[MAX];
int k = 0;

for (i = 0; i < N; ++i) {
    int pos;

    for (j = 0; a[j] != '\0'; ++j)
        if (a[j] != '|')
            tmpstr[k++] = a[j];
        else {
            tmpstr[k] = '\0';
            pos = hash (tmpstr, k); //可以用上面那个函数
            if (hashtab[pos] == 1) {
                a[i] = '\0';  //消除a[i]这一行
                break;
            }
            else hashtab[pos] = 1;
        }    
}

好像要找个很大的空间放hash表.

8 楼


问题已经解决,谢谢各位的帮忙

我最后用树型结构解决,400000条记录需要7秒钟,基本能满足,以后还有更好的,请给我发短消息.

我来回复

您尚未登录,请登录后再回复。点此登录或注册