您的位置:首页 > 其它

m个珠子共n种颜色,找出包含n种颜色的最短连续片段

2012-10-12 19:34 375 查看
转载:/article/2400511.html

分享百度一个面试题:

有一串珠子首尾不相连,总共N个,这些珠子总共有M种颜色,在这串珠子里面找到最短的连续珠子子串,使子串出现所有的M种颜色。

毫无疑问,这个可以用暴力破解,N^2 时间效率可以解决,面试官百分之一千会让你优化。

设置两个位置指针 t 和 h ,代表出现所有颜色的联系珠子的子串的起始位置和最后位置

如果能保证 h 所指的位置的珠子是第一次出现,如果尽量将 t 向前移动,得到的 t - h 的子串就是以 h 结尾子串的最短子串

在什么情况下,能向前移动 t 呢?

如果说 t 位置所指的颜色,在 t+1~h之间还有出现,就能保证 t 可以向前移一个位置

比如珠子是:11232324314,最短子串是 2431

第一次找到所有颜色的子串是 11232324,子串最后颜色 4 是子串中唯一出现的颜色

此时的 t 指向 第一个 1,而 1 在后面还有出现,可以将 t 向前移动一个 即得到更短的子串 1232324

还能再移吗?不能了,因为此时 颜色 1 在这个子串中唯一,也就是说 以 h(指向子串最后一个4)结尾的子串,要包含所有颜色1234那么最短的子串是 1232324

得到的这个子串是所有包含所有颜色子串最短的吗?也不是,那么我们该怎么找到下一个包含所有颜色的子串?

假设,我删除掉获得的子串 1232324 的第一个 颜色 1,再从后边的珠子里找到颜色 1 ,即 23232431,此时 最后的颜色 1 又是这个子串唯一的颜色了

同样的方法,只要后面还有和 当前 t 指向的颜色,那么就移动 t 直到无法移动,过程如下:

t 指向 23232431,2 在后面的 3232431 中还有出现,向前移动 t

t 指向 3232431,3 在后面的 232431 中还有出现,向前移动 1

t 指向 232431,2 在后面的 32431 中还有出现,向前移动 1

t 指向 32431,3 在后面的2431 中还有出现,向前移动 1

t指向 2431,2 在后面的431中没有出现了,不能向前移动了

此时得到的子串就是最短子串,因为 子串长度==颜色种数

//M长度队列有N种颜色,找到包含所有颜色的最短字串

int FindFullColor(int arr[],int n,int m){

//C用来存储 每一种颜色出现的次数,C[0]不用

//颜色用m来表示,m代表有颜色:1,2,3,...,m

//即在arr
中找出同时出现 1,2,...,m 的最短字串

int *c=(int *)malloc((m+1)*sizeof(int));

memset(c,0,(m+1)*sizeof(int));



int min=n;

int h=0,t=0,ctr=m;



while(1){

while( ctr>0 && h<n ){

if(c[arr[h]]==0){

ctr--;

}

c[arr[h]]++;

h++;

}

//已经结束但依然没找齐颜色

if(h>=n){

break;

}

while(1){

c[arr[t]]--;

if(c[arr[t]]==0){

break;

}

//如果c[arr[t]]--之后,不为0,代表在 t 后面还有 arr[t] 的颜色

//所以当前 t 不是最短的,至少比后面那个长

t++;

}

if(h-t<min){

min=h-t;

//更新之后打印

//如果最后只打印最短的,则可以把 min,t,h 同时存储

for(int i=t;i<h;i++){

printf("%d",arr[i]);

}

printf("\n");

}



//删除颜色直到某个颜色为,这个颜色在 t-h 之间没有了

//这就需要在 h-n 之间再找到这种颜色

t++;

ctr++;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐