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

转载:http://blog.csdn.net/zhccl/article/details/8044449

分享百度一个面试题:


有一串珠子首尾不相连,总共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中没有出现了,不能向前移动了

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


  1. //M长度队列有N种颜色,找到包含所有颜色的最短字串  
  2. int FindFullColor(int arr[],int n,int m){  
  3.     //C用来存储 每一种颜色出现的次数,C[0]不用  
  4.     //颜色用m来表示,m代表有颜色:1,2,3,...,m  
  5.     //即在arr[n]中找出同时出现 1,2,...,m 的最短字串  
  6.     int *c=(int *)malloc((m+1)*sizeof(int));  
  7.     memset(c,0,(m+1)*sizeof(int));  
  8.   
  9.     int min=n;  
  10.     int h=0,t=0,ctr=m;  
  11.   
  12.     while(1){  
  13.         while( ctr>0 && h<n ){  
  14.             if(c[arr[h]]==0){  
  15.                 ctr--;  
  16.             }  
  17.             c[arr[h]]++;  
  18.             h++;  
  19.         }  
  20.         //已经结束但依然没找齐颜色  
  21.         if(h>=n){  
  22.             break;  
  23.         }  
  24.         while(1){  
  25.             c[arr[t]]--;  
  26.             if(c[arr[t]]==0){     
  27.                 break;  
  28.             }  
  29.             //如果c[arr[t]]--之后,不为0,代表在 t 后面还有 arr[t] 的颜色  
  30.             //所以当前 t 不是最短的,至少比后面那个长  
  31.             t++;  
  32.         }  
  33.         if(h-t<min){  
  34.             min=h-t;  
  35.             //更新之后打印  
  36.             //如果最后只打印最短的,则可以把 min,t,h 同时存储  
  37.             for(int i=t;i<h;i++){  
  38.                 printf("%d",arr[i]);  
  39.             }  
  40.             printf("\n");  
  41.         }  
  42.   
  43.         //删除颜色直到某个颜色为,这个颜色在 t-h 之间没有了  
  44.         //这就需要在 h-n 之间再找到这种颜色  
  45.         t++;  
  46.         ctr++;  
  47.     }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值