求平方根
原本是写成这样超时了
import java.util.*;
public class Solution {
/**
*
* @param x int整型
* @return int整型
*/
public int sqrt (int x) {
// write code here
int result=1;
if(x<=1){
return x;
}
for(int i=x/2;i>=1;i--){
if(x/i==i){
result=i;
break;
}
}
return result;
}
}
想了想换成二分法,因为找平方根本质还是做一个x/i==i的搜索而已
这里面有几个要点很出错:
1.因为start<=end是循环条件,所以最后return start和end里面小的那个的时候返回的是end而不是start
2.我真的搞不清临界条件…
import java.util.*;
public class Solution {
/**
*
* @param x int整型
* @return int整型
*/
public int sqrt (int x) {
// write code here
int result;
if(x<=1){
return x;
}
int start=1;
int end=x;
int mid=0;
while(start<=end){
mid=start+(end-start)/2;
if(x/mid==mid){
return mid;
}else if(x/mid>mid){
start=mid+1;
}else{
end=mid-1;
}
}
return end;
}
}
两数之和
基本的思路就是使用一个哈希表来查找另一半,Java里面实现哈希表使用的是HashMap,注意HashMao的泛型是一个键值对,常用的方法是put放进去和get查询和containsKey是否包含等等
这题有个题目里面没提到,但是默认的规定:
找两个数的和为target,但是规定不能是一个数*2=target所以要排除这种情况
找到了记得马上break…查bug查半天
import java.util.*;
public class Solution {
/**
*
* @param numbers int整型一维数组
* @param target int整型
* @return int整型一维数组
*/
public int[] twoSum (int[] numbers, int target) {
int[] result=new int[2];
HashMap<Integer,Integer> dict=new HashMap<>();
for(int i=0;i<numbers.length;i++){
if (!dict.containsKey(numbers[i])){
dict.put(numbers[i],i);
}
int temp=target-numbers[i];
if(dict.getOrDefault(temp,-1)!=-1 && dict.get(temp)!=i){
result[0]=Math.min(i+1,dict.get(temp)+1);
result[1]=Math.max(i+1,dict.get(temp)+1);
break;
}else{
continue;
}
}
return result;
}
}
然后还有一个点需要改进一下,没找到的时候默认返回{-1,-1},这个情况必须要写
下面这个写法简便了不少,不过我临场想不到…
import java.util.*;
public class Solution {
/**
*
* @param numbers int整型一维数组
* @param target int整型
* @return int整型一维数组
*/
public int[] twoSum (int[] numbers, int target) {
HashMap<Integer,Integer> map=new HashMap<>();
for (int i=0;i<numbers.length;i++){
if (map.containsKey(target-numbers[i])){
return new int[]{map.get(target-numbers[i]),i+1};
}else{
map.put(numbers[i],i+1);
}
}
return new int[]{-1,-1};
}
}
泛型
泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候可以使用泛型,泛型也可以看做一个变量用来接收数据类型
泛型的常见类型比如有:
E:Element元素
T:Type类型
ArrayList集合在定义的时候,不知道集合中都会存储什么类型的数据,所以参数类型使用的是泛型,比如ArrayList的源码里面add的输入参数用的是E,代表未知的数据类型
创建集合对象的时候,就会确定泛型的数据类型:
ArrayList< Integer >就把Integer这个数据类型作为参数传递进来,赋值给泛型E了
- 我们怎么定义含有泛型的类呢
/*
泛型可以接受任意类型的数据类型,创建对象的时候才确定数据类型
*/
public class GenericClass<E> {
private E name;
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
/*
定义含有泛型的方法
修饰符<泛型> 返回类型 方法名(参数(使用泛型))
*/
public <M> void method01(M m){
System.out.println(m);
}
}
使用的时候就像这样
public class GenericClassTest {
public static void main(String[] args){
//
GenericClass<Integer> gc=new GenericClass<>();
gc.setName(1);
Integer name=gc.getName();
System.out.println(name);
GenericClass<String> gc2=new GenericClass<>();
gc2.setName("小明");
String name2=gc2.getName();
System.out.println(name2);
//创建一个含有泛型的方法
GenericClass<Integer> gc3=new GenericClass<>();
gc3.method01(10);
gc3.method01("小明");//传递什么类型,就输入什么类型
//静态方法同样可以传递任意类型
}
}
- 怎么实现含有泛型的接口呢
含有泛型的接口,第一种使用方法:定义接口的实现类,实现接口,指定接口的泛型,比如scanner这个类实现了iterator接口,所以重写的next方法泛型默认是字符串String
第二种使用方式,接口使用什么泛型,实现类就是用什么泛型,类跟着接口走,这就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型,比如ArrayList是List接口的实现类,ArrayList和List里面用的都是泛型< E >
记得时候就记Scanner和ArrayList这两个例子就可以了
使用的时候也是给实现的类传递一个具体的数据类型就好了
- 泛型的通配符,不知道是用什么类型来接受的时候使用?表示未知通配符
使用方式:不能创建对象使用,只能作为方法的参数使用
意思就是比如说我们不知道一个对象是什么类的时候不是通常可以写成Object吗,但是泛型是不存在的Object这个说法的,而是用?来指代我们不清楚的一种类型的泛型,比如说我们不知道它是< Integer >还是< String >的时候,就写成< ? >就好了,但是定义的时候不能这么写,只是传参的时候这么写
- 泛型的上限? extends E代表使用的泛型只能是E的子类或者本身
- 下限? super E代表传递的泛型只能是E的父类或者本身
final关键字
final修饰一个类的时候表示这个类不能被继承
Java里面常见的final类有String/System
final修饰一个方法的时候表示这个方法不能被重写
final修饰一个成员变量的时候表示这个变量必须赋初值且只能初始化一次
1.当final修饰的成员变量是基本类型的时候,表示这个变量的值不能改变
2.当final修饰的成员变量是引用类型的时候,表示这个变量的地址的值不能改变,内容还是可以改变的哦
- final的优点是什么呢
JVM和java应用都会缓存final变量,可以提高性能
final变量可以安全的在多线程环境下共享,不需要额外的同步开销
使用final的时候,JVM会对方法/变量/类进行优化
工厂模式
用于实现创建者和调用者的分离
分为简单工厂/工厂方法/抽象工厂
要满足:
开闭原则:一个软件的实体应当对扩展开放,对修改关闭,也就是说,我们是不接受修改代码的
依赖倒转原则:要针对接口编程,不要针对实现编程
迪米特法则:只于你的朋友通信,而避免和陌生人通信
- 工厂模式的核心是:
实例化对象不使用new,而是用工厂方法代替
将选择实现类,创建对象统一管理和控制,从而实现调用者和实现类的解耦
- 比如我们写一个车的类,里面包含了五菱啊大众啊
public interface Car {
void name();
}
public class Wuling implements Car{
@Override
public void name() {
System.out.println("五菱宏光");
}
}
public class Tesla implements Car{
@Override
public void name() {
System.out.println("Tesla");
}
}
- 我们发现,实例化一台五菱或者大众的时候,每次都要通过修改代码来new一个,这样就不符合我们的开闭原则了,所以我们想到一个factory的写法,这个factory类用于new具体的车的子类,从意义上来讲他就像一个生产车的工厂,这样我们只用修改参数就好了,而不是来修改代码本身,这就是简单工厂模式的含义
public class Consumer {
public static void main(String[] args) {
//一般的写法
Car car1=new Wuling();
Car car2=new Tesla();
car1.name();
car2.name();
//而使用工厂模式创建的话就不一样了
Car car=CarFactory.getCar("五菱");//这样我们只用在意参数就好了,而不需要修改具体的代码类啊什么的
}
}
- 毕竟java里面万物皆对象嘛,所以工厂这个东西也被我们抽象成了一个factory类,他的功能很单一,就是拿来生产
/*
工厂模式里面的造车工厂
*/
public class CarFactory {
public static Car getCar(String car){
if (car.equals("五菱")){
return new Wuling();
}else if(car.equals("特斯拉")){
return new Tesla();
}else{
return null;
}
}
}
突然想到
先快速把这50道题刷完,然后去看看九章的模板写法背一下传到git去
设计模式的做成一个项目传到git去
写这50道题的时候看看基础,11月中旬左右必须得开始做mybatis和springboot项目了,11月得把这两个项目昨完吧
每个周末作为一个节点,提交一次上周的项目代码
我现在时常感觉自己在补天
明天
数据类型总结