目录
java使用省略号代替多参数(参数类型... 参数名)java使用省略号代替多参数(参数类型... 参数名)
学习目标:
- 面向对象的封装特性
- 局部变量和成员变量的作用域问题
- 静态属性、静态方法、静态代码块
- 面向对象的继承特性
- 继承中构造方法的细节
- 面向对象的多态特性
- 抽象方法与抽象类
- 接口
学习内容:
面向对象的封装特性:
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问,把尽可能多的东西藏起来,只对外提供便捷的接口。
使用步骤:
1.属性私有化:将属性的访问权限修饰符更改为 private
2.提供公共的操作和访问方法(getter和setter方法):每个属性创建俩个方法,一个设置值的方法setXXX,一个是读取值的方法getXXX
3.根据需要,在操作和访问方法中添加合理的判断和处理
封装的优势:
1.便于使用者正确使用系统,防止错误修改属性。(提高了程序的安全性和健壮性)
2.有助于系统之间的松耦合(低耦合),提高系统独立性
3.提高软件的可重用性(相对独立的整体,高内聚)
类的定义规范:(JavaBean规范)
- 属性私有化
- 提供公共的操作和访问方法
- 编写无参构造方法
- 实现序列化接口 (Serializable接口)
PS:一个java源代码文件中(.java)可以编写很多类,但是只能有一个类是被 public 修饰,且这个类的名字与文件名一致
建议:没有特殊情况,一个源文件之写一个类
局部变量和成员变量的作用域问题:
成员变量:(1)定义在类里,方法之外的变量。
(2)成员变量可以不显式初始化,它们可以由系统设定默认值;
(3)成员变量在所在类被实例化后,存在堆内存中
局部变量:(1)定义在方法体内部的变量。
(2)局部变量没有默认值,所以必须设定初始赋值。
(3)局部变量在所在方法调用时,存在栈内存空间中。
静态属性、静态方法、静态代码块:
定义:
用static修饰符修饰的属性和方法叫作静态属性和静态方法
静态代码块只能写在类中方法外,不能写在方法中,它会随着类的加载而优先于各种代码块和构造方法的加载,并且只会 加载一次,如果出现多个静态代码块,会按照书写顺序加载
区别:
1.在内存中存放的位置不同:所有static修饰的属性和方法都存放在内存的方法区里,而非静态的都存在堆内存中
2.出现的时机不同:静态属性和方法在没创建对象之前就存在,而非静态的需要在创建对象才存在
3.静态属性是整个类都公用的
4.生命周期不一样,静态在类消失后被销毁,非静态在对象销毁后销毁
5.用法:静态的可以直接通过类名访问,非静态只能通过对象进行访问
例子:
public class StaticTest {
public static void main(String[] args) {
test t =new test();
test a = new test();
System.out.println(t.a);
System.out.println(test.c);
//test.eat() eat是普通方法,还想被直接调用?只能像下一行一样,被对象调用!
t.eat();
//run是静态方法,权限高,可以被对象调用也可被类名调用
t.run();
test.run();
}
static class test{
String a ="我是普通变量a,只能被对象调用";
static String c = "我是静态变量c,可被对象或类名调用";
//非静态代码块 每创建一个对象就执行一次
{
System.out.println("我是非静态代码块,只能要创建对象,我就执行一次!假如我被创建两次对象,就执行2次!");
}
//静态代码块 只能执行一次
static{
System.out.println("我是静态代码块,我只执行一次");
}
//普通方法 只可被对象调用
public void eat(){
System.out.println("我是eat方法,是普通方法,我权限低,只能被对象调用!");
}
//静态方法 可被对象丶类名调用
public static void run(){
System.out.println("我是run方法,是静态方法,权限高,可以直接被类名调用,也可以被对象调用");
}
}
}
/*(1)非静态属:性(即普通属性)只能被对象调用
静态属性:可被对象或类名直接调用。(权限更大)
(2)非静态方法(即无static修饰符的方法):只能被对象调用
静态方法:可被对象或者类名直接调用。(权限更大)
(3)非静态代码块:每次创建一个对象就执行一次
静态代码块:只在类加载到内存的时候执行一次!在以后调用类的时候不再执行!**/
输出:
我是静态代码块,我只执行一次
我是非静态代码块,只能要创建对象,我就执行一次!假如我被创建两次对象,就执行2次!
我是非静态代码块,只能要创建对象,我就执行一次!假如我被创建两次对象,就执行2次!
我是普通变量a,只能被对象调用
我是静态变量c,可被对象或类名调用
我是eat方法,是普通方法,我权限低,只能被对象调用!
我是run方法,是静态方法,权限高,可以直接被类名调用,也可以被对象调用
我是run方法,是静态方法,权限高,可以直接被类名调用,也可以被对象调用
静态代码块补充:
作用:
一般情况下,有些代码需要在项目启动的时候就执行,这时候就需要静态代码块,比如一个项目启动需要加载配置文件,或初始化内容等。
静态代码块不能出现在任何方法体内:
对于普通方法:普通方法是需要加载类new出一个实例化对象,通过运行这个对象才能运行代码块,而静态方法随着类加载就运行了。
对于静态方法:在类加载时静态方法也加载了,但是必须需要类名或者对象名才可以访问,相比于静态代码块,静态方法是被动运行,而静态代码块是主动运行。
静态代码块不能访问普通变量:
普通变量只能通过对象调用的,所以普通变量不能放在静态代码块中。
执行顺序:
静态代码块>构造代码块>构造函数>普通代码块
使用static的注意事项:
- 带静态修饰符的方法只能访问静态属性
- 非静态方法既能访问静态属性也能访问非静态属性
- 非静态方法不能定义静态变量
- 静态方法不能使用this关键字
- 静态方法不能调用非静态方法,反之可以
父子类中静态和非静态的关系:
- 对于非静态属性,子类可以继承父类非静态属性,但是当父子类出现相同的非静态属性时,不会发生子类的重写并覆盖父类的非静态属性,而是隐藏父类的非静态属性
- 对于非静态方法,子类可以继承并重写父类的非静态方法
- 对于静态属性,子类可以继承父类的静态属性,但是如何和非静态属性一样时,会被隐藏
- 对于静态方法,子类可以继承父类的静态方法,但是不能重写静态方法,同名时会隐藏父类的
注:静态属性、静态方法、非静态属性都可以被继承和隐藏,但是不可以被重写,
非静态方法可以被重写和继承
面向对象的继承特性:
继承涉及的概念
- 理解: 子类自动共享父类数据和方法的机制,这是类之间的关系就是叫做继承。继承是在一个现有类型的基础上,通过增加新的方法或者重定义已有方法(即重写)的方式,产生一个新的类型。
- 继承:被继承的类称为父类(超类),继承父类的类称为子类(派生类) ,继承是指一个对象直接使用另一个对象的属性和方法,通过继承可以实现代码重用。
- super关键字:可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类 使用super调用父类中的属性,调用父类的方法,调用父类中的构造方法 super 表示父类对象的默认引用 super如果子类要调用父类被覆盖的实例方法,可用super作为调用者调用父类被覆盖的实例方法 使用super调用父类方法,使用super调用父类的构造方法。
- 方法的覆写:方法覆写又称为重写;
- 产生原因:当父类中某个方法不适合于子类时,子类出现父类一模一样的方法 调用被覆盖的父类方法:使用super.方法名(实参); 方法覆写时应遵循的原则(一同,两小,一大): (一同):方法签名必须相同; (两小):子类方法的返回值类型比父类方法的返回值类型更小或相等;子类方法声明抛出的异常应比父类方法申明抛出的异常更小或相等 (一大):子类方法的访问权限应比父类方法更大或相等。
- 子类对象实例化过程:
- 子类对象的实例化: 子类对象在实例化之前必须首先调用父类中的构造方法之后再调用自身的构造方法;在子类进行实例化操作时,首先会让其父类进行实例化操作(调用父类的构造方法),之后子类再自己进行实例化操作;
- 子类访问父类; 子类不能直接访问父类的私有成员,但是子类可以调用父类中的非私有方法来间接访问父类的私有成员。
类与继承
(1)类的分类
- 类:使用class定义且不含有抽象方法的类。
- 抽象类:使用abstract class定义的类,它可以含有,也可以不含有抽象方法。
- 接口:使用interface定义的类。
(2)类的继承规律
- 类可以继承(extends)类,可以继承(extends)抽象类,可以继承(implements)接口。
- 抽象类可以继承(extends)类,可以继承(extends)抽象类,可以继承(implements)接口。
- 接口只能继承(extends)接口。
(3)继承规律遵循的约束
- 类和抽象类都只能最多继承一个类,或者最多继承一个抽象类,并且这两种情况是互斥的,也就是说它们要么继承一个类,要么继承一个抽象类。
- 类、抽象类和接口在继承接口时,不受数量的约束,理论上可以继承无限多个接口。对于类来说,它必须实现它所继承的所有接口中定义的全部方法。
- 抽象类继承抽象类,或者实现接口时,可以部分、全部或者完全不实现父类抽象类的抽象(abstract)方法,或者父类接口中定义的接口。
- 类继承抽象类,或者实现接口时,必须全部实现父类抽象类的全部抽象(abstract)方法,或者父类接口中定义的全部接口。
修饰符与继承
(1)类成员访问修饰符与访问能力之间的关系:
类型 | private | 无修饰 | protected | public |
---|---|---|---|---|
同一类 | 可访问 | 可访问 | 可访问 | 可访问 |
同一包中子类 | 不可访问 | 可访问 | 可访问 | 可访问 |
同一包中的非子类 | 不可访问 | 可访问 | 可访问 | 可访问 |
不同包中的子类 | 不可访问 | 不可访问 | 可访问 | 可访问 |
不同包中的非子类 | 不可访问 | 不可访问 | 不可访问 | 可访问 |
(2)子类不能继承父类中访问权限为 private 的成员变量和方法,也不能继承父类的构造方法。子类可以重写父类的方法,及命名与父类同名的成员变量。
代码
public class Demo {
public static void main(String[] args) {
Apple apple =new Apple(10);
}
}
public class Fruits {
private int num;
public Fruits(){
System.out.println("这是Fruits类的不带参构造方法");
}
public Fruits(int num){
System.out.println("这是Fruits类的带参构造方法"+"数量为:"+num);
}
}
public class Apple extends Fruits{
Apple(){
System.out.println("这是Apple类的不带参构造方法");
}
Apple(int num){
super(num);
System.out.println("这是Apple类的带参构造方法");
}
}
//
这是Fruits类的带参构造方法数量为:10
这是Apple类的带参构造方法
继承的优缺点
- 优点:提高了代码的复用性;让类与类之间产生了关系,提供了多态的前提。
- 缺点:提高了类之间的耦合性,耦合度高就会造成代码之间的联系越紧密,代码独立性越差。
继承中构造方法的细节:
- A:案例演示
- 父类没有无参构造方法,子类怎么办?
- B:注意事项
- super(…)或者this(….)必须出现在构造方法的第一条语句上
1.可以使用super的有参构造方法:
package Demo2;
import Demo2.Son;
public class Demo2 {
public static void main(String[] args){
Son s1 = new Son();
System.out.println(s1.getName() + "---" + s1.getAge());
System.out.println("----------");
Son s2 = new Son("张三", 23);
System.out.println(s2.getName() + "---" + s2.getAge());
}
}
public class Father{
private String name;
private int age;
/*
public Father(){ //空参构造
System.out.println("Father 空参构造");
}
*/
public Father(String name, int age){ //有参构造
this.name = name;
this.age = age;
System.out.println("Father 有参构造");
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
}
public class Son extends Father{
public Son(){
super("李四",24);
System.out.println("Son 空参构造");
}
public Son(String name, int age){
super(name, age);
System.out.println("Son 有参构造");
}
}
2.使用this调用自己的有参构造方法:
package Demo2;
import Demo2.Son;
public class Demo2 {
public static void main(String[] args){
Son s1 = new Son();
System.out.println(s1.getName() + "---" + s1.getAge());
System.out.println("----------");
Son s2 = new Son("张三", 23);
System.out.println(s2.getName() + "---" + s2.getAge());
}
}
public class Father{
private String name;
private int age;
/*
public Father(){ //空参构造
System.out.println("Father 空参构造");
}
*/
public Father(String name, int age){ //有参构造
this.name = name;
this.age = age;
System.out.println("Father 有参构造");
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
}
class Son extends Father{
public Son(){
//this与super为平行关系,只能存在一个
this("李四", 24); //调用本类中的构造方法
System.out.println("Son 空参构造");
}
public Son(String name, int age){
super(name, age);
System.out.println("Son 有参构造");
}
}
面向对象的多态特性:
形式
父类类型 对象名称 = new 子类构造器; 接口 对象名称 = new 实现类构造器;
父类类型的范围 > 子类类型范围的。
概念
同一个类型的对象,执行同一个行为,在不同的状态下会表现出不同的行为特征。
识别技巧
对于方法的调用:编译看左边,运行看右边。 对于变量的调用:编译看左边,运行看左边。
使用前提
(1) 必须存在继承或者实现关系。 (2) 必须存在父类类型的变量引用子类类型的对象。 (3) 需要存在方法重写。
public class Main {
public static void main(String[] args) {
Person p = new Student();
p.run(); // Student.run
}
}
class Person {
public void run() {
System.out.println("Person.run");
}
}
class Student extends Person {
@Override
public void run() {
System.out.println("Student.run");
}
}
补充例子
java使用省略号代替多参数(参数类型... 参数名)java使用省略号代替多参数(参数类型... 参数名)
public class Main {
public static void main(String[] args) {
// 给一个有普通收入、工资收入和享受国务院特殊津贴的小伙伴算税:
Income[] incomes = new Income[] {
new Income(3000),
new Salary(7500),
new StateCouncilSpecialAllowance(15000)
};
System.out.println(totalTax(incomes));
}
// Income... incomes == Income[] incomes
public static double totalTax(Income... incomes) {
double total = 0;
for (Income income: incomes) {
total = total + income.getTax();
}
return total;
}
}
class Income {
protected double income;
public Income(double income) {
this.income = income;
}
public double getTax() {
return income * 0.1; // 税率10%
}
}
class Salary extends Income {
public Salary(double income) {
super(income);
}
@Override
public double getTax() {
if (income <= 5000) {
return 0;
}
return (income - 5000) * 0.2;
}
}
class StateCouncilSpecialAllowance extends Income {
public StateCouncilSpecialAllowance(double income) {
super(income);
}
@Override
public double getTax() {
return 0;
}
}
观察totalTax()
方法:利用多态,totalTax()
方法只需要和Income
打交道,它完全不需要知道Salary
和StateCouncilSpecialAllowance
的存在,就可以正确计算出总的税。如果我们要新增一种稿费收入,只需要从Income
派生,然后正确覆写getTax()
方法就可以。把新的类型传入totalTax()
,不需要修改任何代码。
可见,多态具有一个非常强大的功能,就是允许添加更多类型的子类实现功能扩展,却不需要修改基于父类的代码。
抽象方法与抽象类
定义:
如果一个class
定义了方法,但没有具体执行代码,这个方法就是抽象方法,抽象方法用abstract
修饰。因为无法执行抽象方法,因此这个类也必须申明为抽象类(abstract class)。使用abstract
修饰的类就是抽象类。我们无法实例化一个抽象类。
因为抽象类本身被设计成只能用于被继承,因此,抽象类可以强迫子类实现其定义的抽象方法,否则编译会报错。因此,抽象方法实际上相当于定义了“规范”。 例如,Person
类定义了抽象方法run()
,那么,在实现子类Student
的时候,就必须覆写run()
方法:
public class Main {
public static void main(String[] args) {
Person p = new Student();
p.run();
}
}
abstract class Person {
public abstract void run();
}
class Student extends Person {
@Override
public void run() {
System.out.println("Student.run");
}
}
用法
1.不能直接创建new抽象类对象。
2.必须用一个子类,继承抽象的父类;
3.子类必须覆盖重写 父类当中所有的抽象方法
覆盖重写(实现):去掉抽象方法的abstract关键字,然后补上方法体大括号的内容
4.创建子类对象使用
PS:
- 抽象类不能创建对象
- 抽象类可以有构造方法
- 抽象类中不一定包含抽象方法
- 抽象类的子类,必须覆盖重写所有的抽象方法
用例
public class Demo {
public static void main(String[] args) {
// 给一个有工资收入和享受国务院特殊津贴的小伙伴算税:
Income[] incomes = new Income[] {
new SalaryIncome(7500),
new RoyaltyIncome(15000)
};
System.out.println(totalTax(incomes));
}
public static double totalTax(Income[] incomes) {
double total = 0;
for (Income income: incomes) {
total = total + income.getTax();
}
return total;
}
}
public abstract class Income {
protected double income;
public Income(double income){
this.income=income;
}
public abstract double getTax();
}
public class SalaryIncome extends Income{
public SalaryIncome(double income) {
super(income);
}
@Override
public double getTax(){
if (income <= 5000) {
return 0;
}
return (income - 5000) * 0.2;
}
}
public class RoyaltyIncome extends Income{
public RoyaltyIncome(double income) {
super(income);
}
@Override
public double getTax(){
return income*0.2;
}
}
接口
概念
接口可以理解为一种特殊的类,里面全部是由全局常量和公共的抽象方法所组成。接口是解决Java无法使用多继承的一种手段,但是接口在实际中更多的作用是制定标准的。或者我们可以直接把接口理解为100%的抽象类,既接口中的方法必须全部是抽象方法。
接口和抽象类的区别
abstract class | interface | |
构造方法 | 有构造方法,用于子类实例化使用。 | 没有构造方法 |
成员变量 | 可以是变量,也可以是常量。 | 只能是常量。 默认修饰符:public static final |
成员方法 | 可以是抽象的,也可以是非抽象的。 | jdk1.7只能是抽象的。默认修饰符:public abstract (推荐:默认修饰符请自己永远手动给出) jdk1.8可以写以default和static开头的具体方法 |
继承 | 只能extends一个class | 可以implements多个interface |
default方法
public class Main {
public static void main(String[] args) {
Person p = new Student("Xiao Ming");
p.run();
}
}
interface Person {
String getName();
default void run() {
System.out.println(getName() + " run");
}
}
class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
实现类可以不必覆写default
方法。default
方法的目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default
方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。 default
方法和抽象类的普通方法是有所不同的。因为interface
没有字段,default
方法无法访问字段,而抽象类的普通方法可以访问实例字段。
LintCode刷题:
·柠檬水找零
定义两个int变量,用来放五元的和十元的,五元进入是five变量要++,十元变量进入时需要five变量 --,在20元变量进入的时候需要判断十元变量是否为0,ten为0时,需要five-3,ten不为0时,ten--,five--,只需要最后判断five值是否为负值即可。
import java.util.List;
public class Solution {
public boolean lemonadeChange(List<Integer> bills) {
int five = 0, ten = 0;
for (int i : bills) {
if (i == 5) {
five++;
}
if (i == 10) {
ten++;
five--;
}
if (i == 20) {
if (ten == 0) {
five -= 3;
} else {
five--;
ten--;
}
}
}
if (ten < 0 || five < 0)
return false;
else
return true;
}
}
·最大子数组
按照K的大小创建数组,按照A的数组遍历,找到大的地方记录下标值即可。
public class Solution {
public int[] largestSubarray(int[] A, int K) {
int[] res = new int[K];
int start = 0;
for (int i = 0; i <= A.length - K; i++) {
for(int j = 0; j < K; j++) {
if(A[i + j] > A[start + j]) {
start = i;
break;
}
else if (A[i + j] < A[start + j]){
break;
}
}
}
for(int i = 0; i < K; i++) {
res[i] = A[start + i];
}
return res;
}
}
·数组中的K-diff对
1、先把数组排序完,之后建立双指针每次往后遍历第一个指针后面的所有元素,当第一个指针或第二个指针后面的元素和指针指向元素相同时,把指针向后移一位,当两个指针指向同一个时,把后面的指针移一位,当后一位超出范围时跳出循环,因为按顺序排序,所以当两个指针相差超过K时接下来的一定比K大,所以当相差小于K时才会第二个指针向后移,等于K时标记++即可。
import java.util.Arrays;
public class Solution {
public int findPairs(int[] nums, int k) {
Arrays.sort(nums);
int temp = 0;
for (int i = 0, j = 0; i < nums.length; i++) {
if (i == j) j++;
while (i + 1 < nums.length && nums[i + 1] == nums[i]) i++;
while (j + 1 < nums.length && nums[j + 1] == nums[j]) j++;
while (j < nums.length && Math.abs(nums[j] - nums[i]) < k) j++;
if (j >= nums.length) break;
if (Math.abs(nums[j] - nums[i]) == k) {
temp++;
j++;
}
}
return temp;
}
public static void main(String[] args) {
Solution solution = new Solution();
int[] arr = new int[]{3,1,4,1,5};
System.out.println(solution.findPairs(arr,2));
}
}
·最大子数组III
动态规划,做好要把数组分为K组的准备,建立两个长度比length和k大1的二维数组,然后需要知道,global数组代表全局最优解,(可以不包括本身元素),local时局部最优解,(必须包括当前元素)i表示取到多少个数,j表示分成多少组,当i和j相等时,就是直接在取数和分组都小1的下表元素下加上这个元素。在i和j不相等的时候,局部最优解需要比较全局中少一个元素并且分组少一和局部元素少一相同分组数量的大小,然后再加上当前元素。而全局最优解只需要比较全局少取当前元素相同分组和当前局部最优解的大小即可。
public class Solution {
public int maxSubArray(int[] nums, int k) {
int n = nums.length;
if (n < k){
return 0;
}
int[][] local = new int[n + 1][k + 1];
int[][] global = new int[n + 1][k + 1];
for (int i = 1; i <= n; i++){
for (int j = Math.min(i,k); j > 0; j--){
if(i == j){
local[i][j] = local[i - 1][j - 1] + nums[i - 1];
global[i][j] = global[i - 1][j - 1] + nums[i - 1];
}
else{
local[i][j] = Math.max(local[i - 1][j], global[i - 1][j - 1]) + nums[i - 1];
global[i][j] = Math.max(global[i - 1][j], local[i][j]);
}
}
}
return global[n][k];
}
}
·完全平方数
先开方后直接转成int型再判断int值平方是否等于num即可
public class Solution {
public boolean isPerfectSquare(int num) {
int a = (int)Math.sqrt(num);
if (a*a==num){
return true;}
else{
return false;
}
}
}
·最大回文乘积
找到最大的n位数,并且写一个制造回文数的方法,因为n位×n位形成的回文数是2n位的所以只要从当前n位最大数,把它构成为回文数,然后再从最大的开始遍历,寻求可以整除的地方。
public class Solution {
public int largestPalindrome(int n){
if (n==1)
return 9;
long maxNumber = (long) Math.pow(10,n)-1;
long minNumber =(long) Math.pow(10,n-1);
long maxlimit =maxNumber*maxNumber;
long temp =maxNumber;
while (true){
long firstHalf=palindrome(temp--);
if (firstHalf>maxlimit)
continue;
for (long i = maxNumber;i>=minNumber;i--){
if (firstHalf/i>maxNumber)
break;
if (firstHalf%i==0){
System.out.println(firstHalf);
return (int) (firstHalf%1337);
}
}
}
}
public long palindrome(long firstHalf) {
StringBuffer stringBuffer = new StringBuffer(Long.toString(firstHalf));
String str = firstHalf+stringBuffer.reverse().toString();
return Long.parseLong(str);
}
}
·音乐组合
用for循环遍历会太过于慢了,所以直接建立一维数组,拿来放60以内的音乐,只需要拿到60-music的有没有就可以把temp++;
public class Solution {
public long musicPairs(int[] musics) {
int [] arr =new int[60];
long temp =0;
for (int music:musics){
if (music%60==0){
temp+=arr[0];
arr[0]++;
continue;
}
temp+=arr[60-music];
arr[music]++;
}
return temp;
}
}
·左叶子的和
先把根节点放入,左右子节点判断是否为空,在不为空的时候
public class Solution {
public int sumOfLeftLeaves(TreeNode root) {
int sum = 0;
if (root == null) {
return 0;
}
if (root.left != null) {
TreeNode left = root.left;
if (left.left == null && left.right == null) {
sum += left.val;
} else
sum += sumOfLeftLeaves(left);
}
if (root.right!=null){
TreeNode right= root.right;
sum+=sumOfLeftLeaves(right);
}
return sum;
}
}
·判断重复
把数组放入hashset中,比较长度即可
import java.util.HashSet;
import java.util.LinkedHashSet;
public class Solution {
public boolean isUnique(int[] arr) {
HashSet set =new LinkedHashSet();
for (int i:arr){
set.add(i);
}
if (set.size()==arr.length){
return true;
}else
return false;
}
}
·约翰的生意
public class Solution {
/**
* @param A: The prices [i]
* @param k:
* @return: The ans array
*/
public int[] business(int[] A, int k) {
// Write your code here
Deque<Integer> dq = new LinkedList<>();
for (int i = 0; i < A.length && i < k + 1; i++) {
while (!dq.isEmpty() && A[dq.peekLast()] > A[i]) {
dq.pollLast();
}
dq.offer(i);
}
int[] res = new int[A.length];
for (int i = 0; i < A.length; i++) {
res[i] = A[i] - A[dq.peekFirst()];
if (i > k && dq.peekFirst() == i - k) {
dq.pollFirst();
}
if (i + k + 1 < A.length) {
while (!dq.isEmpty() && A[dq.peekLast()] > A[i + k + 1]) {
dq.pollLast();
}
dq.offer(i + k + 1);
}
}
return res;
}
}
学习感慨:
关于迟了这么久才更新继续学习,自己也感觉自己挺废的,从去年九月份左右接触到了虚拟币,听到了同学发财的消息,想着和他一起实现财富自由把自己从小到大的积蓄也拿了出来,一开始只是小玩玩,从1000变成了3500,取出来1000本金后,一晚上就爆仓爆玩,便开始去研究区块链,学习k线,macd,kdj这些k线图一直在学习,然后在ETH2925买入了一个,再把自己的积蓄放了进去,在元宇宙的币上面也是赚了钱,当本金从八万变成15万的时候心动了,把自己所有钱全部投入了进去,但是还是没有敬畏市场的心,在这里我以为可以把20万本金再次翻倍时,从12月份一路跌倒了现在,多次的爆仓也让我明白,散户和新手,在这个吃人不吐骨头的大资金盘里,很难捞到油水,开学就大四了,学会面对现实,在之后的日子里每天保持更新,学习丰富自己,脚踏实地,不做发大财的白日梦,每天踏踏实实学习。
学习产出:
学习博客*1
刷题*8