【每日蓝桥】43、一六年省赛Java组真题“压缩变换”

你好呀,我是灰小猿,一个超会写bug的程序猿!

欢迎大家关注我的专栏“每日蓝桥”,该专栏的主要作用是和大家分享近几年蓝桥杯省赛及决赛等真题,解析其中存在的算法思想、数据结构等内容,帮助大家学习到更多的知识和技术!

标题:压缩变换

小明最近在研究压缩算法.

他知道,压缩的时候如果能够使得数值很小,就能通过熵编码得到较高的压缩比。

然而,要使数值很小是一个挑战.

最近,小明需要压缩一些正整数的序列,这些序列的特点是,后面出现的数字很大可能是刚

出现过不久的数字.对于这种特殊的序列,小明准备对序列做-一个变换来减小数字的值.

变换的过程如下:

从左到右枚举序列,每枚举到一一个数字,如果这个数字没有出现过,刚将数字变换成它的相反数,如果数字出现过,则看它在原序列中最后的一次出现后面(且在当前数前面)出现了

几种数字,用这个种类数替换原来的数字.

比如,序列(al, a2, a3, a4, a5)=(1, 2,2, 1, 2)在变换过程为:

al:1未出现过,所以al变为-1;

a2:2未出现过,所以a2变为-2;

a3:2出现过,最后一次为原序列的a2,在a2后、a3 前有0种数字,所以a3变为0;

a4: 1出现过,最后一次为原序列的al,在al后、a4 前有1种数字,所以a4变为1;

a5:2出现过,最后一次为原序列的a3,在a3后、a5 前有1种数字,所以a5变为1.

现在,给出原序列,请问,按这种变换规则变换后的序列是什么.

输入格式:

输入第一行包含一个整数n,表示序列的长度

第二行输入n个整数,表示输入序列。

输出格式:

输出一行,包含n个数,表示变换后的序列.

例如,输入:

5

1 2 2 1 2

程序应该输出:

-1 -2 0 1 1

 

再例如,输入:

12

1 1 2 3 2 3 1 2 2 2 3 1

程序应该输出:

-1 0 -2 -3 1 1 2 2 0 0 2 2

 

【数据规模与约定】

对于30%的数据,n<=1000;

对于50%的数据,n<= 30000;

对于100%的数据,1 < =n<=100000,1<=ai<=10^9

资源约定:

峰值内存消耗(含虚拟机) < 256M

CPU消耗< 3000ms

请严格按要求输出,不要画蛇添足地打印类似:“ 请您输...”的多余内容.

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码.

注意:不要使用package语句.不要使用jdk1.7及以上版本的特性.

注意:主类的名字必须是: Main, 否则按无效代码处理.

解题思路:

本题在求解上其实就是一个判断的过程,需要我们定义一个数组存放初始数据,再定义一个数组存放答案数据,主要用到的考点是HashMap和HashSet的应用,首先应该判断该数是否已经被读取过了,如果没有读取过,则在答案数组的对应序列上记录该数的相反数,如果读取过了则判断在初始数组中,该数和上一次出现的序列之间存放了多少种数据,这就用到HashSet来进行不重复存储,之后返回HashSet的长度并在答案数组对应位置存储该长度即可。

答案源码:

public class Year2016_Bt10 {

	static int [] initialArr;	//初始数组
	static int [] ansArr;		//答案数组
	static Map arrMap = new HashMap();
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int n = scanner.nextInt();
		initialArr = new int[n];
		ansArr = new int[n];
		for (int i = 0; i < n; i++) {
			initialArr[i] = scanner.nextInt();
			ansArr[i] = initialArr[i];
		}
		for (int i = 0; i < n; i++) {
			//如果map中没有对应的键
			if (!arrMap.containsKey(initialArr[i])) {
				ansArr[i]=-initialArr[i];	//将数变换成它的相反数
				//将数值和其对应的序列号存入
				arrMap.put(initialArr[i], i);
			}else {
				int num = arrMap.get(initialArr[i]);//获取到上一次出现该数时在数组中的序号
				int count = getNum(num,i);
				ansArr[i] = count;
				arrMap.put(initialArr[i], i);
			}
			
		}
		//将答案输出
		for (int i = 0; i < n; i++) {
			System.out.print(ansArr[i] + " ");
		}
		System.out.println();

	}
	
	/**判断两个序号之间的数组中有多少种数字
	 * @param i 起始序列
	 * @param j 终止序列
	 * */
	private static int getNum(int i, int j) {
		HashSet numSet = new HashSet();
		//从起始序列开始向终止序列进行遍历
		for (int k = i+1; k < j; k++) {
			numSet.add(initialArr[k]);//将数值不重复的存放进hashset中
		}
		return numSet.size();//返回set长度,即不重复数的个数
	}

}

输出样例:

【每日蓝桥】43、一六年省赛Java组真题“压缩变换”_第1张图片

其中有不足或者改进的地方,还希望小伙伴留言提出,一起学习!

感兴趣的小伙伴可以关注专栏!

灰小猿陪你一起进步!

你可能感兴趣的:(每日蓝桥,数据结构,java,编程语言,算法,蓝桥杯)