2023.3.20-爱代码爱编程
文章目录
算法部分
2:前缀和数组
// 前缀和数组
public class RangSum {
public static int[] help;
public static int rangSum(int[] array, int L, int R) {
help = new int[array.length];
help[0] = array[0];
for (int i = 1; i < array.length; i++) {
help[i] = help[i-1] + array[i];
}
return L == 0 ? help[R] : help[R] - help[L - 1];
}
}
思路:
array:{1,2,3,4,5,6,7}
1:先创建一个前缀和数组 help:{1,3,6,10,15,21,28}
2:根据要求的L—R累加和的区间,如果L == 0,那么直接返回help[R],如果L !=0,那么就返回help[R] - help[L-1]
3:之所以采用前缀和数组的原因是:用空间换时间,空间复杂度是On但是时间复杂度却是O1,而传统的累加的方式,空间复杂度虽然是O1但是时间复杂度是On.
3:Math.random( ):等概率的返回[0 , 1)之间的数
package Novice_class;
// Math.random(): 等概率的返回[0,1)上的每一个数,注意返回类型是double类型
public class RandToRand {
// Math.random() -> x属于[0,1)之间,P[0,x] = x
// 现在想设计一个 Math.random() -> x属于[0,1)之间,P[0,x] = x^2
public static void main(String[] args) {
int testTime = 100000;
int count1 = 0;
int count2 = 0;
int count3 = 0;
for (int i = 0; i < testTime; i++) {
double x = 0.3;
if(Math.random() < x) {
count1++;
}
if(xpoewrx2() < x) {
count2++;
}
if(xpoewrx3() < x) {
count3++;
}
}
System.out.println(count1 * 1.0 / testTime);
System.out.println(count2 * 1.0 / testTime);
System.out.println(count3 * 1.0 / testTime);
}
public static double xpoewrx2() {
return Math.max(Math.random(),Math.random());
}
public static double xpoewrx3() {
return Math.max(Math.max(Math.random(),Math.random()),Math.random());
}
}
/*
0.30134
0.08862
0.02707
*/
4:从ab随机到cd随机
// 有f1这么一个函数:等概率返回[1,5]之间的数字
// 我们想要[0,6]等概率返回一个,注意只能使用f1方法改写
public static int f1() {
return (int)(Math.random() * 5) + 1;
}
// f2: 1,2 -> return 0 4,5 -> return 1 3 -> 重新加载
// f2就是一个0 , 1发生器,并且是等概率的
public static int f2() {
int ans = f1(); // 1,2,3,4,5
while(ans == 3) {
ans = f1();
}
// 出来之后ans肯定不等于3
return ans < 3 ? 0 : 1;
}
// 返回 0 - 7:之间的数字是等概率的
public static int f3() {
// 000 —— 111 :0 - 7
int ans = (f2() << 2) + (f2() << 1) + (f2() << 0);
// 返回 0 - 7:之间的数字是等概率的
return ans;
}
public static int f4() {
int ans = f3();
while(ans == 7) {
ans = f3();
}
// 出来之后肯定没有7
return ans;
}
举一反三:
//有t1这么一个函数:等概率返回[1,24]之间的数字
// 33~57等概率获得一个数,整数,只能使用t1改写
// 1-24等概率发生器
public static int t1() {
return (int)(Math.random() * 24) + 1;
}
// t2是一个0,1发生器
// 12,13是[1,24]的一个中间值
public static int t2() {
int ans = t1();
while(ans == 12 || ans == 13) {
ans = t1();
}
// 出来之后肯定没有12 和 13
return ans < 12 ? 0 : 1;
}
// 等概率的返回[0,24]
public static int t3() {
int ans = (t2() << 4) + (t2() << 3) + (t2() << 2) + (t2() << 1) + (t2() << 0);
// ans : [0,31]
while(ans > 24){
ans = (t2() << 4) + (t2() << 3) + (t2() << 2) + (t2() << 1) + (t2() << 0);
}
return ans;
}
public static int t4() {
return t3()+33;
}
5:01不等概率随机到01等概率随机
// 你只知道x会以固定的概率返回0或者1,并且返回0/1的概率不同
public static int x() {
return Math.random() < 0.84 ? 0 : 1;
}
// 等概率的返回 0 / 1
public static int y() {
int ans = x();
while(ans == x()) {
ans = x();
}
return ans;
}
语法部分
@8:局部变量必须初始化
数据类型分为基本数据类型与引用数据类型,引用数据类型做成员变量时,初始值是null.
局部变量不初始化会报错
@9:同一个类,类的加载只加载一次
class person {
。。。。。。。。。。
}
person p1 = new person();
person p2 = new person();
person p3 = new person();
/*
在创建person对象p1的时候首先会进行类的加载,然后再进入类(构造方法)中,进行对象的构造,属性没有初始化的时候进行初始化。在创建person对象p2的时候不会再进行类的加载,直接进入类(构造方法)中,进行对象的构造,属性没有初始化的时候进行初始化,P3亦是如此。
*/
创建对象操作:@@@
首先进行类的加载,(需要注意的是同一个类只加载一次不管这个类创建了多少对象)。然后创建对象并在堆中为这个对象开辟空间。(需要注意的是这一步我们是看不见的),然后进行对象的初始化,(初始化的时候如果属性没有赋初始值,则赋默认的初始值,如果刚开始就已经赋值了则根据类中的值赋值),然后再调用构造方法,对对象的属性进行赋值。(注意调用构造方法并不是创建对象,因为在调用构造器之前对象就已经创建好了,调用构造方法只是对对象进行赋值。)
例子如下:
class person {
public person() {
this.name = "222";
this.age = 20;
}
String name = "111";
int age = 10;
public void eat() {
System.out.println("hello MSB");
}
public static void main(Strng args[]) {
person p = new person();
}
}
@10:空构造器注意点
@11:内存分析
执行流程:
mian函数是程序的入口,所以先为main方法创建栈帧,所以先进入main函数,然后进行对象的创建:
person p1 = new person( );
首先进行类的加载,会将类的字节码文件放到方法区,然后根据类的字节码文件在堆中创建对象,然后对对象
中的属性进行初始化。然后进入构造方法对对象的属性进行赋值,由于这里是空构造器,没有对对象的属性进
行赋值,然后对象创建完毕,局部变量P1指向堆中的这个对象。
栈:存放的是局部变量
堆:存放的是new出来的对象
方法区:存放的是类的字节码信息
执行流程:
首先main方法是程序的入口,所以先在栈上为main方法创建栈帧,然后开始类的加载,将类的字节码信息放到方法区,根据类的字节码信息在堆中创建对象,并对对象的属性进行初始化,然后调用类的构造方法,先在栈上为构造方法创建栈帧,并对局部变量进行赋值,(由于string类型是存放在字符串常量池中的,所以局部变量c存放的是字符串常量池中字符串的地址。)然后对对象的属性进行赋值。赋值完之后,构造器的栈帧自动销毁,然后main方法栈帧中有局部变量P1指向该对象。
字符串常量池:同一个字符串在字符串常量池中只存一份。举个例子:比如说有好几个“海淀”要放在字符串常量池中,其实字符串常量池只有一份。用的时候直接取就行。
@12:this关键字
1:this可以修饰属性
(主要是用在形参与成员变量重名 | | 局部变量与成员变量重名的时候)
2:this可以修饰方法
(主要是用在方法中,用来调用另一个方法,注意方法中可以调用另一个方法,但是方法中不可以再写一个方法)
class Person {
String name;
int age;
public void eat() {
this.bark();
............
}
public void bark() {
............
}
}
3:this可以修饰构造器
同一个类中构造器之间可以通过this相互调用,注意this修饰构造器必须放在第一行。
class Person {
String name;
int age;
public Person(String name, int age) {
this(age);
this.name = name;
}
public Person(int age) {
this.age = ag
}
public void eat() {
............
}
}