1. 解题思路
这道题主要的难点是,如何提高颜色对比时的速度,惯性思维会直接暴力求解,一个一个去对比,这样造成的结果使得时间复杂度非常高。
由于该题的颜色是用数字来表示,那么我们可以使用一个一维数组来表示,也就是用数组的下标“1,2,3,4,......,n”来表示颜色,由于没有颜色0,因此再最后计数时需要注意直接从下标1开始。
又因为该题是对颜色种数进行计数,所以我们可以使用boolean类型标记,将该数组初始化为false,当且仅当在m个连续串珠内某种颜色出现的次数大于或等于2时,则将该颜色对应的下标值置为true。在本题解中我定义该数组为flag。
例如:该题的示例1为:
5 2 3 3 1 2 3 0 2 2 3 1 2 1 3
那么在第三颗珠子和第四颗珠子的颜色出现次数分别为:
颜色:2,次数:2; 颜色:3,次数:1;
此时颜色2即为重复出现的颜色,因此在一维数组flag中将数组下标为2的值置为true,即:flag[2]=true。
2.采用List和ArrayList的数据结构来进行存储数据
为了更好地实现这个解题思路,我们首要问题是解决数据获取与存储问题,根据题目要求的输入格式,最佳方式是采用二维数组;但是有一个问题是每一行颜色的数目我们并不知道,也就是说这是动态的。
因此,我们需要采用动态的二维数组,避免浪费大量的空间。我们可以采用如下定义:
List list = new ArrayList(); List li = new ArrayList(); list.add(li);
这样就实现一个简单的动态二维数组。
3.获取数据
根据题目要求的数据格式,第一行可以使用nextInt()来获取一个整数,接下来的几行直接使用nextLine()读取字符串,再通过split函数对字符串进行分割,最后用Integer.parseInt将字符串转换为整形变量。
这里需要特别注意,使用nextInt()后,需要先使用一次nextLine()来清楚缓存,否则会读入一个换行符,导致Integer.parseInt运行异常。
代码片段如下:
int n,m,c; List list = new ArrayList();//二维数组 n = input.nextInt(); m = input.nextInt(); c = input.nextInt(); boolean flag[] = new boolean[c+1];//保存重复颜色 for(int i=0; i<=c; i++)flag[i] = false;//数组初始化 input.nextLine();//清除缓存 for(int i=0; i<n; i++){ String str = input.nextLine(); String s[] = str.split(" ");//分割字符串 int len = s.length; List li = new ArrayList();//用于保存每一行的数据 for(String sh:s){ int num = 0; try { num = Integer.parseInt(sh); } catch (NumberFormatException e) { e.printStackTrace(); } li.add(num); } list.add(li); }
4.颜色计数
对于颜色计数,我们需要在每m个珠子中,对每种颜色进行计数;根据解题思路,我们可以使用map来计数,通过将颜色种类保存在key值,value值保存该颜色在连续的m个珠子中出现的次数。通过这样的方式,我们可以利用起map的检索能力,保证时间复杂度不会过高,即在每一轮颜色出现次数计数完后,可以直接查找value值大于或等于2对应的key值,再将flag数组中对应的颜色下标值置为true。
代码如下:
for(int i=0; i<n; i++){ Map<Integer, Integer> map = new HashMap<Integer, Integer>();//key代表颜色,value代表颜色出现次数 int k=i;//k值用于遍历m个连续的珠子 for(int j=0; j<m; j++){ //由于获取颜色数据时,每一行的第一个数字代表颜色数量,因此该值若为0则直接跳过,注意数组的下标溢出处理 if((int)list.get(k).get(0) == 0){ k++; if(k>=n){ k=k-n; } continue; } int len = list.get(k).size(); //第一个值为颜色数量,直接从第二个值开始遍历 for(int l=1; l<len; l++){ //获取颜色 int color = (int)list.get(k).get(l); //初始化颜色出现次数 int colorNumber = 0; //若map中找得到该颜色,说明该颜色已经出现过,将该颜色出现次数拿出来 if(map.containsKey(color)){ colorNumber = map.get(color); } colorNumber+=1; map.put(color,colorNumber); } k++; //k值溢出,从0开始 if(k>=n){ k=k-n; } } for(Map.Entry<Integer,Integer > entry:map.entrySet()){ //判断map中value值是否有大于1的值,若有则说明该颜色已经重复出现 if(entry.getValue()>=2){ int key = entry.getKey(); flag[key] = true; } } map.clear();//清空map }
5.最终计数
这个很简单,直接贴代码(注意计数时从下标1开始):
int number=0; for(int p=1; p<=c; p++){ if(flag[p])number++; }
6.完整代码
import java.util.Scanner; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.HashMap; public class Main{ public static Scanner input = new Scanner(System.in); public static void main(String []args){ int n,m,c; List<List> list = new ArrayList<List>();//二维数组 n = input.nextInt(); m = input.nextInt(); c = input.nextInt(); boolean flag[] = new boolean[c+1];//保存重复颜色 for(int i=0; i<=c; i++)flag[i] = false;//数组初始化 input.nextLine();//清除缓存 for(int i=0; i<n; i++){ String str = input.nextLine(); String s[] = str.split(" ");//分割字符串 int len = s.length; List<Integer> li = new ArrayList<Integer>(); for(String sh:s){ int num = 0; try { num = Integer.parseInt(sh); } catch (NumberFormatException e) { e.printStackTrace(); } li.add(num); } list.add(li); } for(int i=0; i<n; i++){ Map<Integer, Integer> map = new HashMap<Integer, Integer>();//key代表颜色,value代表颜色出现次数 int k=i;//k值用于遍历m个连续的珠子 for(int j=0; j<m; j++){ //由于获取颜色数据时,每一行的第一个数字代表颜色数量,因此该值若为0则直接跳过,注意数组的下标溢出处理 if((int)list.get(k).get(0) == 0){ k++; if(k>=n){ k=k-n; } continue; } int len = list.get(k).size(); //第一个值为颜色数量,直接从第二个值开始遍历 for(int l=1; l<len; l++){ //获取颜色 int color = (int)list.get(k).get(l); //初始化颜色出现次数 int colorNumber = 0; //若map中找得到该颜色,说明该颜色已经出现过,将该颜色出现次数拿出来 if(map.containsKey(color)){ colorNumber = map.get(color); } colorNumber+=1; map.put(color,colorNumber); } k++; //k值溢出,从0开始 if(k>=n){ k=k-n; } } for(Map.Entry<Integer,Integer > entry:map.entrySet()){ //判断map中value值是否有大于1的值,若有则说明该颜色已经重复出现 if(entry.getValue()>=2){ int key = entry.getKey(); flag[key] = true; } } map.clear();//清空map } int number=0; for(int p=1; p<=c; p++){ if(flag[p])number++; } System.out.println(number); } }