题目:
分析过程:
一看到这个问题描述我就头疼,长篇大论、虚无缥缈的(对我这样数学比较差的)人来说,简直就是一种折磨。即使它处于csp考试的第一题,超小难度,但若是没有将抽象具体化的能力的话,再简单也是白搭。在做这个题目之前,我先解析下上一个题目:出现次数最多的数-2013-12-1.
解题目的:将抽象问题转化为实际编程需求,需要具备这种能力,没有怎么办,多加锻炼。
解题三部曲:
1.看输入,输出。输入什么参数,需要输出什么结果。
2.弄清楚输入和输出参数具体是什么含义,有什么用。
3.将所求问题转化为编程需求实现。
注1:编程时注重选取合适的数据结构和算法,但有时候解题出来就行,毕竟是考试,只需要对就行,不过最好是在平常编码时就注重编码的好习惯(注释、精简的代码、适合的数据结构和算法)
注2:多注重一下题目的细节要求,有可能掉了条件,就没有满分了,也要多进行边界、特殊值测试,从而使答案更完美。如提交测评显示超出 内存或时间限制,需要事先进行一下渐近复杂度分析,分析一下所使用的的数据结构和算法是不是最好的(肯定是很垃圾的,不然也不会测评不过)
开始上次解题了。
1、输入:有两行,第一行是要输入的数字的个数n(循环的次数)
第二行是以空格隔开的n个数字
2、输出:求出出现次数最多的那个数,并且如果次数最多的有多个,需要输出数值最小的那个。
由题意:
用户会有两个输入,第一个输入是n,即数的个数
第二个输入是这n个数本身,要求出出现次数最多的数
1)次数需要存、数本身也要存
2)次数需要累加
自然而然想到Map键值对集合了,数字本身作为key,次数作为value。次数作为value可以实现累加覆盖。但是如果最大的出现次数一样,有多个怎么办?需要取出数值最小的那个,这个怎么实现?我希望集合可以按照key排序,这样最小的就在前面,即时有跟它次数相同的,只要出现次数不超过它,我也舍弃掉,这样就可以取出出现次数相同情况下比较小的那个了。
想要排序很简单,使用TreeMap即可实现,默认按照key升序排序,小的就在前面。【如果需要降序,自己实现自定义比较器即可】
有了实现思路下面就直接上代码,谁都不可能一蹴而就,需要大量的练习和编码实践。
package practice_20210831;
import java.util.*;
public class Main {
public static void main(String[] args) {
// 问题描述
// 给定n个正整数,找出它们中出现次数最多的数。如果这样的数有多个,请输出其中最小的一个。
// 输入格式
// 输入的第一行只有一个正整数n(1 ≤ n ≤ 1000),表示数字的个数。
// 输入的第二行有n个整数s1, s2, …, sn (1 ≤ si ≤ 10000, 1 ≤ i ≤ n)。相邻的数用空格分隔。
// 输出格式
// 输出这n个次数中出现次数最多的数。如果这样的数有多个,输出其中最小的一个。
// 样例输入
// 6
// 10 1 10 20 30 20
// 样例输出
// 10
run();
}
public static void run() {
//输入数字的个数n
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] nums = new int[n];
//循环输入数字,将其存入数组
for (int i = 0; i < n; i++) {
nums[i] = sc.nextInt();
}
//构建Map,且要求能排序的Map,选取TreeMap,用以储存数字和数字的个数,number:cnt
Map<Integer,Integer> map=new TreeMap<Integer, Integer>();//默认按照key的升序排序
int cnt=0;
for (int num : nums) {
Integer value = map.getOrDefault(num, 0);
value++;
map.put(num,value);
}
//遍历map找出出现次数最多的数字,且需要满足 如果次数最多的一样,要取最小的数
Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
int max_num=0;
int max_cnt=0;
for (Map.Entry<Integer, Integer> entry : entries) {
Integer key = entry.getKey();
Integer value = entry.getValue();
if(value>max_cnt)
{
max_cnt=value;
max_num=key;
}
}
System.out.println(max_num);
}
}
测评结果:100分
额,,肯定没有c++执行效率快和占用内存小的~
接下来,我们来看下今天这道题,灰度直方图
说实话,我刚开始读题目,读了三遍,没读懂o(╥﹏╥)o
咱还是按照三部曲走:题目里面其他什么扯淡的白话懂最好,不懂就算了
1、第一步,看输入:
输入一共n+1行
第一行是是三个数字,空格隔开,n、m、L
从第二行到n+1行输入的是矩阵
每一行是m个数字
n和m是什么?
n是矩阵(可以理解为坐标系)的纵坐标轴
m是矩阵的横坐标轴
n和m的范围----->面积n*m即组成了这个大矩阵
这每行的m个数字究竟是什么呢?由题意(需要多看几遍、理解)
可知,用户每行输入的这m个数字,即代表那一点(m、n组成的矩阵)像素的灰度值
L:就是一个数组的长度
2、输出什么:
需要输出数组h[0]、h[1].......h[L-1]的值,并以空格隔开。
那这个数组h[x]所带表的含义是什么呢?
由题意可知,h[x]即直方图中灰度值为x的像素的个数,灰度值是什么,灰度值不就是用户输入的那每行的m个数嘛?
3、理解了输入输出代表的含义,转化为编程需求很简单,不就是要求输入的这m*n个数里面,我给的这个数组的每个下表值在这个m*n的矩阵里面有多少个嘛,计数问题,双层for循环,搞定!
代码如下:
package prac_20210401;
import java.util.*;
/**
* @author:tom
* @Date:Created in 9:23 2021/9/4
*/
public class Main {
public static void main(String[] args) {
run();
}
//灰度直方图
public static void run() {
//第一行输入的三个值:n、m、l
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();//矩阵长
int m = sc.nextInt();//矩阵宽
int l = sc.nextInt();//数组长度
int[] h = new int[l];
int[] zhiFangTu=new int[n*m];
for (int i = 0; i < n * m; i++) {
//存入m*n个元素
zhiFangTu[i]=sc.nextInt();
}
//计算h[0]~h[l-1]
for (int i = 0; i < h.length; i++) {
int cnt=0;
for (int i1 = 0; i1 < zhiFangTu.length; i1++) {
if(i==zhiFangTu[i1])
cnt++;
}
h[i]=cnt;
}
for (int i = 0; i < h.length; i++) {
if(i==h.length-1)
System.out.print(h[i]);
else
System.out.print(h[i]+" ");
}
}
}
经过多次输入测试,发现代码符合题目要求。
测评结果:100分。