目录
一、输入的三种方式
1.最常见的Scanner的输入方法
2.数据多的时候常用BufferedReader快读
3.较麻烦的StreamTokenizer快读(用的不多)
StreamTokenizer常见错误:
二、min和max值的设置
三、妮妮的翻转游戏
四、小明和完美序列
五、顺子日期(填空题)
六、星期计算(填空题)
七、山
推荐
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站
一、输入的三种方式
1.最常见的Scanner的输入方法
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int m = scan.nextInt();
System.out.print(n+" "+m);
2.数据多的时候常用BufferedReader快读
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] strings = br.readLine().split(" ");
int n = Integer.parseInt(strings[0]);
int m = Integer.parseInt(strings[1]);
System.out.print(n+" "+m);
3.较麻烦的StreamTokenizer快读(用的不多)
对于读取字符类型的操作,只能读取26个字母,特殊符号和数字无法读取,有其局限性
因为他使用起来比较麻烦,所以可以封装一个对象,减少代码量
//封装的对象
static class Read {
StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
public int nextInt() throws Exception {
st.nextToken();//读取数据
return (int)st.nval;//默认存储的是double类型
}
public String readLine() throws Exception {//有局限,慎用
st.nextToken();
return st.sval;
}
}
public static void main(String[] args) throws Exception {
Read read = new Read();
int n = read.nextInt();
System.out.print(n);
}
StreamTokenizer常见错误:
(1)StreamTokenizer读入long类型的数字时会出现错误
因为nval的类型是double,在转换为long类型的过程中,double类型能表示的数字范围比long大,但是是以牺牲精度的方式获得更大的存储,而他能精确保存的数字位数为十进制的15或16位,要比long小
由图可以看见,double类型在存储时,牺牲了精度,导致结果不准确
(2)StreamTokenizer读入太长的字符串时也会有问题
二、min和max值的设置
min设为最大值(以及这样设的易错点),max设为最小值,求和初始值为0,求积初始值为1简单理解这样设的原理,min要存储最小值,我们在给min设初始值的时候不能影响我的最终结果,那我肯定不能设一个小的值,假设设为0,那么输入是1234,这样你的min输出的是几?自然是0,但实际最小值是1,这是因为我们的初始值,影响到了答案,所以要设一个题目中的最大值或者设一个不会出现的最大值也行。
一般都这样设置:int min = Integer.MAX_VALUE
但是也存在一定的弊端:
如果遇到了以下代码if(min+a>b),类似这种判断很容易出现问题,本身min是整数类型的最大值,它在加上a,很可能爆int直接变成负数,那么就会导致判断出错。这样写的时候可以加一个判断if(min!=Integer.MAX_VALUE&&min+a>b)。
三、妮妮的翻转游戏
import java.util.*;
public class 妮妮的翻转游戏 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int n = s.nextInt();
//解法1:if else语句
if(n==0) System.out.print(1);
else System.out.print(0);
//解法2:异或(找不同)
System.out.print(n^1);
//解法3:取反
System.out.print(~n+2);//~n=-n-1
//解法4:三目运算符
System.out.print(n==1?0:1);
}
}
四、小明和完美序列
思路1:只看删除
eg:对于3这个数字,如果3的个数<3,那么就需要全删;如果3的个数>3,那么就需要删到3个
因为本题每个数字都有一个对应的值,所以可以考虑map(key,value) (用数组时间会超时)
那么如果3的个数<3,那么就删value次;如果3的个数>3,那么就需要删value-key次
import java.util.*;
public class 小明和完美序列 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
HashMap<Integer,Integer> map = new HashMap<>();
//输入数据并放入map
for(int i=0;i<n;i++) {
int a = scan.nextInt();
// if(!map.containsKey(a)) {//第一次放入,value置为1
// map.put(a, 1);
// }else {
// map.put(a, map.get(a)+1);//非第一次放入,value+1
// }
//这一行可以代替上面,getOrDefault方法
map.put(a, map.getOrDefault(a, 0)+1);
}
int count = 0;//要删除的次数
for(Integer e : map.keySet()) {//从map中遍历每个key
if(map.get(e)>e) {//相当于>3次
count+=map.get(e)-e;
} else if(map.get(e)<e) {//相当于<3次
count+=map.get(e);
}
}
System.out.print(count);
}
}
思路2:看保留(找到本来需要保留的个数m和现有的总次数n,删除的次数count=n-m)
但是注意:只有value>=key的时候才进行保留
import java.util.*;
public class 小明和完美序列 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
HashMap<Integer,Integer> map = new HashMap<>();
for(int i=0;i<n;i++) {
int a = scan.nextInt();
map.put(a, map.getOrDefault(a, 0)+1);
}
int sum = 0;//要保留的次数
for(Integer e:map.keySet()) {
if(map.get(e)>=e) {
sum+=e;
}
}
System.out.print(n-sum);
}
}
五、顺子日期(填空题)
思路1:手写日期模拟器 注意闰年
public class 顺子日期 {
static int year=2022,month=1,day=1;
static int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};//注意2月
public static void main(String[] args) {
//手写日期模拟器自动生成下一个日期
Scanner scan = new Scanner(System.in);
int count = 0;//顺子日期的个数
while(year!=2023) {
if(check()) {//判断是否满足顺子日期
count++;
}
day++;
if(month==2) {
//闰年29天特殊考虑
if(year%400==0||(year%4==0&&year%100!=0)) {
if(day>29) {
month++;
day=1;
}
}else {
if(day>28) {
month++;
day=1;
}
}
}else {
if(day>days[month]) {//day超过了本月的天数范围
month++;
day=1;
}
}
if(month==13) {//month超过了12
year++;
month=1;
}
}
System.out.print(count);
}
//判断是否满足顺子日期
private static boolean check() {
//数字形式
int num = 0;
num += year;
num =num*100+month;
num =num*100+day;
//转为字符串的形式
String string = String.valueOf(num);
//正式开始判断:思路如果后面一个字符是前面字符+1那么就step++,直到step到3
int step = 1;
for(int i =1;i<string.length();i++) {
if(string.charAt(i-1)+1==string.charAt(i)) {
step++;
} else {
step=1;//不是顺子重新开始
}
//如果step到3就是顺子日期
if(step==3) {
return true;
}
}
return false;
}
}
思路2:java自带的日期函数
(1)用到了Calendar calendar = Calendar.getInstance();的set和get方法
注意set方法中的bug:month是从0开始的
(2)用到了SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");//规范日期的写法
//方法2:java自带的日期函数
public class 顺子日期 {
public static void main(String[] args) {
String [] seq = {"012","123"};//day不可能为4-9
Calendar calendar = Calendar.getInstance();
calendar.set(2022, 0,1);//为什么月要初始化为0:这里相当于一个bug,这个函数月就是从0开始的
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");//规范日期的写法
int count = 0;
//开始统计顺子日期的数目
while(calendar.get(calendar.YEAR)==2022) {//取出calendar中的年份
String date = sdf.format(calendar.getTimeInMillis());//让date规范为yyyyMMdd
//遍历字符串看有没有这个可能存在的顺子
for(String s:seq) {
if(date.contains(s)) {
count++;
break;//有两个顺子也算一个日期,count只能加一次
}
}
calendar.add(calendar.DATE, 1);//日期+1
}
System.out.print(count);
}
}
六、星期计算(填空题)
20的22次方已经超过了long类型的范围
解法1:BigInteger类(这个类在java中可以表示任意大小的整数,没有固定的范围限制)
import java.math.BigInteger;
public class 星期计算 {
public static void main(String[] args) {
BigInteger bigInteger = new BigInteger("20");
//运算类型都得是BigInteger类型
BigInteger n = bigInteger.pow(22).mod(new BigInteger("7"));
System.out.print(n);
}
}
得到的答案是1,那么结果直接输出7即可
解法2: 数学方法:(a*b)%p=(a%p*b%p)%p
int mod7 = 1;
for(int i=1;i<=22;i++) {
mod7 = (mod7*20)%7;//每一次次方都%7
}
System.out.print(mod7);
七、山(填空题)
思路:回文&&单调性
//思路:回文判断+单调性判断(这样就只用判断一边)
public class 山 {
public static void main(String[] args) {
int n = 0;
for(int i=2022;i<=2022222022;i++) {
if(huiwen(i)&&dandiao(i)) {
n++;
}
}
System.out.print(n);
}
//判断单调性
private static boolean dandiao(int n) {
int[] a = new int[10];
int i=0;
while(n>0) {
a[i++] = n%10;
n =n/10;
}
int l=i/2;
for(int j=1;j<=l;j++) {
if(a[j]<a[j-1]) {
return false;
}
}
return true;
}
//回文判断:思路前后指针遍历,看是不是一样
public static boolean huiwen(int n) {
int[] a = new int[10];
int i =0;
//把数字放入数组
while(n>0) {
a[i++] = n%10;
n =n/10;
}
int l=0,r=i-1;
while(l<r) {
if(a[l]!=a[r]) {
return false;
}
l++;
r--;
}
return true;
}
}