问题:给定由1-n索引的两列数据,问是否存在两行的某两列列值完全相同,即k1.c1 = k2.c1且k1.c2 = k2.c2
办法1:对第一列排序(o(nlogn)),找到第一列中列值相同的(mi个)在第二列中根据相应索引取出所有值并排序(o(milogmi)),顺序找出值相同的(mi)。总时间复杂度为o(nlogn+∑(mi+milogmi+mi))=o(nlogn+2n+∑milogmi)=o(2nlogn)
办法2:对两列带上索引都排序(o(nlogn)),对每列的每个键值找出与它列值相同但键值最小的f[i]保存(o(n)).设一个标志数组tag[N],第一列中列值相同的,第二列根据键值得到f[i],判断tag[f[i]]是否被标记,如果被标记表示之前已经有相同的出现,找到这样的两行他们的这两列值相同,否则标记tag[f[i]]。每次处理完列值相同的一组数据m个,对tag恢复默认,即把修改过的m个重新恢复。总复杂度o(2nlogn+n*3).
http://poj.org/problem?id=3865
此题中含有m列,判断冗余,比如下标中2,3行的2,3列
How to compete in ACM ICPCPeterpeter@neerc.ifmo.ruHow to win ACM ICPCMichaelmichael@neerc.ifmo.ruNotes from ACM ICPC championMichaelmichael@neerc.ifmo.ru方法1超时:复杂度为o(m*nlogn)+C(m,2)*(2n+∑milogmi)=o(mnlogn+mmn+mmnlogn)=o(mmnlogn)
方法2勉强:复杂度o(m*nlogn+C(m,2)*n*3)=o(mnlogn+mmn)
上面把字符串的比较操作看作了1,此时m=10,n=10000,复杂度就是1为千万级,2为百万级。如果加上字符串比较操作可能还更长。如此看来2的复杂度比1低,表明处理两列时候1,2差不多,多列时候2更好。不知道还有什么好办法吗?
附方法2的计算代码:
struct Node
{
char s[LEN];
short row;
}node[M][N]; //M为列数,n为行数,row为初始给定的行号
void compute()
{
int i,j,k,u,l;
memset(tag,-1,sizeof(tag));
for(i = m-1;i >= 0;i --){
sort(node[i],node[i]+n,cmp);
f[i][node[i][0].row] = node[i][0].row;
for(j = 1;j < n;j ++)
{
if(strcmp(node[i][j].s,node[i][j-1].s) == 0)
f[i][node[i][j].row] = f[i][node[i][j-1].row];
else
f[i][node[i][j].row] = node[i][j].row;
}
for(j = i+1;j < m;j ++)
{
tag[f[i][node[j][0].row]] = node[j][0].row;
l = 0;
for(k = 1;k <= n;k ++)
{
if(strcmp(node[j][k].s,node[j][k-1].s) == 0)
{
if(tag[f[i][node[j][k].row]] != -1)
{
r1 = tag[f[i][node[j][k].row]]+1;
r2 = node[j][k].row+1;
c1 = j+1;
c2 = i+1;
return;
}
tag[f[i][node[j][k].row]] = node[j][k].row;
}
else{
for(u = k-1;u >= l;u --)
tag[f[i][node[j][u].row]] = -1;
tag[f[i][node[j][k].row]] = node[j][k].row;
l = k;
}
}
}
}
}