斐波那契数列
第一种方法递归
public class Solution {
public int Fibonacci(int n) {
if(n==0 || n==1){
return n;
}
return Fibonacci(n-1)+Fibonacci(n-2);
}
}
第二种方法迭代代替递归
public class Solution {
public int Fibonacci(int n) {
int result=0;
int pre_1=1;
int pre_2=1;
if(n==1 || n==2){
return 1;
}
for(int i=2;i<n;i++){
result=pre_1+pre_2;
pre_1=pre_2;
pre_2=result;
}
return result;
}
}
二叉树的层序遍历
- 因为ide里面没有输入序列直接构造树的函数,所以写了一个constructTree的方法平时可以测试用
- 注意实现层序遍历的时候,中间利用的是一个队列来实现每一层节点的存储,而不是栈,因为节点需要先进先出,并用一个临时变量size来记录每一层的数量,这样就不需要使用两个队列了
- java里面可以用stack类直接实现栈,队列的实现用的不是queue,而是用linkedlist来实现哦
import java.util.*;
public class Solution {
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(){
}
public TreeNode(int val){
this.val=val;
}
}
/**
* 构造一棵树
* @param nums
* @return
*/
public TreeNode constructTree(Integer[] nums){
if (nums.length == 0) return new TreeNode(0);
Deque<TreeNode> nodeQueue = new LinkedList<>();
// 创建一个根节点
TreeNode root = new TreeNode(nums[0]);
nodeQueue.offer(root);
TreeNode cur;
// 记录当前行节点的数量(注意不一定是2的幂,而是上一行中非空节点的数量乘2)
int lineNodeNum = 2;
// 记录当前行中数字在数组中的开始位置
int startIndex = 1;
// 记录数组中剩余的元素的数量
int restLength = nums.length - 1;
while(restLength > 0) {
// 只有最后一行可以不满,其余行必须是满的
// // 若输入的数组的数量是错误的,直接跳出程序
// if (restLength < lineNodeNum) {
// System.out.println("Wrong Input!");
// return new TreeNode(0);
// }
for (int i = startIndex; i < startIndex + lineNodeNum; i = i + 2) {
// 说明已经将nums中的数字用完,此时应停止遍历,并可以直接返回root
if (i == nums.length) return root;
cur = nodeQueue.poll();
if (nums[i] != null) {
cur.left = new TreeNode(nums[i]);
nodeQueue.offer(cur.left);
}
// 同上,说明已经将nums中的数字用完,此时应停止遍历,并可以直接返回root
if (i + 1 == nums.length) return root;
if (nums[i + 1] != null) {
cur.right = new TreeNode(nums[i + 1]);
nodeQueue.offer(cur.right);
}
}
startIndex += lineNodeNum;
restLength -= lineNodeNum;
lineNodeNum = nodeQueue.size() * 2;
}
return root;
}
public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) {
// write code here
ArrayList<ArrayList<Integer>> result=new ArrayList<>();
if(root==null){
return result;
}
LinkedList<TreeNode> queue=new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size=queue.size();
ArrayList<Integer> list=new ArrayList<>();
while(size>0){
size--;
TreeNode node=queue.poll();
System.out.println(node.val);
list.add(node.val);
if(node.left!=null) queue.offer(node.left);
if(node.right!=null) queue.offer(node.right);
}
result.add(list);
}
return result;
}
public static void main(String[] args) {
Integer[] nums = {5,4,8,11,null,13,4,7,2,null,null,null,1};
Solution solution=new Solution();
TreeNode root = solution.constructTree(nums);
ArrayList<ArrayList<Integer>> result=solution.levelOrder(root);
System.out.println(result);
}
}
设计模式-单例模式
昨天学习了使用接口和类的组合,来实现一个策略模式
还是接着昨天游戏的例子来看,如何实现一个单例模式(即一个类有且只能有一个实例)
需求:因为游戏里面的水晶和基地是唯一的
所以:需要用到单例模式
下面写一个代码来完成多个英雄来攻击同一个水晶
- 首先針對基地,我們創造一個單利類,注意里面需要写一个公共的静态的同步的创建对象的方法
/**
* 基地(单例类)
*/
public class Base {
// 构造方法需要是私有的
private Base(){}
// 创建一个私有的,静态的,基地对象的引用
private static Base base=null;
// 提供一个公共的静态的创建基地对象或获取基地对象的方法
// 多个英雄中只有一个英雄能够获取基地所以我们需要使用[同步]的方法
public synchronized static Base getBase(){
if(base==null){
base=new Base();
}
return base;
}
// 基地的生命值
private int life=999;
// 基地的摧毁状态,默认是没有摧毁的
private boolean destroy=false;
public int getLife() {
return life;
}
public void setLife(int life) {
this.life = life;
}
public boolean isDestroy() {
return destroy;
}
public void setDestroy(boolean destroy) {
this.destroy = destroy;
}
}
- 如下所示,注意在实例化单例类的时候,我们不使用new,而是使用之前写到的公共的静态的同步的创建对象的方法
import java.util.BitSet;
/**
* 测试
*/
public class BaseTest {
public static void main(String[] args){
System.out.println("英雄集合攻击基地");
// 模拟两个英雄,攻击基地
new Thread(new Runnable() {
@Override
public void run() {
// 创建英雄[后裔],设置英雄单次攻击伤害值
Hero hero=new Houyi();
hero.setHeroHurt(100);//攻击力100
// 获取基地,英雄攻击基地
// 因为构造方法私有化了,所以不能这样new了 Base base=new Base();
// 而需要使用getbase得到唯一的一个基地实例,我们就把这种模式称为单例模式
Base base=Base.getBase();
destroyBase(hero,base);
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// 创建英雄[鲁班七号],设置英雄单次攻击伤害值
Hero hero=new LuBanQiHao();
hero.setHeroHurt(80);//攻击力80
// 获取基地,英雄攻击基地
// 因为构造方法私有化了,所以不能这样new了 Base base=new Base();
// 而需要使用getbase得到唯一的一个基地实例,我们就把这种模式称为单例模式
Base base=Base.getBase();
destroyBase(hero,base);
}
}).start();
}
// 英雄摧毁基地的方法
private static void destroyBase(Hero hero, Base base) {
//1.显示是哪个英雄在攻击,伤害是多少
System.out.println("英雄"+hero.getHeroname()+"伤害值"+hero.getHeroHurt());
// 2.攻击基地
// 判断基地生命值>0,若生命值>0,英雄持续攻击
while(base.getLife()>0) {
//为了让基地一段时间内只能被一个英雄摧毁,我们需要添加一个同步
synchronized (base){
//写了synchronized,这个大括号里面的代码,一次只能被一个线程使用
if(!base.isDestroy()){
// 没有被摧毁
//攻击基地,基地的剩余生命值减少
//基地的剩余生命值=当前生命值-攻击力
base.setLife(base.getLife()-hero.getHeroHurt());
//模拟攻击基地的耗时操作
try{
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
};
// 若没有被摧毁
//判断基地生命值>0,若生命值>0,英雄攻击
if(base.getLife()>0){
System.out.println("英雄"+hero.getHeroname()+"剩余生命值"+base.getLife());
}else{
//基地生命值<=0,说明基地已被摧毁,更新状态为摧毁,游戏胜利
base.setDestroy(true);
System.out.println("基地已被["+hero.getHeroname()+"]摧毁,游戏胜利");
}
}
}
// 2.1判断当前基地的状态是否已被摧毁
}
}
}
abstract object & interface
面试经常问到的问题,接口和抽象类的区别是什么呢?
我们先了解一下抽象类
-
抽象方法所在的类,必须是抽象类才行,抽象类里面也可以有普通的成员方法
-
如何使用抽象类和抽象方法呢?这个过程参见昨天写hero和houyi,不再赘述了
1.首先,不能直接new一个抽象类的对象
2.必须用一个子类来继承抽象类
3.子类必须覆盖重写抽象父类当中[所有]的抽象方法
4.创建(new)一个子类对象进行使用,运行的就是子类里面的方法了 -
抽象类和方法的注意事项
1.抽象类不能创建对象
2.抽象类中,可以有构造方法,抽象父类的构造方法在子类的构造方法之前执行,new一个子类的时候,父类的构造方法仍然是要执行的
3.一个抽象类中,不一定包含抽象方法
4.子类仍然可以是抽象类,比如动物(抽象类)->狗(抽象类)->博美(可实例化)
然后讲一下接口
接口就是一种公共的规范标准,接口是一种引用数据类型,最重要的内容就是其中的抽象方法
- 换成了关键字interface之后,编译生成的字节码文件仍然是.java—>.class
- 接口的构成
java7,接口中包含常量,抽象abstra方法
java8,额外包含默认defaul方法,静态static方法
java9,额外包含私有private方法
抽象方法的格式:public abstract 返回值类型 方法名称(参数列表);(没有大括号也就是方法体,且必须是public和abstract不能是其他的,如果不写的话,默认就是public abstract的)
- 接口使用步骤
1.接口不能直接使用,必须有一个"实现类"来实现该接口,可以类比extends
2.接口的实现类必须覆盖重写接口中所有的抽象方法
3.创建实现类的对象,进行使用
可以看到implements和继承的规定来说是差不多的
默认方法的格式:public default 返回值类型 方法名称(参数列表){方法体};接口当中的默认方法可以解决接口的升级问题,默认方法也可以被覆盖重写
静态方法的格式:public static 返回类型 方法名称(参数列表){方法体};使用的时候通过接口名称直接调用其中的静态方法myInterface.methodstatic();
私有方法的格式:private 返回类型 方法名称(参数列表){方法体};解决多个默认方法之间重复代码问题
接口当中也可以定义成员变量,但是必须使用public static final三个关键字进行修饰,从效果上看这就是接口的常量
明天
工厂模式/final
搞个小项目
哎,真不想去实验室,每天都在被老师pua,放嘲讽,不放嘲讽会死啊(白眼),快点毕业吧