m个珠子共n种颜色,找出包含n种颜色的最短连续片段
原题目:
有一串的珠子(首尾不相连),共有m个,每一个珠子有一种颜色,并且颜色的总数不超过n(n<=10),求连续的珠子的颜色总数为n时,长度最小的区间。
题目分析:
一 、暴力搜索
1、最简单的方法---暴力搜索,逐个扫描第i个位置开始包含n中颜色最短区间,时间复杂度为O(m^2) 。
2、从i开始扫描,每出现一种新的颜色,计数+1 ,当计数=n时候,结束,此时即为i开始的最短区间 。
二 、
1、扫描一遍数组m,计算出每种颜色在数组m中下一次出现的位置,存在数据nextColor[m]中 (每种颜色的最后一个元素的下一个位置记为-1 ,在后面的程序中需要特殊处理)。
2、从0位置开始扫描数组m,找出第一个包含所有颜色的区间,此时的开始位置即为beginTag (此时是0),结束位置记为endTag 。
3、对beginTag进行操作:如果beginTag位置的颜色的下一个颜色nextColor[beginTag]<=endTag ,则将beginTag++ ,重复此步骤,直到nextColor[beginTag]>endTag 或者 beginTag==endTag ,此时beginTag---->endTag即为以endTag结束但包含所有颜色的最小区间 。
4、endTag后移一步,然后重复步骤3 。
5、重复步骤4 ,直到endTag=m.length-1 。
6、此时可以得到所有元素结尾的最短区间的长度,选取一个最小的 。
代码如下:
package ddc.test.com; public class MNSelectTestMain { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int data[]={0,1,2,3,4,4,5,4,2,3,1,0,2,3}; getSubAll(data,6); } public static int[] getSubAll(int[] colorArray,int colorLength){ for(int color:colorArray){ if(color>=colorLength) throw new RuntimeException("color error!!"); } int[] least=new int[colorArray.length]; int[] nextColor=new int[colorArray.length]; for(int i=0;i<nextColor.length;i++) nextColor[i]= -1; int[] colorCounter=new int[colorLength]; int[] colorTmp=new int[colorLength]; for(int i=0;i<colorTmp.length;i++) colorTmp[i]= -1; for(int i=colorArray.length-1;i>=0;i--){ nextColor[i]=colorTmp[colorArray[i]]; colorTmp[colorArray[i]]=i; } int hasColor=0 ; //已经发现的颜色总数 int beginTag=0 ,endTag =0; //找到第一个包含所有颜色的结束点 while(endTag <colorArray.length){ if(colorCounter[colorArray[endTag]]==0){ hasColor++; colorCounter[colorArray[endTag]]++; } if(hasColor==colorLength) break; endTag++; } //结束点逐步后移,然后找到以endTag为结束点的最短区间 while(endTag<colorArray.length){ if(nextColor[beginTag]>=0&&nextColor[beginTag]<=endTag){ beginTag++; continue; } least[endTag]=endTag-beginTag+1; endTag++; } //打印 for(int tt:least) System.out.print(tt+" "); System.out.println(); for(int tt:colorArray) System.out.print(tt+" "); return colorArray; } }