这几天初步的了解了一下Java,然后写了几道题:
下面总结一下学Java的时候遇到的一易错的小问题以及总结:
1. java里面只能在一个源文件里有一个public类,但是入口main那个可以理解为public static是一个整体也就是不属于public;(其实看到后面才知道main属于方法,不是类)
2. jdk9才有的交互jshell; (这是遗憾没有试过,但是书上看到的知识)
3. 类型的分类:基本类型和引用类型(引用类型和指针有点像);
4. 在cmd里面执行Java代码的时候要在该Java代码的路径下,如果没有在可以用绝对路径,可以设置环境变量CLASSPATH,但是如果在环境变量里面没有当前路径要记得设置,否则可能会找不到,如果设置了CLASSPATH会严格按照它的路径来找,可以省略-d选项生成字节码,即默认为在当前目录下保存。
总结为: -classpath > CLASSPATH > -d(虽然现在基本上用到的是IDE工具,但是还是了解一下底层一点的知识)
5. 想知道如何解决文档乱码问题;用text文件创建(这个是我现在都还没查到的,但是先不打算深究,主要是现在开始初学);同时这里总结一下在ideal里面刚开始是不可以用打印函数打印中文的,这里说一下解决方法;
刚开始创建一个项目并且一个类的时候敲代码的页面右下角有这样一个,把那个UFT-8改成GBK,之后它会有一个提示是然后按那个convert按键就可以了,然后你会发现没有报错了;
6. 在java里面,一个语句可以跨多行和c语言有区别,而变量名和字符串不可以;
7. IDE 的原理:IDE工具有很多,原理也是我很想弄明白的,大概就是在操作者每创建一个类,都会出现相应class文件而且在该文件中只能有一个public类,并且这个类型的名称要和文件名一样,否则就会报错,除非你不用public;
8.标识符和c语言的区别:C语言是以字母数字下划线,且不可以用数字开头;Java是以字母下划线美元符开头,不可以以数字开头,总的来说就是Java多了一个美元符,其他没什么区别,Java的字母不限于26个字母可以是中文或者日文字符等,而c语言就是26个字母;但不可以是@等其他字符;直接量保留字和关键字都不可以作为标识符,var可作为标识符;
9. java 9开始不允许只用下划线作为标识符;
10. 在一个超出int类型的数不会自动转换成long而是要在最后1个L或者l;由于java在int类型里面的数是三十二位的,如果有一个数它超过了三十二位则会溢出变成负数,这时如果把它1加一个L的话,他就不会溢出啦!!举个栗子:
long n1=0b10000000000000000000000000000001L;
结果:2147483649
long n1=0b10000000000000000000000000000001;
结果:-2147483647
而且,在Java 里面如果把第一个结果用这样的形式long n1=2147483649;还会报错;因为这已经超出了int的范围,要想将它转换成long型;
11. 负数在计算机里面是以补码形式存在的,反码和原码还有补码的关系:对源码逐位取反,除了符号位,补码=反码加1;
13.如果用long 定义一个变量是自动转换,如long a=100;这里其实100在系统认为是int型,但是这时候就会自动转换成long型;
(如何看API帮助文档;)
14.初始化的时候,字符串可以··加减,也就是连起来;
15.只有浮点类型的数才有科学计数法,和c语言一样,默认的浮点数都是双精度JAVA提供了三个浮点数值,正无穷大,负无穷大,和非数。NaN和其他数都不相等,自己也是;如果是整数除以零会报错,浮点数就不会;
public class Test
{
public static void main(String[]args)
{
//String s1="abcdef";
//String s2="abcdef"+"xy";
//也可作字符串的连接运算符
//System.out.println(s2);
//System.out.println(s1);
//float af=5.2345556f;
//System.out.println(af);
double a=0.0;
double c=Double.NEGATIVE_INFINITY;//负无穷直接量
float d=Float.POSITIVE_INFINITY;//正无穷
System.out.println(c==d);//表示正无穷和负无穷不等
System.out.println(a/a);//得到非数
System.out.println(a/a==Float.NaN);非数和他本身都不想等
System.out.println(6.0/0==555.0/0);//正无穷和正无穷相等
System.out.println(-8/a);
//数值是用下划线分割
int bival=0b0000_1;
System.out.println(bival);
boolean aaaa=true;
String ssss=aaaa+"";
System.out.println(ssss);
//java 10;才有
// var a=10;
}
}
16.和c语言有一点不一样的是,布尔类型0/1和true/false差不多的样子,但是java里面和0/1是无关的,它不属于数值类型,但是是基本类型,Java里面的布尔类型是可以和字符串进型运算的,虽然布尔类型刚开始并不是字符串类型,但是运算后就是可以是;关于自动转换,小的可以向大的转化,但是char只可以向int,虽然long是64位,但是可以向float32为转换;
17.字符串类型不可以直接转换成基本类型,但是可以有对应的方法:p60,比如整型转换可用方法Integer.parseInt(a),也就是把字符串a转换成整数;
18. 基本类型算术的时候是会自动类型提升,以至于Java里面short类型有这样的表达式是错误的,b=b-2;但是如果用拓展运算符写成这样就可以了:b-=2;
19:在java里面可以用==比较字符串,但是这样比较有缺点;
20.按位异或^两个不一样的才取一;>>>总是以零补位,>>按照最高位来补有两种,而左移只有一种也就是补零,移位要先学会取余,比如移位33和1在int类型都是一样的;
21:在Java里面的比较运算符的结果是布尔类型,而不是0/1;
22:对于==如果都是数值类型的话,类型不一样也是可以比较的,但是对于引用类型如果不是父子关系不可以比较,要是同一个对象才有可能返回true;
23:在Java里面有一个短路&&,有一个不短路&;或也是一样
24:通常Java是以打印字符串的形式来打印变量;
25:对于Java来说,不仅break可以结束当前的循环,还可以结束所在的整个外部循环,先设置一个标签在循环要结束循环的前面,然后在里面用break加这个标签就可以实现打破它们从里到外之间的循环了;
26:和c语言不同的是,Java不可以及设置数组的长度的同时又对其初始化,只可选其一中;分别是初始化自动让系统计算长度,和给长度然后后系统初始化;分别叫做静态和动态;使用静态初始化简化语法不可以用var类型,在Java里面就算是局部变量也是会对刚开始数组初始化为零;
27:类之间的成员可以相互调用,但是static修饰的成员不能访问没有的;
28:Java里面可以有可以变参数,但是只能放到最后一个并且最多只有一个。
29:成员变量会自动初始化;可以有同名的方法,叫重载,但是不可以有同名的成员变量;
30:可以成员变量和局部变量同名,方法里面局部变量会将成员变量覆盖,如需调用,用this或者类名;来引用,如果不是static类型就只能用this。
31:和c语言不同的一点是,在Java一个类里面是可以把顺序打乱的,但是方法里面是严格按照顺序的,其他的,比如方法在被应调用的后面是没关系,不会报错的;
(Test,Person,Main)举例代码到时候补上;
关于刷题:
第一道,烦恼的高考志愿
刚开始用暴力,然后一直卡Test2,再用直接插入排序,快排,时间长了,(其实之前还是有一点错误的,可能是由于那个错误)然后用的是c++的sort函数,然后把小错误纠正了一下,就以一半分(只有一半分)堪堪过了:
我觉得自己只有一半分可能是没有用到二分查找,我的搜索是暴力搜索,先将学生估分和学校分数线都排序,然后从小到大搜索,分三种情况,如果那个学生的分数比最低的分数线都要低那那个学生估的最好也只能是最低的,后面的都是这样,如果该学生可以找到一个比他小的和比他大的那么估的最好的就一定是这两者的其中一个,最后如果这个学生的分数比学校分数线都要高的话就可以直接求最高的,当然这里有一个技巧,每个学生在哪里停止,下一个学生就从他的较低分开始,这样就避免重复多次扫描。
注意:这里的h也就是不满意度之和是有可能超过int的范围的所以要用long long;
下面是代码:
#include<bits/stdc++.h>
using namespace std;
int c[100005];
int d[100005];
int main()
{
int n,m;
scanf("%d %d",&m,&n);
for(int i=1; i<=m; i++)
{
scanf("%d",&c[i]);
}
sort(c+1,c+m+1);
for(int i=1; i<=n; i++)
{
scanf("%d",&d[i]);
}
sort(d+1,d+n+1);
long long h=0;
int l=1;
int minn;
for(int i=1; i<=n; i++)
{
for(int j=l; j<=m; j++)
{
if(j==m)
{
minn=abs(d[i]-c[j]);
l=m;
}
else if(d[i]<=c[l])
{
minn=c[l]-d[i];
break;
}
else if(d[i]>=c[j]&&d[i]<=c[j+1])
{
int z=abs(c[j]-d[i]);
int x=abs(c[j+1]-d[i]);
minn=x>z?z:x;
l=j-1;
break;
}
}
h+=minn;
}
printf("%lld",h);
return 0;
}
第二道:领地选择
刚开始想的是以正方体的边长为单位逐个循环,每找到一个符合题意的正方形就将它进行循环求和,但是会发现循环套循环会爆炸,数据太大了,所以采用动态规划,里面的一个二维数组求前缀和;
我觉得这篇博客讲的很好:浅谈二维前缀和
动态规划就是讲究一个本来是未知,把它装作已知,最后向已知走;在这个题里面,先是用动态规划将每个以最左上角为一个顶点目前坐标为右下角顶点的所有矩形的权值都求出来,然后用来求以c为边长的某个正方形,求里面的最大值;在这里面要注意两点:
1.做这种题目一定要注意不要数组越界,控制好变量范围,我是通过将整个0行0列都赋值为0;
2.最后这个最大值初始化一定要足够小,比如int的范围最小是2*10^-10多,不然过不了。
上代码:
#include<stdio.h>
int a[1010][1001];
int b[1001][1001];
int main()
{
int n,m,c;
scanf("%d %d %d",&n,&m,&c);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
}
}
int maxx=-2000000000;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
b[i][j]=a[i][j]+b[i][j-1]+b[i-1][j]-b[i-1][j-1];
}//动态规划,这里也是二维数组前缀和;这里不设置以零为边界的初始化为零;可以从前开始往后求
int mx,my;
for(int i=c;i<=n;i++)
{
for(int j=c;j<=m;j++)
{
int mm=b[i][j]-b[i-c][j]-b[i][j-c]+b[i-c][j-c];
if(maxx<mm)
{
maxx=mm;
mx=i-c+1;
my=j-c+1;
}
}
}
printf("%d %d",mx,my);
return 0;
}
最最最后,疲惫的心灵怎么能少得了一碗热腾腾的心灵鸡汤呢:
你要接受自己的普通,然后拼尽全力去与众不同