diff --git a/.DS_Store b/.DS_Store index 49776b3..714766f 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e7e8552 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ + +JVM/虚拟机执行子系统/.DS_Store +Utils/jdk8新特性/stream/.DS_Store +Utils/jdk8新特性/lambda/lambda_demo/lambda_demo.iml +Utils/jdk8新特性/lambda/lambda_demo/.idea/workspace.xml +Utils/jdk8新特性/.DS_Store +JVM/虚拟机执行子系统/.DS_Store +Utils/.DS_Store +Utils/jdk8新特性/lambda/lambda_demo/.idea/$CACHE_FILE$ +*.class +Algorithm/LeetCode/leetcode/.idea/workspace.xml +Algorithm/LeetCode/leetcode/.idea/workspace.xml +SourceCode/.DS_Store +SourceCode/mybatis/mybatis怎么加载进spring的/.DS_Store +SourceCode/mybatis/mybatis怎么加载进spring的/img/.DS_Store +SourceCode/TreeMap/.DS_Store +spring/ioc/.DS_Store +spring/aop/JDK和CGlib动态代理/img/.DS_Store +spring/aop/JDK和CGlib动态代理/.DS_Store +spring/ioc/bean的初始化/.DS_Store +spring/.DS_Store +spring/aop/.DS_Store +spring/.DS_Store diff --git a/Algorithm/.DS_Store b/Algorithm/.DS_Store index 67f0215..5b96121 100644 Binary files a/Algorithm/.DS_Store and b/Algorithm/.DS_Store differ diff --git a/Algorithm/LeetCode/leetcode/.idea/compiler.xml b/Algorithm/LeetCode/leetcode/.idea/compiler.xml deleted file mode 100644 index a1757ae..0000000 --- a/Algorithm/LeetCode/leetcode/.idea/compiler.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/Algorithm/LeetCode/leetcode/.idea/misc.xml b/Algorithm/LeetCode/leetcode/.idea/misc.xml deleted file mode 100644 index fa53a49..0000000 --- a/Algorithm/LeetCode/leetcode/.idea/misc.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/Algorithm/LeetCode/leetcode/.idea/modules.xml b/Algorithm/LeetCode/leetcode/.idea/modules.xml deleted file mode 100644 index 8fd8bd1..0000000 --- a/Algorithm/LeetCode/leetcode/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/Algorithm/LeetCode/leetcode/.idea/workspace.xml b/Algorithm/LeetCode/leetcode/.idea/workspace.xml deleted file mode 100644 index 0be58b8..0000000 --- a/Algorithm/LeetCode/leetcode/.idea/workspace.xml +++ /dev/null @@ -1,471 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - true - true - - - true - DEFINITION_ORDER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + 1579134050324 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git "a/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/lambda_demo.iml" "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/lambda_demo.iml" new file mode 100644 index 0000000..78b2cc5 --- /dev/null +++ "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/lambda_demo.iml" @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git "a/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/pom.xml" "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/pom.xml" new file mode 100644 index 0000000..0a0c1f7 --- /dev/null +++ "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/pom.xml" @@ -0,0 +1,42 @@ + + + 4.0.0 + + org.example + lambda_demo + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.1.5.RELEASE + + + + + + org.projectlombok + lombok + 1.18.10 + provided + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + + + + com.alibaba + fastjson + 1.2.4 + + + + + \ No newline at end of file diff --git "a/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/Student.java" "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/Student.java" new file mode 100644 index 0000000..c62b23f --- /dev/null +++ "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/Student.java" @@ -0,0 +1,26 @@ +package com.leosanqing; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * @Author: leosanqing + * @Date: 2020/1/17 上午7:54 + * @Package: com.leosanqing + * @Description: 学生类 + */ +@Data +@AllArgsConstructor +public class Student { + private String name; + private int age; + private String sex; + /** + * 课程 + */ + private String subject; + private int height; + private int weight; + private String teacher; + +} diff --git "a/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/cart/Sku.java" "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/cart/Sku.java" new file mode 100644 index 0000000..6add2dc --- /dev/null +++ "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/cart/Sku.java" @@ -0,0 +1,20 @@ +package com.leosanqing.cart; + +import com.leosanqing.enums.CategoryEnum; +import lombok.Data; + +/** + * @Author: leosanqing + * @Date: 2020/1/16 上午8:23 + * @Package: com.leosanqing.cart + * @Description: 购物车商品规格对象 + */ +@Data +public class Sku { + private Integer skuId; + private String name; + private Double price; + private Integer totalNum; + private Double totalPrice; + private Enum category; +} diff --git "a/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/enums/CategoryEnum.java" "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/enums/CategoryEnum.java" new file mode 100644 index 0000000..0527718 --- /dev/null +++ "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/enums/CategoryEnum.java" @@ -0,0 +1,26 @@ +package com.leosanqing.enums; + +import lombok.Getter; + +/** + * @Author: leosanqing + * @Date: 2020/1/16 上午8:26 + * @Package: com.leosanqing.cart + * @Description: 分类枚举 + */ +public enum CategoryEnum { + FOOD(10,"食品"), + CLOTHING(20,"衣服"), + BOOK(30,"图书"), + ELECTRONIC(40,"电子"), + + + ; + private int code; + private String name; + + CategoryEnum(int code,String name){ + this.code = code; + this.name = name; + } +} diff --git "a/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/predicate/AgePredicate.java" "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/predicate/AgePredicate.java" new file mode 100644 index 0000000..9a5509f --- /dev/null +++ "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/predicate/AgePredicate.java" @@ -0,0 +1,16 @@ +package com.leosanqing.predicate; + +import com.leosanqing.Student; + +/** + * @Author: leosanqing + * @Date: 2020/1/19 下午11:49 + * @Package: com.leosanqing.predicate + * @Description: 根据年龄过滤 + */ +public class AgePredicate implements StudentPredicate { + @Override + public boolean filter(Student student) { + return student.getAge() > 20; + } +} diff --git "a/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/predicate/StudentPredicate.java" "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/predicate/StudentPredicate.java" new file mode 100644 index 0000000..436a26a --- /dev/null +++ "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/predicate/StudentPredicate.java" @@ -0,0 +1,13 @@ +package com.leosanqing.predicate; + +import com.leosanqing.Student; + +/** + * @Author: leosanqing + * @Date: 2020/1/19 下午11:41 + * @Package: com.leosanqing.service + * @Description: 学生条件接口 + */ +public interface StudentPredicate { + boolean filter(Student student); +} diff --git "a/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/predicate/TeacherPredicate.java" "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/predicate/TeacherPredicate.java" new file mode 100644 index 0000000..b80f5d2 --- /dev/null +++ "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/predicate/TeacherPredicate.java" @@ -0,0 +1,16 @@ +package com.leosanqing.predicate; + +import com.leosanqing.Student; + +/** + * @Author: leosanqing + * @Date: 2020/1/19 下午11:51 + * @Package: com.leosanqing.predicate + * @Description: 根据老师过滤 + */ +public class TeacherPredicate implements StudentPredicate{ + @Override + public boolean filter(Student student) { + return "如来".equals(student.getTeacher()); + } +} diff --git "a/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/service/StudentService.java" "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/service/StudentService.java" new file mode 100644 index 0000000..4b8aabe --- /dev/null +++ "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/main/java/com/leosanqing/service/StudentService.java" @@ -0,0 +1,121 @@ +package com.leosanqing.service; + +import com.leosanqing.Student; +import com.leosanqing.predicate.StudentPredicate; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: leosanqing + * @Date: 2020/1/17 上午7:58 + * @Package: com.leosanqing.service + * @Description: 学生服务类 + */ +public class StudentService { + private static List studentList = new ArrayList() { + { + add(new Student("张三丰", 20, "男", "体育", + 180, 75, "太上老君")); + add(new Student("张无忌", 18, "男", "语文", + 178, 73, "文曲星")); + add(new Student("赵敏", 17, "女", "数学", + 170, 50, "太白金星")); + add(new Student("金毛狮王", 25, "男", "体育", + 176, 80, "太白金星")); + add(new Student("周芷若", 16, "女", "语文", + 168, 48, "太上老君")); + add(new Student("张三", 21, "男", "英语", + 172, 65, "如来")); + add(new Student("赵勇", 26, "男", "体育", + 188, 80, "太上老君")); + + + } + }; + + + public static List getStudentList() { + return studentList; + } + + /** + * 版本一 + * 找出女学生 + * + * @return + */ + public static List getFemaleStudent(List studentList) { + List students = new ArrayList<>(); + for (Student student : studentList) { + if ("女".equals(student.getSex())) { + students.add(student); + } + } + return students; + } + + /** + * 版本二 + *

+ * 根据输入性别查找学生 + * + * @param studentList + * @param sex + * @return + */ + public static List getStudentBySex(List studentList, String sex) { + List students = new ArrayList<>(); + for (Student student : studentList) { + if (sex.equals(student.getSex())) { + students.add(student); + } + } + return students; + } + + /** + * 版本三 + *

+ * 根据输入的年龄或者老师查找。true表示使用年龄,false表示使用老师这个参数 + * + * @param studentList + * @param age + * @return + */ + public static List getStudentByAgeOrTeacher(List studentList, int age, + String teacher, boolean ageOrTeacher) { + List students = new ArrayList<>(); + for (Student student : studentList) { + if ((ageOrTeacher && student.getAge() > age) + || !ageOrTeacher && teacher.equals(student.getTeacher()) + ) { + + students.add(student); + } + } + return students; + } + + + /** + * 版本四 + * + * 使用多态完成,使用策略者模式 + * @param studentList + * @param predicate + * @return + */ + public static List filterStudent(List studentList, StudentPredicate predicate) { + List students = new ArrayList<>(); + for (Student student : studentList) { + if(predicate.filter(student)){ + students.add(student); + } + } + return students; + } + + + +} diff --git "a/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/test/java/lambda/VersionTest.java" "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/test/java/lambda/VersionTest.java" new file mode 100644 index 0000000..ef7a36b --- /dev/null +++ "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/src/test/java/lambda/VersionTest.java" @@ -0,0 +1,108 @@ +package lambda; + +import com.alibaba.fastjson.JSON; +import com.leosanqing.Student; +import com.leosanqing.predicate.AgePredicate; +import com.leosanqing.predicate.StudentPredicate; +import com.leosanqing.predicate.TeacherPredicate; +import com.leosanqing.service.StudentService; +import org.junit.Test; + +import java.util.List; + +/** + * @Author: leosanqing + * @Date: 2020/1/17 上午8:20 + * @Package: lambda + * @Description: 版本测试 + */ + +public class VersionTest { + + + /** + * 第一版 + * + * 根据性别查找 + */ + @Test + public void getFemaleStudent(){ + final List studentList = StudentService.getStudentList(); + + final List femaleStudents = StudentService.getFemaleStudent(studentList); + + System.out.println(JSON.toJSONString(femaleStudents,true)); + + } + + + /** + * 第二版 根据输入性别查找 + */ + @Test + public void getStudentBySex(){ + final List studentList = StudentService.getStudentList(); + + final List femaleStudents = StudentService.getStudentBySex(studentList,"男"); + + System.out.println(JSON.toJSONString(femaleStudents,true)); + + } + + /** + * 版本三: 根据两个参数判断查找 + */ + @Test + public void getStudentByAgeOrTeacher(){ + final List studentList = StudentService.getStudentList(); + + final List studentByAgeOrTeacher = StudentService.getStudentByAgeOrTeacher(studentList, 20, null, true); + System.out.println(JSON.toJSONString(studentByAgeOrTeacher,true)); + + + } + + /** + * 版本四,使用接口,策略者模式 + */ + @Test + public void filterStudent(){ + final List studentList = StudentService.getStudentList(); + + final TeacherPredicate teacherPredicate = new TeacherPredicate(); + + final List students = StudentService.filterStudent(studentList,teacherPredicate); + System.out.println(JSON.toJSONString(students,true)); + + } + + + /** + * 版本五,使用匿名内部类 + */ + @Test + public void AnonymousInnerClass(){ + final List studentList = StudentService.getStudentList(); + final List students = StudentService.filterStudent(studentList, new StudentPredicate() { + @Override + public boolean filter(Student student) { + return "如来".equals(student.getTeacher()); + } + }); + System.out.println(JSON.toJSONString(students,true)); + + } + + + /** + * 版本五,使用lambda + */ + @Test + public void lambda(){ + final List studentList = StudentService.getStudentList(); + final List students = StudentService.filterStudent(studentList, student -> "如来".equals(student.getTeacher())); + System.out.println(JSON.toJSONString(students,true)); + + } + +} diff --git a/Algorithm/LeetCode/leetcode/.DS_Store "b/Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/target/.DS_Store" similarity index 100% rename from Algorithm/LeetCode/leetcode/.DS_Store rename to "Utils/jdk8\346\226\260\347\211\271\346\200\247/stream/lambda_demo/target/.DS_Store" diff --git a/banner-demo/.idea/$CACHE_FILE$ b/banner-demo/.idea/$CACHE_FILE$ new file mode 100644 index 0000000..6cb8985 --- /dev/null +++ b/banner-demo/.idea/$CACHE_FILE$ @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/banner-demo/.idea/.gitignore b/banner-demo/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/banner-demo/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/banner-demo/.idea/compiler.xml b/banner-demo/.idea/compiler.xml new file mode 100644 index 0000000..845b656 --- /dev/null +++ b/banner-demo/.idea/compiler.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/banner-demo/.idea/inspectionProfiles/Project_Default.xml b/banner-demo/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..6560a98 --- /dev/null +++ b/banner-demo/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,36 @@ + + + + \ No newline at end of file diff --git a/banner-demo/.idea/jarRepositories.xml b/banner-demo/.idea/jarRepositories.xml new file mode 100644 index 0000000..35a2ecc --- /dev/null +++ b/banner-demo/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/banner-demo/.idea/misc.xml b/banner-demo/.idea/misc.xml new file mode 100644 index 0000000..3ccb27b --- /dev/null +++ b/banner-demo/.idea/misc.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/banner-demo/.idea/vcs.xml b/banner-demo/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/banner-demo/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/banner-demo/pom.xml b/banner-demo/pom.xml new file mode 100644 index 0000000..6a4f851 --- /dev/null +++ b/banner-demo/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + + org.example + banner-demo + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-web + 2.1.4.RELEASE + + + \ No newline at end of file diff --git a/banner-demo/src/main/java/com/leosanqing/demo/BannerDemo.java b/banner-demo/src/main/java/com/leosanqing/demo/BannerDemo.java new file mode 100644 index 0000000..70daefb --- /dev/null +++ b/banner-demo/src/main/java/com/leosanqing/demo/BannerDemo.java @@ -0,0 +1,18 @@ +package com.leosanqing.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @Author: rtliu + * @Date: 2020/6/28 上午10:17 + * @Package: com.leosanqing.demo + * @Description: + * @Version: + */ +@SpringBootApplication +public class BannerDemo { + public static void main(String[] args) { + SpringApplication.run(BannerDemo.class,args); + } +} diff --git a/banner-demo/src/main/resources/application.yml b/banner-demo/src/main/resources/application.yml new file mode 100644 index 0000000..51c551f --- /dev/null +++ b/banner-demo/src/main/resources/application.yml @@ -0,0 +1,7 @@ +server: + port: 10011 + +spring: + banner: + image: + location: banner1.png \ No newline at end of file diff --git a/banner-demo/src/main/resources/banner.gif b/banner-demo/src/main/resources/banner.gif new file mode 100644 index 0000000..7a9a632 Binary files /dev/null and b/banner-demo/src/main/resources/banner.gif differ diff --git a/banner-demo/src/main/resources/banner.jpg b/banner-demo/src/main/resources/banner.jpg new file mode 100644 index 0000000..79089d7 Binary files /dev/null and b/banner-demo/src/main/resources/banner.jpg differ diff --git a/banner-demo/src/main/resources/banner.txt b/banner-demo/src/main/resources/banner.txt new file mode 100644 index 0000000..d85ea96 --- /dev/null +++ b/banner-demo/src/main/resources/banner.txt @@ -0,0 +1,19 @@ + + .::::. + .::::::::. + ::::::::::: + ':::::::::::.. + :::::::::::::::' + ':::::::::::. + .::::::::::::::' + .:::::::::::... + ::::::::::::::'' + .:::. '::::::::'':::: + .::::::::. ':::::' ':::: + .::::':::::::. ::::: '::::. + .:::::' ':::::::::. ::::: ':::. + .:::::' ':::::::::.::::: '::. + .::::'' ':::::::::::::: '::. + .::'' ':::::::::::: :::... + ..:::: ':::::::::' .:' '''' + ..''''':' ':::::.' diff --git a/banner-demo/src/main/resources/banner1.png b/banner-demo/src/main/resources/banner1.png new file mode 100644 index 0000000..3ef38ff Binary files /dev/null and b/banner-demo/src/main/resources/banner1.png differ diff --git a/banner-demo/target/classes/application.yml b/banner-demo/target/classes/application.yml new file mode 100644 index 0000000..51c551f --- /dev/null +++ b/banner-demo/target/classes/application.yml @@ -0,0 +1,7 @@ +server: + port: 10011 + +spring: + banner: + image: + location: banner1.png \ No newline at end of file diff --git a/banner-demo/target/classes/banner.gif b/banner-demo/target/classes/banner.gif new file mode 100644 index 0000000..7a9a632 Binary files /dev/null and b/banner-demo/target/classes/banner.gif differ diff --git a/banner-demo/target/classes/banner.jpg b/banner-demo/target/classes/banner.jpg new file mode 100644 index 0000000..79089d7 Binary files /dev/null and b/banner-demo/target/classes/banner.jpg differ diff --git a/banner-demo/target/classes/banner.txt b/banner-demo/target/classes/banner.txt new file mode 100644 index 0000000..d85ea96 --- /dev/null +++ b/banner-demo/target/classes/banner.txt @@ -0,0 +1,19 @@ + + .::::. + .::::::::. + ::::::::::: + ':::::::::::.. + :::::::::::::::' + ':::::::::::. + .::::::::::::::' + .:::::::::::... + ::::::::::::::'' + .:::. '::::::::'':::: + .::::::::. ':::::' ':::: + .::::':::::::. ::::: '::::. + .:::::' ':::::::::. ::::: ':::. + .:::::' ':::::::::.::::: '::. + .::::'' ':::::::::::::: '::. + .::'' ':::::::::::: :::... + ..:::: ':::::::::' .:' '''' + ..''''':' ':::::.' diff --git a/banner-demo/target/classes/banner1.png b/banner-demo/target/classes/banner1.png new file mode 100644 index 0000000..3ef38ff Binary files /dev/null and b/banner-demo/target/classes/banner1.png differ diff --git a/books/README.md b/books/README.md index 79efc7f..a3eafd2 100644 --- a/books/README.md +++ b/books/README.md @@ -4,7 +4,7 @@ 程序猿不能只限于技术,还要有广度,这些非技术类的都是非常好的书,我基本都看过的,所以你可以从我的每本书后面的简介选择感兴趣的来看。如果不知道哪些好,**我直接推荐你看吴军老师的书籍**,**至今他是我最最喜欢的作者**。 -**吴军老师**的书每本都非常吸引人,我看他的书基本都是一天都在那里看(浪潮之巅,三天读完,文明之光四本,四天看了三本半,数学之美,三天看完) + 如果想了解我们学计算机的为啥要学数学还有电路电子,我是学Java,py方向的为啥还要学C语言,计网,操作系统。我真心推荐你们看下这三本书,他们都非常非常有趣且不失深度的讲了为什么,而不只是很多书讲,是什么 @@ -134,55 +134,81 @@ ## 科普类 -- 穿越计算机迷雾(了解计算机怎么产生的,用到了啥技术) -- 上帝掷骰子吗 +- 物理世界的数学奇迹(1.21更,数学是怎么影响物理的,物理又是怎么推进数学的。两者在交叉融合之后,又产生了多少神奇的理论。作为物理中目前非常非常热门的弦论,数学表达怎么发展的。) +- 改变世界的方程(1.21更,这本书非常非常nice,通过人物模拟对话的形式向我们展示了 爱因斯坦是怎么发展 牛顿的经典物理的,为啥会有光速不变性,爱因斯坦是怎么将时空统一的,相对论又是怎么兼容牛顿物理的。为啥爱因斯坦的方程能指导制造原子弹,是否有可能造出比氢弹威力更大的反物质弹) +- 数学大师(1.21更, 数学作为所有科学学科的基础,他由哪些数学大佬发展成这样的,你可能知道牛顿,莱布尼兹,高斯,黎曼。但还有很多你不知道的大佬们,我们享受科学带来的种种福利,应当了解哪些人对我们对我们的生活做出了巨大贡献) +- 人类简史(8.17更,我们人类如何从动物中脱颖而出成为地球的霸主,我们经历了三次革命——认知、农业、科学。每次都带来了哪些变革) +- 穿越计算机迷雾(了解计算机怎么产生的,用到了啥技术,如何) +- 上帝掷骰子吗(物理科学史话,不需要有什么物理基础就能看懂的激动人心的物理发展史,从牛顿的经典物理到爱因斯坦相对论再到现代的量子物理) +- 基因传(生物学科,讲述基因的发展历程及基因的作用,看过后至少不会对转基因,基因工程有偏见,大多宣传天然,妖魔转基因的都是收割智商税的) - 码农翻身(用故事讲计算机的各种知识) - 从一到无穷大(生动形象的科普了很多很多我们不理解的东西,比如假如思维空间的物体在三维空间怎么呈现,怎么统一时间空间。[可以看下我的这个读后感](https://mp.weixin.qq.com/s?__biz=MzU0ODgzNjQ2MQ==&mid=2247483941&idx=1&sn=bf5a2fec08aea0733c75b5805090a2de&chksm=fbb84727cccfce31db3fed67971fe2760db6138c1d4ba204a4c041827584e57e1d13ae360b24&token=391583946&lang=zh_CN#rd)) - 菊与刀(解读日本人的矛盾的性格的本质,别再被各种武士道啥的误导了,那个是评论家的片面解读) -## 理财 +## 理财投资 + +- 小狗钱钱(通过简单且生动具体的事,讲述如何理财) -- 小狗钱钱第一本(第一本是理财基础和一些道理,如果不是给初中前小孩子看,不建议看第二本) - 穷爸爸富爸爸(学校可不会教你怎么赚钱怎么创业,学校学不到的东西) + - 韭菜的自我修养(很小的一本书,很简单的道理,但是很实用) + - 漫步华尔街 + - 股市进阶之道 + - 投资最重要的事 -- -## 吴军老师的书籍(强烈安利,任何一本都是好书) + + +## 吴军老师的书籍(强烈安利) [可以看下这篇吴军老师的分享](https://pic1cdn.luojilab.com/html/poster/picRmko00X4v9FjoRE4Mkvy.html?ts=1556514071182&from=timeline&isappinstalled=0) -- 浪潮之巅(你所不知道的科技公司的兴衰) +- 全球科技通识(什么是科学,什么是技术?什么又是科技,中国为啥一直缺乏科学思维,为啥工业革命之后科技发展的这么快,围绕人类发展的两条主线,能量与信息讲述全球科技的发展历程) +- 浪潮之巅(讲述上个世纪开始的互联网浪潮下的各大互联网公司的兴衰史,要了解互联网公司发展历史的千万不要错过) - 硅谷之谜(浪潮之巅续,硅谷为何只在美国硅谷,其他地方模仿总学不来) -- 文明之光(理科男角度的历史) +- 文明之光(从科技文明角度描述历史的发展,不是老套的人文英雄,帝王八卦,权术博弈,当时大四拿到书的两天基本是除了吃饭睡觉一直在看,真的很有趣) - 态度 - 大学之路(终生学习) -- 数学之美(我觉得更可以说是程序员该了解的数学) -- 全球科技通识(什么是科学,什么是技术?什么又是科技,中国(也可以说东方)为啥一直缺乏科学思维,为啥工业革命之后科技发展的这么快) +- 数学之美(讲述计算机中用到了哪些数学知识。很多人被书名中的数学所劝退,其实这本书并不需要太多数学知识,更多的是讲数学的作用,发展以及在计算机中的应用。当时看完觉得真的是相见恨晚,如果早点看,可能就不会对数学那么排斥,大学中的高数现代离散概率论一定要好好学) ## 提升思维和学习方法 - 如何阅读一本书(读书的四个层次以及不同类型书的阅读方法) -- 少有人走的路(成年不代表心智成熟,能让你反思自己有哪些心智不成熟的地方) -- 认知天性(如何学习,为什么别人看似比你用的时间短,掌握的却比你好) + +- 少有人走的路(这本书前半段讲述家庭教育重要性,父母对孩子教育的影响非常深刻。很多父母都是巨婴,生了孩子不养,不如不生。(我最痛恨的就是那种生而不养的父母,真的让我恶心。可以看看电影【何以为家】,看的真虐心) + + 孩子心理性格有问题,基本都是家长的锅,学习不好也基本都是家长的锅。但是家长根本不会反思,全部甩给老师,要么甩给游戏、早恋等等。) + +- 认知天性(如何学习,为什么别人看似比你用的时间短,掌握的却比你好,重复就一定有用吗) + - 稀缺(我们是如何陷入贫穷和忙碌的。用行为经济学为你解答疑惑) + - 原则(人生箴言,不过25岁之前或者人生阅历不够的应该看不懂,至少我现在看不懂) -- 异类(一万小时定理出处,大神之所以为大神的原因) + +- 异类(一万小时定理出处,稻田文化麦田文化,机遇比自身能力更重要,大神之所以为大神的原因) + - 自学是门手艺(不会自学的人没有未来,别一上来就说自己不会。以Python为例,讲述如何自学技能) + - 把时间当朋友(不要把时间当敌人,不管你怎么做,时间还是那样(对普通人来说还是绝对时空观)) + - 乌合之众(解读大众心理) + - 娱乐至死(娱乐的危害) -- 深度工作(怎么提高工作效率) -- 学习之道(没怎么看懂,不过是一本畅销书,而且作者是个真正的大神) + +- 深度工作(怎么提高工作效率,放下手机,暂时承受孤独) + +- 学习之道(美国畅销书,讲述作者如何在棋艺和其他方面成为大师) + - 人性的弱点 + - 黑客与画家(这个是2001年左右的书,里面很多对于互联网方面的洞见,过去将近20年了,你会直呼准) -- ## 企业相关 - 奈飞文化手册(21世纪就要用21世纪的管理方法,还在使用20世纪的管理方法,是让人受不了的) +- 美国陷阱(公司高管因为公司和国家争端被迫入狱,讲述美国为了搞垮对手如何使用卑劣的手段强制让竞争对手认罚) ## 更好的生活 @@ -202,59 +228,68 @@ ## 名人传 -- 乔布斯传(推荐看英文版,只要上过高中做过阅读,基本无障碍) -- 特斯拉传(思维超前的发明家) +- 乔布斯传(推荐看英文版,只要上过高中做过阅读,基本无障碍.乔布斯在全世界封神,理念被互联网推崇。但他性格方面,尤其是对员工方面,不要太苛刻。 + + 苹果跟微软的那些事,乔布斯被踢出公司,跟斯卡利结怨,到后来被请回公司力挽狂澜,一举把濒临破产的苹果公司推向市值及创造力最高的公司) + +- 特斯拉传(严重被低估的工程师,思维超前的发明家) + +- 《硅谷钢铁侠:埃隆·马斯克的冒险人生》([如何看待年轻人崇拜马斯克](http://mp.weixin.qq.com/s?__biz=MzU0ODgzNjQ2MQ==&mid=100000457&idx=1&sn=24732e225c8ba6d63a11857d7802a136&chksm=7bb847cb4ccfcedddc771d51c2ddbd68816f06c075dfe09c8511f1e539e35c4571d943e1b2f4#rd)) + - 从孤独中醒来:微信之父张小龙(纯粹也能成功,继乔布斯之后的极简主义代表。中国最牛产品经理。) + - 只是为了好玩(linux 之父林纳斯自传) +- 腾讯传(腾讯是如何从通信软件变成现在的巨无霸,在各个战役中,腾讯如何应对。最终,为什么会有中国最早的产品经理马化腾和最牛产品经理 张小龙) + +- 浮生六记("余忆童稚时,能张目对日,明察秋毫"。还记得以前语文书中的这篇文章吗?但是我觉得他最经典的是第一记,描述他与妻子间的爱情。虽没有什么海枯石烂,乃敢与君绝的惊天动地,也没有琼瑶式的狗血剧情。但从文字间能看到平淡但是令人向往的夫妻生活,让我一个没有结婚的,对此甚是羡慕) + ## 科幻书籍 -- 基地(超级超级好看的科幻巨著,一共15本,哈里·谢顿通过心理学史预言帝国灭亡,并预言1000年之后建立新的帝国,[如果要看详细的可以参考我的这篇文章](http://mp.weixin.qq.com/s?__biz=MzU0ODgzNjQ2MQ==&mid=100000271&idx=1&sn=e113e57b123ef919d634c4cd84656933&chksm=7bb8470d4ccfce1bd93ef4571d06c839b7ed25b3c955ae300d8e97532bcbf07f1c67bcb202b0#rd)) +- 基地(超级超级好看的科幻巨著,一共15本。科幻小说巨佬,阿西莫夫的代表作,虽然你感受不到三体那种惊艳的物理知识,毕竟他很有年代了,但你能感受到构建出来的非常非常宏大的科幻世界架构 + + 哈里·谢顿通过心理学史预言帝国灭亡,并预言1000年之后建立新的帝国,他预留了两批人来建立新帝国,一个是明的,一个是暗的。如果有偏差就由另一批人来修正,最后两批人斗智斗勇[如果要看详细的可以参考我的这篇文章](http://mp.weixin.qq.com/s?__biz=MzU0ODgzNjQ2MQ==&mid=100000271&idx=1&sn=e113e57b123ef919d634c4cd84656933&chksm=7bb8470d4ccfce1bd93ef4571d06c839b7ed25b3c955ae300d8e97532bcbf07f1c67bcb202b0#rd)) + - 与罗摩相会(罗摩人好事成三,作者是真正的科幻大佬) + - 三体(丛林法则,水滴) +- 永恒的终结(基地前传,永恒国度的人试图通过时光机来改变各个历史,防止人们走向毁灭,最终永恒国度又是如何瓦解,为什么瓦解) + +- 童年的终结(比人类更高文明的超主,也只是更高文明的奴隶附庸。最终人类是如何进化,人类是如何灭绝。有另外一个名称,最后一个地球人) + ## 治愈 -- 解忧杂货铺(一封封穿越时空的信件,非常治愈的) +- 解忧杂货铺(东野圭吾的治愈系小说,讲述三个品行不太好的人,偷东西后被迫藏到一个杂货铺中,但这个杂货铺在某一天时有穿越时空的能力,他们能收到很多年前的人写的信。他们三个就进行回信,帮助他人的同时,也引导自己的心回归。最终还有因果轮回,这个悬念就留给大家自己探索吧) - 海街日记(心情不好的时候看这个确实很治愈。只是简单的画出了四姐妹平时的生活,却能唤起自己内心最柔软的地方) - 小王子(西方阅读率仅次于圣经的作品) ## 文学小说 -- 1984(老大哥在看着你,构想出几十年后的斯大林专制下的俄国,警醒世人不要让这种情况发生,全程压抑到不行。) -- 罗生门(用很多短篇小说剖析人性) +- 动物庄园 (8.15更,《1984》作者乔治·奥威尔的另一本神作,比1984更讽刺,里面的预言基本都实现,虽然是讽刺苏联,但上面可是不敢看,因为跟他们一模一样啊,想想被禁也是理所应当) +- 1984(老大哥在看着你,构想出几十年后的斯大林专制下的俄国,警醒世人不要让这种情况发生,但实际情况是预言成真,并且中国也同样) +- 人间失格 - 浮生六记(浮生若梦,为欢几何。读第一篇就把我吸引到了,原来 爱情是这样的) +- 罗生门(用很多短篇小说剖析人性) - 了不起的盖茨比(穷屌丝想回到过去,以为自己有钱就能得到爱) - 白夜行(我的新年愿望:能在白天行走,共生的两个小孩,最后结局是咋样的) - 嫌疑人X的献身(宅男的爱受得起不?) - 月亮与六便士(满地都是六便士,他却抬头看见了月光) - 麦田里的守望者(虽然满篇的脏话,但是却表达了我们青春期的时候的叛逆的心理) -- 追风筝的人(阿米尔少爷最终还是成为了像哈桑一样勇敢的人) +- 追风筝的人(少爷阿米尔与佣人(但更偏向是奴隶那种)的儿子哈桑是情同手足的好基友。哈桑更是每次在他有危机困难的时候毫不犹豫的甚至愿意付出生命的帮助他。当有一天,哈桑去追风筝(这个是他们的一个活动),被其他人欺负的时候,阿米尔却没有站出来解救哈桑。哈桑被伤害了,但是没有怪罪阿米尔,也没有告诉别人。阿米尔一直很愧疚,后来战争一些原因导致哈桑死了(也是因为在维护阿米尔),他了解到哈桑有个儿子还被抓了,他这回像哈桑以前那样,勇敢站出来解救他儿子。而且还得知了很多真相....) +- 三岛由纪夫的作品 ## 历史相关 +- 跌荡一百年、激荡三十年、激荡十年(吴晓波,从商人或者社会经济的角度分析我们国家从清末到2018年的变革。纵观全局可以看到 官商模式基本从未改变,科技在进步,历史仍在轮回。可以看到清末官商如何试图拯救清朝;抗日战争时期中国商人发挥的作用;不可说的十年之中,商人如何挣扎生存;从改革开放之后,经济制度如何改变,中国如何腾飞) + - 企鹅欧洲史 - 第二次世界大战回忆录(临危受命的丘吉尔讲述二战) -- - - -## 好书,但大学前不推荐看的(很容易变丧) - -- 人间失格(逃避现实,一步步失去人格) -- 三岛由纪夫的作品 -- 百年孤独 -- 最初的爱情,最后的仪式 - - - - - -# 不建议读的 - -- 墨菲定律(张新捷著,之前看到网上的套装,以为还行,但是全程鸡汤,例子基本也都是一个虚拟场景,没有分析本质。不知道怎么火起来的。可能是抖音吧。反正看了几十页看不下去了,浪费时间) + + diff --git a/img/Xnip2020-03-08_21-24-27.jpg b/img/Xnip2020-03-08_21-24-27.jpg new file mode 100644 index 0000000..a32b6cf Binary files /dev/null and b/img/Xnip2020-03-08_21-24-27.jpg differ diff --git a/img/Xnip2020-04-14_17-21-28.jpg b/img/Xnip2020-04-14_17-21-28.jpg new file mode 100644 index 0000000..1be0b9f Binary files /dev/null and b/img/Xnip2020-04-14_17-21-28.jpg differ diff --git a/img/Xnip2020-05-11_14-31-29.jpg b/img/Xnip2020-05-11_14-31-29.jpg new file mode 100644 index 0000000..2cbbad7 Binary files /dev/null and b/img/Xnip2020-05-11_14-31-29.jpg differ diff --git a/img/Xnip2020-05-11_14-39-28.jpg b/img/Xnip2020-05-11_14-39-28.jpg new file mode 100644 index 0000000..f81f855 Binary files /dev/null and b/img/Xnip2020-05-11_14-39-28.jpg differ diff --git a/java-note-algorithm/.idea/$CACHE_FILE$ b/java-note-algorithm/.idea/$CACHE_FILE$ new file mode 100644 index 0000000..6cb8985 --- /dev/null +++ b/java-note-algorithm/.idea/$CACHE_FILE$ @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/java-note-algorithm/.idea/.gitignore b/java-note-algorithm/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/java-note-algorithm/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/java-note-algorithm/.idea/compiler.xml b/java-note-algorithm/.idea/compiler.xml new file mode 100644 index 0000000..4db2371 --- /dev/null +++ b/java-note-algorithm/.idea/compiler.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java-note-algorithm/.idea/inspectionProfiles/Project_Default.xml b/java-note-algorithm/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..6560a98 --- /dev/null +++ b/java-note-algorithm/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,36 @@ + + + + \ No newline at end of file diff --git a/java-note-algorithm/.idea/jarRepositories.xml b/java-note-algorithm/.idea/jarRepositories.xml new file mode 100644 index 0000000..32e7c7d --- /dev/null +++ b/java-note-algorithm/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/java-note-algorithm/.idea/misc.xml b/java-note-algorithm/.idea/misc.xml new file mode 100644 index 0000000..b49fb2f --- /dev/null +++ b/java-note-algorithm/.idea/misc.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/java-note-algorithm/.idea/uiDesigner.xml b/java-note-algorithm/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/java-note-algorithm/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java-note-algorithm/.idea/vcs.xml b/java-note-algorithm/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/java-note-algorithm/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/java-note-algorithm/README.md b/java-note-algorithm/README.md new file mode 100644 index 0000000..2adb555 --- /dev/null +++ b/java-note-algorithm/README.md @@ -0,0 +1,74 @@ +# 前言 + +大家应该都知道算法的重要性,不管是大厂小厂都非常重视,因为这个不仅考察你的逻辑能力,还有对数据结构的了解程度,还有各个集合类是否熟练 + +这一部分就是 算法的章节。 + +主要是 **剑指offer** 和 **LeetCode**上面的算法题进行整理 + +**剑指offer因为是C语言版,这里改成Java版本** + + + +这两个主要是之前自己刷题的时候写下来的,然后顺便传到GitHub上,对你们可能也有些帮助 + + + +# 先看哪个 + +**针对不同时间,侧重点也会不同** + +- 如果你时间多(离面试还有3月以上) + - 刷Leetcode +- 如果马上就要校招、社招了。刷剑指Offer。 + + + +# 格式 + +![](img/Xnip2019-11-06_22-42-30.jpg) + +## 类名 + +- 题号+类名 + +## 文档注释 + +- **主类最上面是整个问题的描述**以及我对这个题目的**审题**和**解题思路** +- 里面的静态方法是各个**不同的解题的方法**。会有**解题思路**+**时间空间复杂度** +- 也会有我对这个**现有题目进行拓展**的一些想法和**解题思路**,比如下图所示 + +针对该题目,进行一些发散性思考。(不一定是最优的,但是思考很重要) + +![](img/Xnip2019-11-06_22-49-50.jpg) + +# 剑指Offer + +很多公司,非大厂(大厂自己会改题)都从这个里面找算法题,你会看到很多校招的算法题90%都是在这本书里,所以如果你时间不多,可以突击刷这个 + + + +# LeetCode + +分为简单和中等,因为大厂的算法一般也就是中等难度,很多算法都是在中等(算法岗除外) + +每个题都是通过了测试,但是代码的风格质量可能不是最优的 + +总共就一个项目,项目分类按照包分类,分为 + +- 简单 + - 数组 + - 链表 + - 哈希 + - 二叉树 + - 等.. +- 中等 + +因为题目不可能是孤立的(比如一个题可能同时要用到数组和hash),所以只是大致分了下,我用什么标签搜索的就放进了哪个包 + +每一个类就是一个题目,每个类中的注释都会有 + +- 题目描述 +- 示例 +- 思路 +- 代码 \ No newline at end of file diff --git a/java-note-algorithm/java-note-algorithm.iml b/java-note-algorithm/java-note-algorithm.iml new file mode 100644 index 0000000..78b2cc5 --- /dev/null +++ b/java-note-algorithm/java-note-algorithm.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/java-note-algorithm/pom.xml b/java-note-algorithm/pom.xml new file mode 100644 index 0000000..ef29ff9 --- /dev/null +++ b/java-note-algorithm/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + org.example + java-note-algorithm + 1.0-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + + + + + com.alibaba + fastjson + 1.2.47 + + + org.projectlombok + lombok + 1.18.12 + + + \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_121_BestTimeToBuyAndSellStock.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_121_BestTimeToBuyAndSellStock.java new file mode 100644 index 0000000..f86c45f --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_121_BestTimeToBuyAndSellStock.java @@ -0,0 +1,67 @@ +package com.leosanqing.leetcode.easy; + +/** + * 描述 : 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + * 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 + * 注意你不能在买入股票前卖出股票。 + *

+ * 示例1: 输入: [7,1,5,3,6,4] + * 输出: 5 + * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 + * 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 + *

+ * 示例2 输入: [7,6,4,3,1] + * 输出: 0 + * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 + */ + +public class _121_BestTimeToBuyAndSellStock { + + /** + * 直接暴力求解,遍历两次数组,求出最优解 + */ + + public static int violence(int[] prices) { + if (prices == null || prices.length == 0) { + return 0; + } + int maxProfit = 0; + for (int i = 0; i < prices.length; i++) { + for (int j = i + 1; j < prices.length; j++) { + if (prices[j] - prices[i] > maxProfit) { + maxProfit = prices[j] - prices[i]; + } + + } + } + return maxProfit; + } + + + /** + * 动态规划: + * 1.定义一个从最开始到当前位置的最小值 + * 2.计算今天减去最小值的值,也就是当天的利润 + * 3.比较当天的利润和之前的最大利润 + */ + public static int dp(int[] prices) { + if (prices == null || prices.length == 0) + return 0; + + int minProfit = Integer.MAX_VALUE; + int maxProfit = 0; + + for (int price : prices) { + //找到最小值 + minProfit = Math.min(minProfit, price); + //比较当天的利润和最大利润 + maxProfit = Math.max(maxProfit, (price - minProfit)); + } + return maxProfit; + } + + public static void main(String[] args) { + int[] a = {7, 6, 4, 3, 1}; + System.out.println(violence(a) == dp(a)); + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_122_BestTimeToBuyAndSellStock2.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_122_BestTimeToBuyAndSellStock2.java new file mode 100644 index 0000000..7851f2a --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_122_BestTimeToBuyAndSellStock2.java @@ -0,0 +1,44 @@ +package com.leosanqing.leetcode.easy; + +/** + * 描述: 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + * 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 + * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + *

+ * 示例1: 输入: [7,1,5,3,6,4] + * 输出: 7 + * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + * 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 + * 示例2: 输入: [1,2,3,4,5] + * 输出: 4 + * 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + * 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 + * 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 + *

+ * 思路:使用两个变量 一个valley表示当天天数中最低价, + * 一个peek表示当前所有的天数中的最高价 + * 因为我们可以买卖股票且是不用付手续费的,也就是我们可以卖了这一只股票,然后再把它买回来 + * 所以上面示例2中,5-1和 (2-1)+(3-2)+(4-3)+(5-4)的效果是一样的,所以顶峰就找递增的,底就找递减的 + */ +public class _122_BestTimeToBuyAndSellStock2 { + public int maxProfit(int[] prices) { + if (prices == null || prices.length == 0) + return 0; + + int valley = prices[0], peek = prices[0]; + int i = 0; + int maxProfit = 0; + + while (i < prices.length - 1) { + while (i < prices.length - 1 && prices[i] >= prices[i + 1]) + i++; + valley = prices[i]; + + while (i < prices.length - 1 && prices[i] <= prices[i + 1]) + i++; + peek = prices[i]; + maxProfit += peek - valley; + } + return maxProfit; + } +} \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_136_singleNum.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_136_singleNum.java new file mode 100644 index 0000000..858ad1e --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_136_singleNum.java @@ -0,0 +1,33 @@ +package com.leosanqing.leetcode.easy; + +/** + * 描述: + * ` Given a non-empty array of integers, every element appears twice except for one. Find that single one. + * ` 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 + * ` 说明: + * ` 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? + * ` 输入: [4,1,2,1,2] + * ` 输出: 4 + * ` + * ` + * ` 思路:使用异或运算: + * ` 异或运算有三个特征: + * ` 1、0 ^ 任何数都为 那个数 0^a = a; + * ` 2、两个相同的数异或结果为 0 a^a = 0; + * ` 3、异或具有交换律 a^b^c = a^c^b + */ +public class _136_singleNum { + public static void main(String[] args) { + int[] nums = {4, 2, 1, 2, 1}; + System.out.println("singleNum(nums) = " + singleNum(nums)); + + } + + public static int singleNum(int[] nums) { + int result = 0; + for (int num : nums) { + result ^= num; + } + return result; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_202_happyNumber.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_202_happyNumber.java new file mode 100644 index 0000000..54e38af --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_202_happyNumber.java @@ -0,0 +1,67 @@ +package com.leosanqing.leetcode.easy; + +import java.util.HashSet; +import java.util.Set; + +/** + * @Author: leosanqing + * @Date: 2020/4/15 上午10:17 + * @Package: easy + * @Description: leetCode 202题 + *

+ * ` A happy number is a number defined by the following process: + * ` Starting with any positive integer, replace the number by the sum of the squares of + * ` its digits, + * ` and repeat the process until the number equals 1 (where it will stay), + * ` or it loops endlessly in a cycle which does not include 1. + * ` Those numbers for which this process ends in 1 are happy numbers. + * `

+ * ` Input: 19 + * ` Output: true + * ` Explanation: + * ` 1² + 9² = 82 + * ` 8² + 2² = 68 + * ` 6² + 8² = 100 + * ` 1² + 0² + 0² = 1 + * ` @Version: v1 + * ` + * ` + * ` 思路: + * ` 我们看到最后,其实可以猜出来,只有最终变成一位数才有可能达到他的预期, + * ` 如果有两位数或者以上,我们肯定是要对他再一次进行运算的,所以我们就一直往下拆数字就行, + * ` 但是这里还有个坑,我们怎么让他不会陷入死循环呢?我们要判断他之前是否运算过,因为如果运算过,就会陷入死循环 + * ` 我们使用 HashSet ,来判断,如果有值,那么这个肯定之前就运算过,就会陷入死循环。不可能是我们想要的 HappyNum + */ +public class _202_happyNumber { + public static void main(String[] args) { + + _202_happyNumber happyNumber = new _202_happyNumber(); + for (int i = 0; i < 10000; i++) { + happyNumber.isHappy(i); + } + } + + public boolean isHappy(int n) { + int row = n; + Set set = new HashSet<>(); + + while (n > 1) { + int m = 0; + // 计算每位的平方的和 + while (n > 0) { + m = m + (n % 10) * (n % 10); + n /= 10; + } + // 之前运算过,不可能是HappyNum,不跳出去就会陷入死循环 + if (set.contains(m)) { + return false; + } + set.add(m); + + n = m; + } + System.out.println(row); + return true; + + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_203_removeLinkedListElements.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_203_removeLinkedListElements.java new file mode 100644 index 0000000..096a8ff --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_203_removeLinkedListElements.java @@ -0,0 +1,51 @@ +package com.leosanqing.leetcode.easy; + +import com.leosanqing.leetcode.medium.list.ListNode; + +/** + * @Author: rtliu + * @Date: 2020/6/1 下午2:11 + * @Package: easy + * @Description: Remove all elements from a linked list of integers that have value val. + * 删除链表中与指定值相同的节点 + *

+ * Example: + *

+ * Input: 1->2->6->3->4->5->6, val = 6 + * Output: 1->2->3->4->5 + * @Version: 1.0 + */ +public class _203_removeLinkedListElements { + public static void main(String[] args) { + + } + + /** + * 使用一个虚拟的头结点来预防边界异常情况 + * + * 如果 + * @param head + * @param val + * @return + */ + public ListNode removeElements(ListNode head, int val) { + // 设置一个虚拟的头结点,就把 特殊的边界节点变成了普通的节点 + ListNode fakeHead = new ListNode(0); + fakeHead.next = head; + ListNode pre = fakeHead; + + + while(pre.next != null){ + // 直接把上一个节点指向 下一个节点,从而跳过当前节点 ,这样就达到了删除的目的 1->2->6->3->4->5->6, val = 6 + if(val == pre.next.val){ + pre.next = pre.next.next; + }else { +// if (pre.next.val == val) pre.next = pre.next.next; + pre = pre.next; + } + } + return fakeHead.next; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_204_countPrimes.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_204_countPrimes.java new file mode 100644 index 0000000..d9ef569 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_204_countPrimes.java @@ -0,0 +1,90 @@ +package com.leosanqing.leetcode.easy; + +/** + * @Author: leosanqing + * @Date: 2020/4/15 上午11:19 + * @Package: easy + * @Description: 统计素数个数 + * @Version: 1.0 + *

+ *

+ * 204. Count Primes + * Des: + * Count the number of prime numbers less than a non-negative number, n. + *

+ * Example: + *

+ * Input: 10 + * Output: 4 + * Explanation: There are 4 prime numbers less than 10, they are 2, 3, 5, 7. + */ +public class _204_countPrimes { + public static void main(String[] args) { +// System.out.println(new _204_countPrimes().countPrimes(499979)); + int num = 49997; + System.out.println((new _204_countPrimes().countPrimes(num)) == new _204_countPrimes().countPrimesFast(num)); +// System.out.println(new _204_countPrimes().countPrimesFast(499979)); + } +// + + /** + * 效率太低 O(n²) + * + * @param n + * @return + */ + public int countPrimes(int n) { + if (n <= 2) { + return 0; + } + + if (n == 3) { + return 1; + } + + boolean flag = false; + int num = 2; + for (int i = 3; i < n; i++) { + flag = false; + + for (int j = 2; j <= i / 2; j++) { + if (i % j == 0) { + break; + } + if (j == i / 2) { + flag = true; + break; + } + } + + if (flag) { + num++; + } + + } + return num; + } + + /** + * O(n·log(log(n))) + * 我们设置一个 bool 型的 数组,长度为 我们要输入的长度 + * 从 + * + * @param n + * @return + */ + public int countPrimesFast(int n) { + boolean[] notPrime = new boolean[n]; + int count = 0; + for (int i = 2; i < n; i++) { + if (!notPrime[i]) { + count++; + for (int j = 2; i * j < n; j++) { + notPrime[i * j] = true; + } + } + } + + return count; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_205_isomorphicStrings.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_205_isomorphicStrings.java new file mode 100644 index 0000000..d2b865e --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_205_isomorphicStrings.java @@ -0,0 +1,121 @@ +package com.leosanqing.leetcode.easy; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Author: rtliu + * @Date: 2020/6/1 下午4:14 + * @Package: com.leosanqing.leetcode.easy + * @Description: Given two strings s and t, determine if they are isomorphic. + * Two strings are isomorphic if the characters in s can be replaced to get t. + * All occurrences of a character must be replaced with another character while preserving the order of characters. + * No two characters may map to the same character but a character may map to itself. + *

+ * 给定两个字符串s和t,确定它们是否同构。 + * 如果可以替换s中的字符以获得t,则两个字符串是同构的。 + * 在保留字符顺序的同时,必须将所有出现的字符替换为另一个字符。 + * 不能将两个字符映射到同一字符,但是可以将一个字符映射到自身。 + * @Version: 1.0 + *

+ *

+ * Example 1: + * Input: s = "egg", t = "add" + * Output: true + *

+ * Example 2: + * Input: s = "foo", t = "bar" + * Output: false + *

+ * Example 3: + * Input: s = "paper", t = "title" + * Output: true + */ +public class _205_isomorphicStrings { + + public static void main(String[] args) { + System.out.println(isIsomorphic("aba","baa")); + System.out.println(isIsomorphic("paper","tifae")); + System.out.println(isIsomorphic("egg","foo")); + System.out.println(isIsomorphic("paper","title")); + + } + + + + public static boolean isIsomorphic(String s, String t) { + + Map sHashMap = new HashMap<>(256); + Map tHashMap = new HashMap<>(256); + + if(s.length() != t.length()){ + return false; + } + + char sChar; + char tChar; + for (int i = 0; i < s.length(); i++) { + + + sChar = s.charAt(i); + tChar = t.charAt(i); + // 如果sMap 中有,但是tMap中 没有,那么肯定就是有问题的 + // 或者 如果tMap 中有,但是sMap中 没有 + if((!sHashMap.containsKey(sChar) && tHashMap.containsKey(tChar)) + || (sHashMap.containsKey(sChar) && !tHashMap.containsKey(tChar))){ + return false; + } + if(!sHashMap.containsKey(sChar)){ + sHashMap.put(sChar,i); + } + + if(!tHashMap.containsKey(tChar)){ + tHashMap.put(tChar,i); + } + + if(!sHashMap.get(sChar).equals(tHashMap.get(tChar))){ + return false; + } + } + + return true; + } + + + /** + * 大佬们的算法,据说时间 3ms, + * 这边是使用 数组, + * @param sString + * @param tString + * @return + */ + public boolean isIsomorphic2(String sString, String tString) { + + char[] s = sString.toCharArray(); + char[] t = tString.toCharArray(); + + int length = s.length; + if(length != t.length) { + return false; + } + + char[] sm = new char[256]; + char[] tm = new char[256]; + + for(int i=0; i + * Example: + *

+ * Input: 1->2->3->4->5->NULL + * Output: 5->4->3->2->1->NULL + */ +public class _206_reverseLinkedList { + + public static void main(String[] args) { + ListNode node1 = new ListNode(1); + ListNode node2 = new ListNode(2, node1); + ListNode node3 = new ListNode(3, node2); + ListNode node4 = new ListNode(4, node3); + ListNode node5 = new ListNode(5, node4); + + ListNode listNode = reverseList(node5); + + while(listNode!=null){ + System.out.println(listNode.val); + listNode= listNode.next; + } + } + + public static ListNode reverseList(ListNode head) { + ListNode pre = null; + while(head != null){ + + // 顺序不能反 + ListNode next = head.next; + head.next = pre; + + pre = head; + head = next; + } + + return pre; + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_237_deleteNodeInLinkedList.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_237_deleteNodeInLinkedList.java new file mode 100644 index 0000000..8d6ce41 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_237_deleteNodeInLinkedList.java @@ -0,0 +1,44 @@ +package com.leosanqing.leetcode.easy; + +import com.leosanqing.leetcode.medium.list.ListNode; + +/** + *` 描述:Write a function to delete a node (except the tail) in a singly linked list, given only access to that node. + *` + *` Given linked list -- head = [4,5,1,9], which looks like following: + *` + *` 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。 + *` + *` 现有一个链表 -- head = [4,5,1,9],它可以表示为: + *` + *` Input: head = [4,5,1,9], node = 5 + *` Output: [4,1,9] + *` Explanation: You are given the second node with value 5, + *` the linked list should become 4 -> 1 -> 9 after calling your function. + *` + *` + *` + *` 提示:你已经进入了那个节点,并不是从头开始。 + *` 链表至少包含两个节点。 + *` 链表中所有节点的值都是唯一的。 + *` 给定的节点为非末尾节点并且一定是链表中的一个有效节点。 + *` 不要从你的函数中返回任何结果。 + *` + *` 请一定要注意描述和提示!!!! + *` + *` + *` 解法: 直接用后面的覆盖前面的,然后将指针修改下就行 + */ + +public class _237_deleteNodeInLinkedList { + + public static void main(String[] args) { + + } + public static void deleteNode(ListNode node){ + // 覆盖 + node.val = node.next.val; + // 修改指针 + node.next = node.next.next; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_581_ShortestUnsortedContinuousSubarray.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_581_ShortestUnsortedContinuousSubarray.java new file mode 100644 index 0000000..b458aa7 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_581_ShortestUnsortedContinuousSubarray.java @@ -0,0 +1,39 @@ +package com.leosanqing.leetcode.easy; + +import java.util.Arrays; + +/** + * 题目: 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。 + * 你找到的子数组应是最短的,请输出它的长度。 + *

+ *

+ * 示例: 输入: [2, 6, 4, 8, 10, 9, 15] + * 输出: 5 + * 解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。 + *

+ *

+ * 思路: 我们先将其排好序,然后用两个游标,left,right + * 如果出现了 数字不相等的情况,那么就说明他是我们要找的数,并且left要最小 + * 与之相对,找到right的位置,相减+1就是我们要的长度 + */ +class _581_ShortestUnsortedContinuousSubarray { + public int findUnsortedSubarray(int[] nums) { + int[] numsClone = nums.clone(); + Arrays.sort(nums); + int left = nums.length - 1, right = 0; + for (int i = 0; i < nums.length; i++) { + if (numsClone[i] != nums[i]) { + left = Math.min(left, i); + right = Math.max(right, i); + } + } + return right - left > 0 ? right - left + 1 : 0; + + } + + + public static void main(String[] args) { + Object object = new Object(); + + } +} \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_617_mergeTwoBinaryTree.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_617_mergeTwoBinaryTree.java new file mode 100644 index 0000000..4cd0e1d --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/_617_mergeTwoBinaryTree.java @@ -0,0 +1,48 @@ +package com.leosanqing.leetcode.easy; + +/** + * ` 描述: 给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。 + * ` 你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值, + * ` 否则不为 NULL 的节点将直接作为新二叉树的节点。 + * ` + * ` 示例: Input: + * ` Tree 1 Tree 2 + * ` 1 2 + * ` / \ / \ + * ` 3 2 1 3 + * ` / \ \ + * ` 5 4 7 + * ` Output: + * ` Merged tree: + * ` 3 + * ` / \ + * ` 4 5 + * ` / \ \ + * ` 5 4 7 + * ` + * ` + * ` 思路: 使用递归遍历二叉树,然后对两者进行操作 + */ + +public class _617_mergeTwoBinaryTree { + + static class TreeNode { + int val; + TreeNode left; + TreeNode right; + } + + public TreeNode mergeTrees(TreeNode t1, TreeNode t2) { + if (t1 == null) { + return t2; + } + if (t2 == null) { + return t1; + } + + t1.val += t2.val; + t1.left = mergeTrees(t1.left, t2.left); + t1.right = mergeTrees(t1.right, t2.right); + return t1; + } +} \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_14_longestCommonPrefix.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_14_longestCommonPrefix.java new file mode 100644 index 0000000..e639d52 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_14_longestCommonPrefix.java @@ -0,0 +1,51 @@ +package com.leosanqing.leetcode.easy.array; + +/** + * @Author: rtliu + * @Date: 2020/7/3 下午5:08 + * @Package: com.leosanqing.leetcode.easy.array + * @Description: Write a function to find the longest common prefix string amongst an array of strings. + * If there is no common prefix, return an empty string "". + *

+ * Example 1: + * Input: ["flower","flow","flight"] + * Output: "fl" + *

+ * Example 2: + * Input: ["dog","racecar","car"] + * Output: "" + * Explanation: + * There is no common prefix among the input strings. + * @Version: 1.0 + */ +public class _14_longestCommonPrefix { + // public static void main(String[] args) { +// BigInteger bigDecimal = BigInteger.valueOf(Math.pow(2, 478)); +// System.out.println(bigDecimal); +// } + + + public static void main(String[] args) { + String[] strings = new String[]{"aa", "a"}; + + System.out.println(longestCommonPrefix(strings)); + } + + public static String longestCommonPrefix(String[] strs) { + if (strs == null || strs.length == 0) { + return ""; + } + + String pre = strs[0]; + for (int i = 1; i < strs.length; i++) { + // 每次减去一个字符,找最长的公共前缀 + while (strs[i].indexOf(pre) != 0) { + pre = pre.substring(0, pre.length() - 1); + } + } + + return pre; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_1_twoSum.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_1_twoSum.java new file mode 100644 index 0000000..cac3cbe --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_1_twoSum.java @@ -0,0 +1,36 @@ +package com.leosanqing.leetcode.easy.array; + +import java.util.HashMap; +import java.util.Map; + +/** + * description:Given an array of integers, return indices of the two numbers such that they add up to a specific target. + * You may assume that each input would have exactly one solution, and you may not use the same element twice. + * 给你一个数组,返回数组两个元素相加等于目标值的元素的下标,返回其中一组解即可。同一个元素不能用两次; + *

+ * 如{1,2,5,6,7,2} 目标值 11 + * 返回{2,3} + * solution: 利用HashMap存储元素以及下标,遍历元素,利用hash表,直接锁定另外一个符合条件的下标 + */ +class _1_twoSum { + public static int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + map.put(nums[i], i); + } + for (int i = 0; i < nums.length; i++) { + if (map.containsKey(target - nums[i]) + && map.get(target - nums[i]) != i) { + return new int[]{i, map.get((target - nums[i]))}; + } + + } + return null; + } + + public static void main(String[] args) { + int[] a = {1, 2, 5, 6}; + + twoSum(a, 7); + } +} \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_26_removeDuplicates.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_26_removeDuplicates.java new file mode 100644 index 0000000..7d67561 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_26_removeDuplicates.java @@ -0,0 +1,35 @@ +package com.leosanqing.leetcode.easy.array; + +/** + * 描述:给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + *

+ * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 + *

+ * 给定 nums = [0,0,1,1,1,2,2,3,3,4], + *

+ * 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 + *

+ * 你不需要考虑数组中超出新长度后面的元素。 + *

+ *

+ * 解法:替换, + */ + + +class _26_removeDuplicates { + public int removeDuplicates(int[] nums) { + int length = 0; + for (int i = 0; i < nums.length; i++) { + if (i == 0) { + length++; + } else { + if (nums[i] - nums[i - 1] != 0) { + nums[length] = nums[i]; + length++; + } + } + + } + return length; + } +} \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_27_removeElement.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_27_removeElement.java new file mode 100644 index 0000000..0af7fe6 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_27_removeElement.java @@ -0,0 +1,37 @@ +package com.leosanqing.leetcode.easy.array; + +/** + * ` description: 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。 + * ` 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 + * ` 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 + * ` + * ` example: 给定 nums = [3,2,2,3], val = 3, + * ` 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 + * ` 你不需要考虑数组中超出新长度后面的元素。 + * ` + * ` 思路: 因为他是返回数组的长度,以此来打印出所有val的数字 + * ` 也就是说我们数组从0到那个长度之间,不会再出现val相等的数字 + * ` 所以,我们设置一个从0开始的数字i,然后遍历数组, + * ` 每当遇到一个不等于 val的值,我们就用它来覆盖数组的值 + * ` 然后i++; + */ + + +public class _27_removeElement { + public int removeElement(int[] nums, int val) { + int i = 0; + for (int j = 0; j < nums.length; j++) { + if (nums[j] != val) { + nums[i] = nums[j]; + i++; + } + } + return i; + } + + public static void main(String[] args) { + _27_removeElement a27removeElement = new _27_removeElement(); + int[] a = {1, 2, 5, 3, 2, 1, 4, 5, 3, 5}; + a27removeElement.removeElement(a, 2); + } +} \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_35_searchInsertPosition.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_35_searchInsertPosition.java new file mode 100644 index 0000000..a8a9a52 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_35_searchInsertPosition.java @@ -0,0 +1,43 @@ +package com.leosanqing.leetcode.easy.array; + +/** + * ` 题目: 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 + * ` 你可以假设数组中无重复元素。 + * ` + * ` 举例: 输入: [1,3,5,6], 5 + * ` 输出: 2 + * ` + * ` 输入: [1,3,5,6], 2 + * ` 输出: 1 + * ` + * ` + * ` 思路: 因为题目已经给定了排好的数组,我最直接就想到用二分法 + * ` 如果找到了就返回下标, + * ` 没找到就返回左边的下标, + * ` 如果你返回的是right,那你就会有 bug, + * ` + */ + +public class _35_searchInsertPosition { + public int searchInsert(int[] nums, int target) { + int left = 0, right = nums.length - 1, mid; + while (left <= right) { + mid = (left + right) >> 1; + if (nums[mid] == target) + return mid; + else if (nums[mid] > target) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } + + public static void main(String[] args) { + int[] a = {1, 3, 5, 7}; + _35_searchInsertPosition a35searchInsertPosition = new _35_searchInsertPosition(); + System.out.println(a35searchInsertPosition.searchInsert(a, 4)); + + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_53_maximum_subarray.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_53_maximum_subarray.java new file mode 100644 index 0000000..46b26d0 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/array/_53_maximum_subarray.java @@ -0,0 +1,57 @@ +package com.leosanqing.leetcode.easy.array; + +/** + * @description: 给定一个整数数组 nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 + *

+ * 示例 1: + *

+ * 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] + * 输出:6 + * 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。 + * 示例 2: + * 输入:nums = [1] + * 输出:1 + *

+ * 示例 3: + * 输入:nums = [0] + * 输出:0 + *

+ * 示例 4: + * 输入:nums = [-1] + * 输出:-1 + *

+ * 示例 5: + * 输入:nums = [-100000] + * 输出:-100000 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/maximum-subarray + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * @author: rtliu + * @date: 2021/4/9 10:09 上午 + */ +public class _53_maximum_subarray { + + public static void main(String[] args) { + System.out.println(maxSubArray(new int[]{-2, 1, -3, 4, -1, 2, 1, -5, 4})); + System.out.println(maxSubArray(new int[]{2})); + System.out.println(maxSubArray(new int[]{-1, 2, -1})); + System.out.println(maxSubArray(new int[]{-1, -1, -2, -2})); + } + + /** + * 这个题思路很简单,从左到右遍历,如果前面的和小于当前数,则舍弃之前的数组,从当前位置重新开始找 + * + * @param nums + * @return + */ + public static int maxSubArray(int[] nums) { + int max = nums[0]; + int sum = 0; + for (int num : nums) { + sum = Math.max(sum + num,num); + max = Math.max(sum, max); + } + return max; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_118_pascals_triangle.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_118_pascals_triangle.java new file mode 100644 index 0000000..4bd382e --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_118_pascals_triangle.java @@ -0,0 +1,41 @@ +package com.leosanqing.leetcode.easy.list; + +import com.alibaba.fastjson.JSON; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/31 下午4:05 + * @Package: com.leosanqing.leetcode.easy.list + * @Description: 1 + * ` Given a non-negative integer numRows, generate the first numRows of Pascal's triangle. + * ` In Pascal's triangle, each number is the sum of the two numbers directly above it. + * ` Example: + * ` Input: 5 + * ` Output: [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ] + * @Version: 1.0 + */ +public class _118_pascals_triangle { + public static void main(String[] args) { + System.out.println(JSON.toJSONString(generate(5))); + } + public static List> generate(int numRows) { + List> answer = new ArrayList<>(); + + for (int i = 1; i <= numRows; i++) { + List list = new ArrayList<>(i); + for (int j = 0; j < i; j++) { + if (j == 0 || j == i - 1) { + list.add(1); + continue; + } + list.add(answer.get(i - 2).get(j - 1) + answer.get(i - 2).get(j)); + } + answer.add(list); + } + + return answer; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_119_pascals_triangleII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_119_pascals_triangleII.java new file mode 100644 index 0000000..ec94e2b --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_119_pascals_triangleII.java @@ -0,0 +1,40 @@ +package com.leosanqing.leetcode.easy.list; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/31 下午4:45 + * @Package: com.leosanqing.leetcode.easy.list + * @Description: 1 + * ` Given a non-negative index k where k ≤ 33, return the kth index row of the Pascal's triangle. + * ` Note that the row index starts from 0. + * ` In Pascal's triangle, each number is the sum of the two numbers directly above it. + * ` Example: + * ` Input: 3 + * ` Output: [1,3,3,1] + * @Version: 1.0 + */ +public class _119_pascals_triangleII { + public static void main(String[] args) { + generate(3); + } + + public static List generate(int numRows) { + List answer = new ArrayList<>(numRows + 1); + + answer.add(0, 1); + + for (int i = 1; i <= numRows; i++) { + Integer integer = 1; + answer.add(i, 1); + for (int j = 1; j < i; j++) { + Integer integer1 = answer.get(j); + answer.set(j, integer + integer1); + integer = integer1; + } + } + return answer; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_141_linked_list_cycle.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_141_linked_list_cycle.java new file mode 100644 index 0000000..bec4f98 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_141_linked_list_cycle.java @@ -0,0 +1,46 @@ +package com.leosanqing.leetcode.easy.list; + +import com.leosanqing.leetcode.medium.list.ListNode; + +/** + * @Author: rtliu + * @Date: 2020/8/4 下午4:15 + * @Package: com.leosanqing.leetcode.easy.list + * @Description: 1 + * ` Given a linked list, determine if it has a cycle in it. + * ` To represent a cycle in the given linked list, + * ` we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. + * ` If pos is -1, then there is no cycle in the linked list. + * ` Example 1: + * ` Input: head = [3,2,0,-4], pos = 1 + * ` Output: true + * ` Explanation: There is a cycle in the linked list, where tail connects to the second node. + * ` Example 2: + * ` Input: head = [1,2], pos = 0 + * ` Output: true + * ` Explanation: There is a cycle in the linked list, where tail connects to the first node. + * @Version: 1.0 + */ +public class _141_linked_list_cycle { + /** + * 设置两个指针 一个快指针 一个慢指针 ,只要出现两个指针指向的一样,那就说明有环 + * + * @param head + * @return + */ + public boolean hasCycle(ListNode head) { + ListNode fast = head; + ListNode slow = head; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + if (fast == slow) { + return true; + } + } + + return false; + + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_21_merge_two_sorted_lists.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_21_merge_two_sorted_lists.java new file mode 100644 index 0000000..5f62dc4 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_21_merge_two_sorted_lists.java @@ -0,0 +1,99 @@ +package com.leosanqing.leetcode.easy.list; + +import com.leosanqing.leetcode.medium.list.ListNode; + +/** + * @Author: rtliu + * @Date: 2020/7/7 下午4:46 + * @Package: com.leosanqing.leetcode.easy.list + * @Description: Merge two sorted linked lists and return it as a new sorted list. + * The new list should be made by splicing together the nodes of the first two lists. + * Example: + * Input: 1->2->4, 1->3->4 + * Output: 1->1->2->3->4->4 + * @Version: 1.0 + */ +public class _21_merge_two_sorted_lists { + + public static void main(String[] args) { + ListNode node1 = new ListNode(4); + ListNode node2 = new ListNode(2, node1); + ListNode node3 = new ListNode(1, node2); + ListNode node4 = new ListNode(4); + ListNode node5 = new ListNode(3, node4); + ListNode node6 = new ListNode(1, node5); + + System.out.println(mergeTwoLists(node3, node6)); + } + + public static ListNode mergeTwoLists(ListNode l1, ListNode l2) { + + // 先处理极限情况 + if (l1 == null && l2 == null) { + return new ListNode(); + } + if (l1 == null) { + return l2; + } + if (l2 == null) { + return l1; + } + + // 放一个虚拟的头,用来预防各种极限值,很多解法都会使用这种方式 + ListNode newList = new ListNode(); + ListNode fakeHead = newList; + ListNode p1 = l1; + ListNode p2 = l2; + + while (p1 != null && p2 != null) { + if (p1.val <= p2.val) { + newList.next = p1; + p1 = p1.next; + } else { + newList.next = p2; + p2 = p2.next; + } + newList = newList.next; + } + + // 如果还有剩的 + if (p1 != null) { + newList.next = p1; + } + + if (p2 != null) { + newList.next = p2; + } + + return fakeHead.next; + } + + public ListNode mergeTwoLists1(ListNode l1, ListNode l2) { + + ListNode cur = new ListNode(); + ListNode fakeHead = cur; + ListNode n1 = l1; + ListNode n2 = l2; + + while (n1 != null && n2 != null) { + if (n1.val < n2.val) { + cur.next = n1; + n1 = n1.next; + } else { + cur.next = n2; + n2 = n2.next; + } + cur = cur.next; + } + // 如果还有剩的 + if (n1 != null) { + cur.next = n1; + } + + if (n2 != null) { + cur.next = n2; + } + + return fakeHead.next; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_876_middle_of_the_linked_list.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_876_middle_of_the_linked_list.java new file mode 100644 index 0000000..d8b0463 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/list/_876_middle_of_the_linked_list.java @@ -0,0 +1,54 @@ +package com.leosanqing.leetcode.easy.list; + +import com.leosanqing.leetcode.medium.list.ListNode; + +/** + * @Author: rtliu + * @Date: 2020/7/22 上午9:28 + * @Package: com.leosanqing.leetcode.easy.list + * @Description: 1 + * Given a non-empty, singly linked list with head node head, return a middle node of linked list. + * If there are two middle nodes, return the second middle node. + * Example 1: + * Input: [1,2,3,4,5] + * Output: Node 3 from this list (Serialization: [3,4,5]) The returned node has value 3. + * (The judge's serialization of this node is [3,4,5]). + * Note that we returned a ListNode object ans, such that: ans.val = 3, + * ans.next.val = 4, ans.next.next.val = 5, and ans.next.next.next = NULL. + * Example 2: + * Input: [1,2,3,4,5,6] + * Output: Node 4 from this list (Serialization: [4,5,6]) + * Since the list has two middle nodes with values 3 and 4, we return the second one. + * @Version: 1.0 + */ +public class _876_middle_of_the_linked_list { + public static void main(String[] args) { + ListNode node1 = new ListNode(6); + ListNode node2 = new ListNode(5, node1); + ListNode node3 = new ListNode(4, node2); + ListNode node4 = new ListNode(3,node3); + ListNode node5 = new ListNode(2, node4); + + middleNode(node5); + } + + public static ListNode middleNode(ListNode head) { + + ListNode fakeHead = new ListNode(); + fakeHead.next = head; + + ListNode fastNode = fakeHead; + ListNode slowNode = fastNode; + while (fastNode != null ) { + slowNode =slowNode.next; + fastNode = fastNode.next; + if(fastNode == null){ + return slowNode; + } + fastNode = fastNode.next; + } + + return slowNode; + + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/num/_263_uglyNumber.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/num/_263_uglyNumber.java new file mode 100644 index 0000000..61c8b6d --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/num/_263_uglyNumber.java @@ -0,0 +1,35 @@ +package com.leosanqing.leetcode.easy.num; + +/** + * @Author: rtliu + * @Date: 2020/6/23 下午3:34 + * @Package: com.leosanqing.leetcode.easy.num + * @Description: Write a program to check whether a given number is an ugly number. + * Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. + * @Version: 1.0 + */ +public class _263_uglyNumber { + public static void main(String[] args) { + System.out.println(isUgly(15)); + } + + public static boolean isUgly(int num) { + + if (num == 0) { + return false; + } + + while (num != 1) { + if (num % 5 == 0) { + num /= 5; + } else if (num % 3 == 0) { + num /= 3; + } else if (num % 2 == 0) { + num /= 2; + } else { + return false; + } + } + return true; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/num/_70_climbing_stairs.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/num/_70_climbing_stairs.java new file mode 100644 index 0000000..1e4bb7b --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/num/_70_climbing_stairs.java @@ -0,0 +1,56 @@ +package com.leosanqing.leetcode.easy.num; + +/** + * @Author: rtliu + * @Date: 2020/7/20 下午2:26 + * @Package: com.leosanqing.leetcode.easy.num + * @Description: 1 + * ` You are climbing a stair case. + * ` It takes n steps to reach to the top. + * ` Each time you can either climb 1 or 2 steps. + * ` In how many distinct ways can you climb to the top? + * ` Example 1: + * ` Input: 2 + * ` Output: 2 + * ` Explanation: + * ` There are two ways to climb to the top. + * ` 1. 1 step + 1 step 2. 2 steps + * ` Example 2: + * ` Input: 3 + * ` Output: 3 + * ` Explanation: + * ` There are three ways to climb to the top. + * ` 1. 1 step + 1 step + 1 step + * ` 2. 1 step + 2 steps + * ` 3. 2 steps + 1 step + * @Version: 1.0 + */ +public class _70_climbing_stairs { + public static void main(String[] args) { + System.out.println(climbStairs(7)); + } + + /** + * 仔细看这个题 其实是斐波那契数列的变种,解题方法一致 + * + * 我们可以使用栈,也可以使用 DP,但是 DP明显优于栈 + * + * @param n + * @return + */ + public static int climbStairs(int n) { + if (n <= 3) { + return n; + } + int pre = 3; + int prePre = 2; + int cur = 0; + for (int i = 4; i <= n; i++) { + cur = pre + prePre; + prePre = pre; + pre = cur; + } + + return cur; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/num/_7_reverseInteger.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/num/_7_reverseInteger.java new file mode 100644 index 0000000..5d63324 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/num/_7_reverseInteger.java @@ -0,0 +1,38 @@ +package com.leosanqing.leetcode.easy.num; + +/** + * @Author: rtliu + * @Date: 2020/7/3 下午3:19 + * @Package: com.leosanqing.leetcode.easy.num + * @Description: ` Given a 32-bit signed integer, reverse digits of an integer. + * ` Example 1: + * ` Input: 123 + * ` Output: 321 + * ` Example 2: + * ` Input: -123 + * ` Output: -321 + * ` Example 3: + * ` Input: 120 + * ` Output: 21 + * ` Note: + * ` Assume we are dealing with an environment which could only store integers + * ` within the 32-bit signed integer range: [−231, 231 − 1]. For the purpose of this problem, + * ` assume that your function returns 0 when the reversed integer overflows. + * @Version: 1.0 + */ +public class _7_reverseInteger { + public static void main(String[] args) { + _7_reverseInteger reverseInteger = new _7_reverseInteger(); + System.out.println(reverseInteger.reverse(-1200)); + } + + public int reverse(int x) { + long res = 0; + while (x != 0) { + res *= 10; + res += x % 10; + x /= 10; + } + return (int) res == res ? (int) res : 0; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/num/_9_palindrome_number.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/num/_9_palindrome_number.java new file mode 100644 index 0000000..f1ec6c3 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/num/_9_palindrome_number.java @@ -0,0 +1,70 @@ +package com.leosanqing.leetcode.easy.num; + +/** + * @Author: rtliu + * @Date: 2020/7/3 下午3:24 + * @Package: com.leosanqing.leetcode.easy.num + * @Description: ` + * ` Determine whether an integer is a palindrome. + * ` An integer is a palindrome when it reads the same backward as forward. + * ` + * ` Example 1: + * ` Input: 121 + * ` Output: true + * ` Example 2: + * ` Input: -121 + * ` Output: false + * ` Explanation: + * ` From left to right, it reads -121. + * ` From right to left, it becomes 121-. + * ` Therefore it is not a palindrome. + * ` Example 3: + * ` Input: 10 + * ` Output: false + * ` Explanation: + * ` Reads 01 from right to left. Therefore it is not a palindrome. + * @Version: 1.0 + */ +public class _9_palindrome_number { + + public static void main(String[] args) { + System.out.println(isPalindrome(12121)); + } + + public static boolean isPalindrome(int x) { + // 如果小于0 或者大于零 但是以0结尾的都不是 + if (x < 0 || (x != 0 && x % 10 == 0)) { + return false; + } + + int rev = 0; + // 只需要一半,就可以进行匹配 + while (x > rev) { + rev = rev * 10 + x % 10; + x /= 10; + } + return rev == x || x == rev / 10; + } + + /** + * 使用字符串 + * + * @param x + * @return + */ + public static boolean isPalindrome2(int x) { + // 如果小于0 或者大于零 但是以0结尾的都不是 + if (x < 0 || (x != 0 && x % 10 == 0)) { + return false; + } + + String s = String.valueOf(x); + + for (int i = 0; i < s.length() / 2; i++) { + if (s.charAt(i) != s.charAt(s.length() - i - 1)) { + return false; + } + } + return true; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/string/_20_valid_parentheses.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/string/_20_valid_parentheses.java new file mode 100644 index 0000000..1ce4f5f --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/string/_20_valid_parentheses.java @@ -0,0 +1,64 @@ +package com.leosanqing.leetcode.easy.string; + +import java.util.Stack; + +/** + * @Author: rtliu + * @Date: 2020/7/7 下午4:20 + * @Package: com.leosanqing.leetcode.easy.string + * @Description: ` Given a string containing just the characters '(', ')', '{', '}', '[' and ']', + * ` determine if the input string is valid. + * ` An input string is valid if: + * ` Open brackets must be closed by the same type of brackets. + * ` Open brackets must be closed in the correct order. + * ` Note that an empty string is also considered valid. + * ` Example 1: + * ` Input: "()" + * ` Output: true + * ` Example 2: + * ` Input: "()[]{}" + * ` Output: true + * ` Example 3: + * ` Input: "(]" + * ` Output: false + * ` Example 4: + * ` Input: "([)]" + * ` Output: false + * ` Example 5: + * ` Input: "{[]}" + * ` Output: true + * @Version: 1.0 + */ +public class _20_valid_parentheses { + public static void main(String[] args) { + + } + + public boolean isValid(String s) { + + if (s == null || "".equals(s)) { + return true; + } + + char[] charArray = s.toCharArray(); + if (charArray.length % 2 != 0) { + return false; + } + + Stack stack = new Stack<>(); + for (char c : charArray) { + if (c == '[') { + stack.push(']'); + } else if (c == '(') { + stack.push(')'); + } else if (c == '{') { + stack.push('}'); + } else if (stack.isEmpty() || stack.pop() != c) { + return false; + } + + } + + return stack.isEmpty(); + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/string/_242_validAnagram.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/string/_242_validAnagram.java new file mode 100644 index 0000000..718cfdf --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/string/_242_validAnagram.java @@ -0,0 +1,52 @@ +package com.leosanqing.leetcode.easy.string; + +/** + * @Author: rtliu + * @Date: 2020/6/22 下午4:48 + * @Package: com.leosanqing.leetcode.easy.string + * @Description: Given two strings s and t , write a function to determine if t is an anagram of s. + * @Version: 1.0 + *

+ *

+ * Example 1: + *

+ * Input: s = "anagram", t = "nagaram" + * Output: true + *

+ * Example 2: + *

+ * Input: s = "rat", t = "car" + * Output: false + * Note: + * You may assume the string contains only lowercase alphabets. + *

+ * Follow up: + * What if the inputs contain unicode characters? How would you adapt your solution to such case? + */ +public class _242_validAnagram { + + public static void main(String[] args) { + + } + + public static boolean isAnagram(String s, String t) { + int[] alphabet = new int[26]; + if (s.length() != t.length()) { + return false; + } + for (int i = 0; i < s.length(); i++) { + alphabet[s.charAt(i) - 'a']++; + } + for (int i = 0; i < t.length(); i++) { + alphabet[t.charAt(i) - 'a']--; + } + + for (int i : alphabet) { + if (i != 0) { + return false; + } + } + + return true; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/string/_60_permutation_sequence.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/string/_60_permutation_sequence.java new file mode 100644 index 0000000..e405bef --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/string/_60_permutation_sequence.java @@ -0,0 +1,65 @@ +package com.leosanqing.leetcode.easy.string; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/15 下午5:39 + * @Package: com.leosanqing.leetcode.easy.string + * @Description: 1 + * ` The set [1,2,3,...,n] contains a total of n! unique permutations. + * ` By listing and labeling all of the permutations in order, + * ` we get the following sequence for n = 3: + * ` "123" "132" "213" "231" "312" "321" Given n and k, + * ` return the kth permutation sequence. + * ` 集[1,2,3,...,n]总共包含n!独特的排列。 + * ` 通过按顺序列出和标记所有排列, + * ` 我们得到n = 3的以下序列: + * ` “ 123”“ 132”“ 213”“ 231”“ 312”“ 321”给定n和k, + * ` 返回第k个排列序列。 + * ` Note: + * ` Given n will be between 1 and 9 inclusive. + * ` Given k will be between 1 and n! inclusive. + * ` Example 1: + * ` Input: n = 3, k = 3 + * ` Output: "213" + * ` Example 2: + * ` Input: n = 4, k = 9 + * ` Output: "2314" + * @Version: 1.0 + */ +public class _60_permutation_sequence { + + public static void main(String[] args) { + System.out.println(getPermutation(8,30654)); + } + public static String getPermutation(int n, int k) { + + LinkedList notUsed = new LinkedList<>(); + + int sum = 1; + for (int i = 1; i <= n; i++) { + notUsed.add(i); + if(i == n){ + break; + } + sum *= i; + } + + StringBuilder result = new StringBuilder(); + k--; + + while (true) { + result.append(notUsed.remove(k / sum)); + k = k % sum; + if(notUsed.isEmpty()){ + break; + } + sum /= notUsed.size(); + } + return result.toString(); + + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_100_same_tree.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_100_same_tree.java new file mode 100644 index 0000000..df2ae29 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_100_same_tree.java @@ -0,0 +1,59 @@ +package com.leosanqing.leetcode.easy.tree; + + +import com.leosanqing.leetcode.medium.tree.TreeNode; + +/** + * @Author: rtliu + * @Date: 2020/7/27 上午11:41 + * @Package: com.leosanqing.leetcode.easy.tree + * @Description: 1 + * ` Given two binary trees, write a function to check if they are the same or not. + * ` Two binary trees are considered the same if they are structurally identical and the nodes have the same + * value. + * ` Example 1: + * ` Input: 1 1 + * ` / \ / \ + * ` 2 3 2 3 + * ` [1,2,3], [1,2,3] + * ` Output: true + * ` Example 2: + * ` Input: + * ` 1 1 + * ` / \ + * ` 2 2 + * ` [1,2], [1,null,2] + * ` Output: false + * ` Example 3: + * ` Input: + * ` 1 1 + * ` / \ / \ + * ` 2 1 1 2 + * ` [1,2,1], [1,1,2] + * ` Output: false + * @Version: 1.0 + */ +public class _100_same_tree { + public boolean isSameTree(TreeNode p, TreeNode q) { + + return backTrace(p,q); + } + + private static boolean backTrace(TreeNode p, TreeNode q) { + if (p == null && q == null) { + return true; + } + + if (p == null || q == null) { + return false; + } + + if (p.val != q.val) { + return false; + } + return backTrace(p.left, q.left) && backTrace(p.right, q.right); + + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_101_symmetric_tree.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_101_symmetric_tree.java new file mode 100644 index 0000000..5c9c2cd --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_101_symmetric_tree.java @@ -0,0 +1,50 @@ +package com.leosanqing.leetcode.easy.tree; + +import com.leosanqing.leetcode.medium.tree.TreeNode; + +/** + * @Author: rtliu + * @Date: 2020/7/27 下午3:46 + * @Package: com.leosanqing.leetcode.easy.tree + * @Description: 1 + * ` Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). + * ` For example, this binary tree [1,2,2,3,4,4,3] is symmetric: + * ` 1 + * ` / \ + * ` 2 2 + * ` / \ / \ + * ` 3 4 4 3 + * ` But the following [1,2,2,null,3,null,3] is not: + * ` 1 + * ` / \ + * ` 2 2 + * ` \ \ + * ` 3 3 + * @Version: 1.0 + */ +public class _101_symmetric_tree { + + public static boolean isSymmetric(TreeNode root) { + if (root == null) { + return true; + } + return backtrace(root.left, root.right); + } + + private static boolean backtrace(TreeNode left, TreeNode right) { + if (left == null && right == null) { + return true; + } + if (left == null || right == null) { + return false; + } + + if (left.val != right.val) { + return false; + } + + return backtrace(left.left, right.right) + && backtrace(left.right, right.left); + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_104_maximum_depth_of_binary_tree.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_104_maximum_depth_of_binary_tree.java new file mode 100644 index 0000000..1dffe71 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_104_maximum_depth_of_binary_tree.java @@ -0,0 +1,59 @@ +package com.leosanqing.leetcode.easy.tree; + +import com.leosanqing.leetcode.medium.tree.TreeNode; + +/** + * @Author: rtliu + * @Date: 2020/7/28 下午4:31 + * @Package: com.leosanqing.leetcode.easy.tree + * @Description: 1 + * ` Given a binary tree, find its maximum depth. + * ` The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. + * ` Note: A leaf is a node with no children. + * ` Example: Given binary tree [3,9,20,null,null,15,7], + * ` 3 + * ` / \ + * ` 9 20 + * ` / \ + * ` 15 7 + * ` return its depth = 3. + * @Version: 1.0 + */ +public class _104_maximum_depth_of_binary_tree { + + + public static void main(String[] args) { + TreeNode treeNode = new TreeNode(3); + treeNode.left = new TreeNode(9); + treeNode.right = new TreeNode(20); + treeNode.right.left = new TreeNode(1); + treeNode.right.right = new TreeNode(7); + System.out.println(maxDepth(treeNode)); + } + + static class Num{ + int max; + } + + public static int maxDepth(TreeNode root) { + Num num = new Num(); + num.max = 0; + if (root == null) { + return 0; + } + backtrace(root, 0, num); + return num.max; + } + + private static void backtrace(TreeNode root, int curInt, Num max) { + if (root == null) { + return; + } + + max.max = Math.max(++curInt, max.max); + + backtrace(root.left, curInt, max); + backtrace(root.right, curInt, max); + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_107_binary_tree_level_order_traversalII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_107_binary_tree_level_order_traversalII.java new file mode 100644 index 0000000..13e1420 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_107_binary_tree_level_order_traversalII.java @@ -0,0 +1,67 @@ +package com.leosanqing.leetcode.easy.tree; + +import com.leosanqing.leetcode.medium.tree.TreeNode; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/29 下午4:15 + * @Package: com.leosanqing.leetcode.easy.tree + * @Description: 1 + * ` Given a binary tree, return the bottom-up level order traversal of its nodes' values. + * ` (ie, from left to right, level by level from leaf to root). + * ` For example: Given binary tree [3,9,20,null,null,15,7], + * ` 3 + * ` / \ + * ` 9 20 + * ` / \ + * ` 15 7 + * ` return its bottom-up level order traversal as: + * ` [ + * ` [15,7], + * ` [9,20], + * ` [3] + * ` ] + * @Version: 1.0 + */ +public class _107_binary_tree_level_order_traversalII { + public static void main(String[] args) { + TreeNode treeNode = new TreeNode(3); + treeNode.left = new TreeNode(9); + treeNode.right = new TreeNode(20); + treeNode.right.left = new TreeNode(15); + treeNode.right.right = new TreeNode(7); + levelOrderBottom(treeNode); + } + + public static List> levelOrderBottom(TreeNode root) { + + List> answer = new ArrayList<>(); + + backTrace(answer, 0, root); + Collections.reverse(answer); + return answer; + } + + + private static void backTrace(List> answer, int depth, TreeNode root) { + if (root == null) { + return; + } + + if (answer.size() > depth) { + answer.get(depth).add(root.val); + } else { + List list = new ArrayList<>(); + list.add(root.val); + answer.add(new ArrayList<>(list)); + } + + backTrace(answer, depth + 1, root.left); + backTrace(answer, depth + 1, root.right); + + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_108_convert_sorted_array_to_binary_search_tree.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_108_convert_sorted_array_to_binary_search_tree.java new file mode 100644 index 0000000..1d8ce25 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_108_convert_sorted_array_to_binary_search_tree.java @@ -0,0 +1,58 @@ +package com.leosanqing.leetcode.easy.tree; + +import com.leosanqing.leetcode.medium.tree.TreeNode; + +/** + * @Author: rtliu + * @Date: 2020/7/30 上午9:26 + * @Package: com.leosanqing.leetcode.easy.tree + * @Description: 1 + * ` Given an array where elements are sorted in ascending order, convert it to a height balanced BST. + * ` For this problem, + * ` a height-balanced binary tree is defined as a binary tree in + * ` which the depth of the two subtrees of every node never differ by more than 1. + * ` + * ` + * ` 给定一个数组,其中元素按升序排序,请将其转换为高度平衡的BST。 + * ` 比如这个问题, + * ` 高度平衡的二叉树被定义为 + * ` 每个节点的两个子树的深度相差不超过1。 + * ` Example: + * ` Given the sorted array: [-10,-3,0,5,9], + * ` One possible answer is: [0,-3,9,-10,null,5], + * ` which represents the following height balanced BST: + * ` 0 + * ` / \ + * ` -3 9 + * ` / / + * ` -10 5 + * @Version: 1.0 + */ +public class _108_convert_sorted_array_to_binary_search_tree { + + public static void main(String[] args) { + TreeNode treeNode = sortedArrayToBST(new int[]{-10, -3, 0, 5, 9}); + System.out.println(111); + } + + public static TreeNode sortedArrayToBST(int[] nums) { + return backTrace(nums, 0, nums.length - 1); + + } + + private static TreeNode backTrace(int[] nums, int left, int right) { + if (left > right) { + return null; + } + + int mid = (right - left) / 2 + left; + + TreeNode root = new TreeNode(nums[mid]); + + root.left = backTrace(nums, left, mid - 1); + root.right = backTrace(nums, mid + 1, right); + return root; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_110_balanced_binary_tree.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_110_balanced_binary_tree.java new file mode 100644 index 0000000..599ffaa --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_110_balanced_binary_tree.java @@ -0,0 +1,74 @@ +package com.leosanqing.leetcode.easy.tree; + +import com.leosanqing.leetcode.medium.tree.TreeNode; + +/** + * @Author: rtliu + * @Date: 2020/7/30 下午3:06 + * @Package: com.leosanqing.leetcode.easy.tree + * @Description: 1 + * ` Given a binary tree, determine if it is height-balanced. + * ` For this problem, a height-balanced binary tree is defined as: + * ` a binary tree in which the left and right subtrees of every node differ in height by no more than 1. + * ` Example 1: + * ` Given the following tree [3,9,20,null,null,15,7]: + * ` 3 + * ` / \ + * ` 9 20 + * ` / \ + * ` 15 7 + * ` Return true. + * ` Example 2: + * ` Given the following tree [1,2,2,3,3,null,null,4,4]: + * ` 1 + * ` / \ + * ` 2 2 + * ` / \ + * ` 3 3 + * ` / \ + * ` 4 4 + * @Version: 1.0 + */ +public class _110_balanced_binary_tree { + + private static boolean result = true; + + public static void main(String[] args) { + TreeNode treeNode = new TreeNode(1); + treeNode.left = new TreeNode(2); + treeNode.right = new TreeNode(2); + treeNode.left.left = new TreeNode(3); + treeNode.left.right = new TreeNode(3); + treeNode.right.left = new TreeNode(3); + treeNode.right.right = new TreeNode(3); + treeNode.left.left.left = new TreeNode(4); + treeNode.left.left.right = new TreeNode(4); + treeNode.left.right.left = new TreeNode(4); + treeNode.left.right.right = new TreeNode(4); + treeNode.right.left.left = new TreeNode(4); + treeNode.right.left.right = new TreeNode(4); + treeNode.left.left.left.left = new TreeNode(4); + treeNode.left.left.left.right = new TreeNode(4); + System.out.println(isBalanced(treeNode)); + } + + public static boolean isBalanced(TreeNode root) { + result = true; + backTrace(root); + return result; + } + + private static int backTrace(TreeNode root) { + if (root == null) { + return 0; + } + int left = backTrace(root.left); + int right = backTrace(root.right); + + if (Math.abs(left - right) > 1) { + result = false; + } + + return 1 + Math.max(left, right); + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_111_minimum_depth_of_binary_tree.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_111_minimum_depth_of_binary_tree.java new file mode 100644 index 0000000..93c519f --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/easy/tree/_111_minimum_depth_of_binary_tree.java @@ -0,0 +1,35 @@ +package com.leosanqing.leetcode.easy.tree; + +import com.leosanqing.leetcode.medium.tree.TreeNode; + +/** + * @Author: rtliu + * @Date: 2020/7/30 下午3:53 + * @Package: com.leosanqing.leetcode.easy.tree + * @Description: 1 + * ` Given a binary tree, find its minimum depth. + * ` The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node. + * ` Note: A leaf is a node with no children. + * ` Example: + * ` Given binary tree [3,9,20,null,null,15,7], + * ` 3 + * ` / \ + * ` 9 20 + * ` / \ + * ` 15 7 + * ` return its minimum depth = 2. + * @Version: 1.0 + */ +public class _111_minimum_depth_of_binary_tree { + + + public int minDepth(TreeNode root) { + if(root == null) { + return 0; + } + if(root.left == null || root.right == null) { + return 1 + Math.max(minDepth(root.left), minDepth(root.right)); + } + return 1 + Math.min(minDepth(root.left), minDepth(root.right)); + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/hard/list/_123_best_time_to_buy_and_sell_stockIII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/hard/list/_123_best_time_to_buy_and_sell_stockIII.java new file mode 100644 index 0000000..7c15335 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/hard/list/_123_best_time_to_buy_and_sell_stockIII.java @@ -0,0 +1,61 @@ +package com.leosanqing.leetcode.hard.list; + +/** + * @Author: rtliu + * @Date: 2020/8/3 上午10:57 + * @Package: com.leosanqing.leetcode.hard.list + * @Description: 1 + * ` Say you have an array for which the ith element is the price of a given stock on day i. + * ` Design an algorithm to find the maximum profit. + * ` You may complete at most two transactions. + * ` Note: You may not engage in multiple transactions at the same time + * ` (i.e., you must sell the stock before you buy again). + * ` Example 1: + * ` Input: [3,3,5,0,0,3,1,4] + * ` Output: 6 + * ` Explanation: + * ` Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3. + * ` Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3. + * ` Example 2: + * ` Input: [1,2,3,4,5] + * ` Output: 4 + * ` Explanation: + * ` Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4. + * ` Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are + * ` engaging multiple transactions at the same time. You must sell before buying again. + * ` Example 3: + * ` Input: [7,6,4,3,1] + * ` Output: 0 + * ` Explanation: + * ` In this case, no transaction is done, i.e. max profit = 0. + * @Version: 1.0 + */ +public class _123_best_time_to_buy_and_sell_stockIII { + public static void main(String[] args) { + + maxProfit(new int[]{1, 2, 3, 4, 5}); + } + + public static int maxProfit(int[] prices) { + if (prices == null || prices.length < 2) { + return 0; + } + int totalK = 2; + int[][] dp = new int[totalK + 1][prices.length]; + for (int k = 1; k <= totalK; k++) { + //profit = 0 when k = 0 + for (int i = 1; i < prices.length; i++) { + //buy on day 0, sell on day i + int maxProfitSellOnDayI = Math.max(0, prices[i] - prices[0]); + //buy on day j, sell on day i + for (int j = 1; j < i; j++) { + maxProfitSellOnDayI = Math.max(maxProfitSellOnDayI, dp[k - 1][j - 1] + prices[i] - prices[j]); + } + //sell on day i OR not + dp[k][i] = Math.max(dp[k][i - 1], maxProfitSellOnDayI); + } + } + return dp[totalK][prices.length - 1]; + + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/_201_bitwiseANDOfNumbersRange.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/_201_bitwiseANDOfNumbersRange.java new file mode 100644 index 0000000..864f81a --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/_201_bitwiseANDOfNumbersRange.java @@ -0,0 +1,63 @@ +package com.leosanqing.leetcode.medium; + +/** + * @Author: rtliu + * @Date: 2020/6/1 上午10:45 + * @Package: medium + * @Description: ` + * ` Given a range [m, n] where 0 <= m <= n <= 2147483647, + * ` return the bitwise AND of all numbers in this range, inclusive. + * ` + * ` 给定一个范围 + * ` 返回这个范围内的所有数字的 按位与 的 和 + * ` + * ` Example 1: + * ` + * ` Input: [5,7] + * ` Output: 4 + * ` Example 2: + * ` + * ` Input: [0,1] + * ` Output: 0 + * ` + * ` + * @Version: 1.0 + */ +public class _201_bitwiseANDOfNumbersRange { + + public static void main(String[] args) { + + System.out.println(solution(5, 12)); + + System.out.println(solution(5, 12)); + } + + + /** + * 思路很简单,只要从 m 到 n 的任意一个数字中的一位是0, 那么那一位 不管怎么 & 都是0 + * 比如 [5-12] + * 5 101 + * 6 110 + * 7 111 + * 8 1000 + * 9 1001 + * 10 1010 + * 11 1011 + * 12 1010 + *

+ * 我们看 只要我们找到他的最前面几位是一样的时候,再给他补完后面的位数,就找到了 + * + * @param m + * @param n + * @return + */ + private static int solution(int m, int n) { + int step = 0; + while (m != n) { + m >>= 1; + n >>= 1; + step++; + } + return m << step; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/_73_setMatrixZeroes.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/_73_setMatrixZeroes.java new file mode 100644 index 0000000..0d9be9e --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/_73_setMatrixZeroes.java @@ -0,0 +1,59 @@ +package com.leosanqing.leetcode.medium; + +/** + * 题目: 给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。 + *

+ * 示例:输入: + * [ + * [1,1,1], + * [1,0,1], + * [1,1,1] + * ] + * 输出: + * [ + * [1,0,1], + * [0,0,0], + * [1,0,1] + * ] + *

+ * 思路: 把矩阵的第一行和第一列作为标志位,如果该行或者该列有0,那么他就置为0 + * 然后再遍历,替换 + */ +class _73_setMatrixZeroes { + public void setZeroes(int[][] matrix) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + return; + } + + int col0 = 1, rows = matrix.length, cols = matrix[0].length; + + + for (int i = 0; i < rows; i++) { + if (matrix[i][0] == 0) { + col0 = 0; + } + for (int j = 0; j < cols; j++) { + if (matrix[i][j] == 0) { + matrix[i][0] = 0; + matrix[0][j] = 0; + } + + } + } + + // 遍历集合,把他们变成0 + for (int i = rows - 1; i >= 0; i--) { + for (int j = cols - 1; j >= 1; j--) { + if (matrix[0][j] == 0 || matrix[i][0] == 0) { + matrix[i][j] = 0; + } + } + + if (col0 == 0) { + matrix[i][0] = 0; + } + } + } + + +} \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/TaskEvData.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/TaskEvData.java new file mode 100644 index 0000000..f0eee3f --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/TaskEvData.java @@ -0,0 +1,31 @@ +package com.leosanqing.leetcode.medium.array; + +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; + +/** + * 任务实体 + * @author zdsys-008 + */ +@Getter +@Setter +public class TaskEvData implements Serializable { + /** + * 任务状态码:0[过程中]>>1[成功]>>2[失败] + */ + private int status; + /** + * 任务状态解读:[运行中]>>[运行成功]>>[运行失败] + */ + private String statusMsg; + /** + * 状态成功时,对应的cosurl + */ + private String url; + /** + * 截图成功时,对应的存证hash + */ + private String hash; +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/Test.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/Test.java new file mode 100644 index 0000000..3c42628 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/Test.java @@ -0,0 +1,56 @@ +package com.leosanqing.leetcode.medium.array; + +import com.alibaba.fastjson.JSONObject; + +import java.lang.reflect.Field; + +/** + * @Author: rtliu + * @Date: 2020/7/14 下午4:15 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: + * @Version: + */ +public class Test { + + /** + * 数据处理 >> 暂目前只支持int + String两种类型 + * @param jsonObject + * @param clazz + * @param + * @return + */ + private static T dataHandle(JSONObject jsonObject, Class clazz, String data) throws ClassNotFoundException, IllegalAccessException, InstantiationException { + if (jsonObject != null && jsonObject.containsKey("retCode") && 0 == jsonObject.getInteger("retCode")) { + JSONObject dataJson = jsonObject.getJSONObject(data); + Field[] fields = Class.forName(clazz.getClass().getName()).getDeclaredFields(); + T bean = (T) clazz.newInstance(); + for (int i = 0; i < fields.length; i++){ + fields[i].setAccessible(true); + String fieldName = fields[i].getName(); + System.out.println(fieldName); + if (fields[i].getGenericType() == String.class) { + fields[i].set(String.class,dataJson.getString(fieldName)); + } + if (fields[i].getGenericType() == Integer.class) { + fields[i].set(int.class,dataJson.getIntValue(fieldName)); + } + } + return bean; + } + return null; + } + + public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("retCode",0); + JSONObject innerJson = new JSONObject(); + innerJson.put("status",1); + innerJson.put("statusMsg","运行完成"); + innerJson.put("url","https://www.baidu.com"); + innerJson.put("hash","UUIDUtil.getUuid()"); + jsonObject.put("detail",innerJson); + TaskEvData task = dataHandle(jsonObject,TaskEvData.class,"detail"); + System.out.println(task); + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_11_container_with_most_water.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_11_container_with_most_water.java new file mode 100644 index 0000000..801abeb --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_11_container_with_most_water.java @@ -0,0 +1,52 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/3 下午4:44 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: ` Given n non-negative integers a1, a2, ..., an , + * ` where each represents a point at coordinate (i, ai). + * ` n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). + * ` Find two lines, which together with x-axis forms a container, + * ` such that the container contains the most water. + *

+ *

+ * ` Note: You may not slant the container and n is at least 2. + * ` The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. + * ` In this case, the max area of water (blue section) the container can contain is 49. + * ` + * ` Example: + *

+ * ` Input: [1,8,6,2,5,4,8,3,7] + * ` Output: 49 + * @Version: 1.0 + */ +public class _11_container_with_most_water { + + /** + * 这个很简单,也是很经典的问题 + * 设置两个游标,然后比较两个游标上的容器壁的高度,盛水以矮的为主 + * 然后移动游标,那边矮就移动哪边 + * + * @param height + * @return + */ + public int maxArea(int[] height) { + int left = 0; + int right = height.length - 1; + + int max = 0; + while (left != right) { + if (height[left] > height[right]) { + max = Math.max(height[right] * (right - left), max); + right--; + } else { + max = Math.max(height[left] * (right - left), max); + left++; + } + } + return max; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_120_triangle.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_120_triangle.java new file mode 100644 index 0000000..8c837f4 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_120_triangle.java @@ -0,0 +1,77 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/8/3 上午9:29 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: 1 + * ` Given a triangle, find the minimum path sum from top to bottom. + * ` Each step you may move to adjacent numbers on the row below. + * ` For example, given the following triangle + * ` + * ` 给定一个三角形,找到从上到下的最小路径总和。 + * ` 您可以将每一步移至下面一行中的相邻数字。 + * ` 例如,给定以下三角形 + * ` [ + * ` [2], + * ` [3,4], + * ` [6,5,7], + * ` [4,1,8,3] + * ` ] + * ` The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11). + * @Version: 1.0 + */ +public class _120_triangle { + public static void main(String[] args) { + int[][] list = { + {2}, + {3, 4}, + {6, 5, 7}, + {4, 1, 8, 3} + }; + + List> lists = new ArrayList<>(); + lists.add(Arrays.asList(2)); + lists.add(Arrays.asList(3, 4)); + lists.add(Arrays.asList(6, 5, 7)); + lists.add(Arrays.asList(4, 1, 8, 3)); + System.out.println(minimumTotal(lists)); + } + + /** + * 动态规划 + * @param triangle + * @return + */ + public static int minimumTotal(List> triangle) { + + int[] ints = new int[triangle.size()]; + int min = Integer.MAX_VALUE; + for (List list : triangle) { + // 从右到左,如果从左到右,ints[n-1]会被之前的修改覆盖 + for (int j = list.size() - 1; j >= 0; j--) { + if (j == 0) { + ints[0] += list.get(0); + } else if (j == list.size() - 1) { + ints[j] = list.get(j) + ints[j - 1]; + } else { + ints[j] = list.get(j) + Math.min(ints[j - 1], ints[j]); + } + } + } + for (int anInt : ints) { + if (min > anInt) { + min = anInt; + } + } + + return min; + + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_121_best_time_to_buy_and_sell_stock.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_121_best_time_to_buy_and_sell_stock.java new file mode 100644 index 0000000..51c478c --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_121_best_time_to_buy_and_sell_stock.java @@ -0,0 +1,53 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/8/3 上午10:07 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: ` + * ` Say you have an array for which the ith element is the price of a given stock on day i. + * ` If you were only permitted to complete at most one transaction + * ` (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit. + * ` Note that you cannot sell a stock before you buy one. + * ` + * ` 假设您有一个数组,第i个元素是第i天给定股票的价格。 + * ` 如果您只被允许最多完成一笔交易 + * ` (即,买入并卖出一股股票),设计一种算法以找到最大的利润。 + * ` 请注意,您不能在买股票之前卖出股票。 + * ` + * ` Example 1: + * ` Input: [7,1,5,3,6,4] + * ` Output: 5 + * ` Explanation: + * ` Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5. + * ` Not 7-1 = 6, as selling price needs to be larger than buying price. + * ` Example 2: + * ` Input: [7,6,4,3,1] + * ` Output: 0 + * ` Explanation: + * ` In this case, no transaction is done, i.e. max profit = 0. + * @Version: 1.0 + */ +public class _121_best_time_to_buy_and_sell_stock { + public static void main(String[] args) { + System.out.println(maxProfit(new int[]{7,1,5,3,6,4})); + } + public static int maxProfit(int[] prices) { + if(prices == null || prices.length < 2){ + return 0; + } + int buy = prices[0]; + int profit = 0; + for (int i = 1; i < prices.length; i++) { + if (buy < prices[i]) { + profit = Math.max(prices[i] - buy,profit); + } else { + buy = prices[i]; + } + } + + return profit; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_122_best_time_to_buy_and_sell_stockII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_122_best_time_to_buy_and_sell_stockII.java new file mode 100644 index 0000000..575dad6 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_122_best_time_to_buy_and_sell_stockII.java @@ -0,0 +1,61 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/8/3 上午10:23 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: 1 + * ` Say you have an array prices for which the ith element is the price of a given stock on day i. + * ` Design an algorithm to find the maximum profit. + * ` You may complete as many transactions as you like + * ` (i.e., buy one and sell one share of the stock multiple times). + * ` Note: You may not engage in multiple transactions at the same time + * ` (i.e., you must sell the stock before you buy again). + * ` Example 1: + * ` Input: [7,1,5,3,6,4] + * ` Output: 7 + * ` Explanation: + * ` Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4. + * ` Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3. + * ` Example 2: + * ` Input: [1,2,3,4,5] + * ` Output: 4 + * ` Explanation: + * ` Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4. + * ` Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are + * ` engaging multiple transactions at the same time. You must sell before buying again. + * ` Example 3: + * ` Input: [7,6,4,3,1] + * ` Output: 0 + * ` Explanation: In this case, no transaction is done, i.e. max profit = 0. + * @Version: 1.0 + */ +public class _122_best_time_to_buy_and_sell_stockII { + public static void main(String[] args) { + int[] ints = {7, 6, 4, 3, 1}; + maxProfit(ints); + } + + public static int maxProfit(int[] prices) { + if (prices == null || prices.length < 2) { + return 0; + } + int profit = 0; + int buy = prices[0]; + for (int i = 1; i < prices.length; i++) { + // 只要 后面的大于前面的就继续往后, + if (prices[i] > prices[i - 1]) { + // 如果是最后一个 如[1,2,3,4,5],当他到5的时候,就要卖出了 不然就是0 + if (i == prices.length - 1) { + profit += prices[i] - buy; + } + continue; + } + // 不然就 计算前面的利润 如 [1,2,5,3] 当我们 到 3 的时候,我们就要计算 5-1 的利润 + profit += prices[i - 1] - buy; + buy = prices[i]; + } + + return profit; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_134_gas_station.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_134_gas_station.java new file mode 100644 index 0000000..333c05f --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_134_gas_station.java @@ -0,0 +1,99 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/8/4 上午9:38 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` There are N gas stations along a circular route, + * ` where the amount of gas at station i is gas[i]. + * ` You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its + * next station (i+1). + * ` You begin the journey with an empty tank at one of the gas stations. + * ` Return the starting gas station's index + * ` if you can travel around the circuit once in the clockwise direction, otherwise return -1. + * ` + * ` Note: + * ` If there exists a solution, it is guaranteed to be unique. + * ` Both input arrays are non-empty and have the same length. + * ` Each element in the input arrays is a non-negative integer. + * ` + * ` 沿循环路线有N个加油站, + * ` 其中,第i个站点的天然气量为gas [i]。 + * ` 您有一辆带无限油箱的汽车,从第i站到下一个(i + 1)的行车成本为[i]。 + * ` 您可以从其中一个加油站的空罐开始旅程。 + * ` 返回起始加油站的索引 + * ` 如果您可以沿顺时针方向绕过电路一次,否则返回-1。 + * ` 注意: + * ` 如果存在解决方案,则保证是唯一的。 + * ` 两个输入数组都是非空的,并且具有相同的长度。 + * ` 输入数组中的每个元素都是非负整数。 + * ` Example 1: + * ` Input: + * ` gas = [1,2,3,4,5] + * ` cost = [3,4,5,1,2] + * ` Output: 3 + * ` Explanation: + * ` Start at station 3 (index 3) and fill up with 4 unit of gas. + * ` Your tank = 0 + 4 = 4 Travel to station 4. Your tank = 4 - 1 + 5 = 8 Travel to station 0. + * ` Your tank = 8 - 2 + 1 = 7 Travel to station 1. + * ` Your tank = 7 - 3 + 2 = 6 Travel to station 2. + * ` Your tank = 6 - 4 + 3 = 5 Travel to station 3. + * ` The cost is 5. Your gas is just enough to travel back to station 3. + * ` Therefore, return 3 as the starting index. + * ` Example 2: + * ` Input: + * ` gas = [2,3,4] + * ` cost = [3,4,3] + * ` Output: -1 + * ` Explanation: + * ` You can't start at station 0 or 1, as there is not enough gas to travel to the next station. + * ` Let's start at station 2 and fill up with 4 unit of gas. + * ` Your tank = 0 + 4 = 4 Travel to station 0. + * ` Your tank = 4 - 3 + 2 = 3 Travel to station 1. + * ` Your tank = 3 - 3 + 3 = 3 You cannot travel back to station 2, as it requires 4 unit of gas but you + * only have 3. + * ` Therefore, you can't travel around the circuit once no matter where you start. + * @Version: 1.0 + */ +public class _134_gas_station { + + public static void main(String[] args) { + + int[] gas = {1, 2, 3, 4, 5}; + int[] cost = {3, 4, 5, 1, 2}; + System.out.println(canCompleteCircuit(gas, cost)); + } + + public static int canCompleteCircuit(int[] gas, int[] cost) { + int total = 0; + + for (int i = 0; i < gas.length; i++) { + total += gas[i] - cost[i]; + } + if (total < 0) { + return -1; + } + + for (int i = 0; i < gas.length; i++) { + if (canDoIt(gas, cost, i)) { + return i; + } + } + return -1; + } + + private static boolean canDoIt(int[] gas, int[] cost, int start) { + int g = 0; + for (int j = 0; j < gas.length; j++) { + int position = (j + start) % gas.length; + g += gas[position] - cost[position]; + if (g < 0) { + return false; + } + } + return true; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_138_copy_list_with_random_pointer.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_138_copy_list_with_random_pointer.java new file mode 100644 index 0000000..fc1e0c9 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_138_copy_list_with_random_pointer.java @@ -0,0 +1,52 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Author: rtliu + * @Date: 2020/8/4 上午11:30 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: https://leetcode.com/problems/copy-list-with-random-pointer/ + * @Version: 1.0 + */ +public class _138_copy_list_with_random_pointer { + public RandomListNode copyRandomList(RandomListNode head) { + + if (head == null) { + return null; + } + Map map = new HashMap<>(); + + + + RandomListNode node = head; + while(node !=null){ + map.put(node,new RandomListNode(node.val)); + node = node.next; + } + + node = head; + + while(node != null){ + map.get(node).next = map.get(node.next); + map.get(node).random = map.get(node.random); + node = node.next; + } + + return map.get(head); + } +} + + +class RandomListNode { + int val; + RandomListNode next; + RandomListNode random; + + public RandomListNode(int val) { + this.val = val; + this.next = null; + this.random = null; + } +} \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_15_3nums.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_15_3nums.java new file mode 100644 index 0000000..7ee25d1 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_15_3nums.java @@ -0,0 +1,67 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + + +/** + * 题目: 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 + * 注意:答案中不可以包含重复的三元组。 + *

+ * 实例: 给定数组 nums = [-1, 0, 1, 2, -1, -4], + * 满足要求的三元组集合为: + * [ + * [-1, 0, 1], + * [-1, -1, 2] + * ] + *

+ *

+ * 思路:1、将数字从大到小排好序 + * 2、然后设置两个游标(left,right),只要满足 0-第三个数 == nums[left]-nums[right], + * 所以设置 sum=0-第三个数,只要找满足 nums[left]-nums[right] ==sum 即可。 + * 3、一个从左往右找,一个从右往左找 + * 4、如果两数之和大于sun,那么说明要找的数字更小,就把右边的游标往左移 + * 反之,左边的往右移 + */ +public class _15_3nums { + + public List> threeSum(int[] nums) { + if (nums.length < 3) { + return new LinkedList<>(); + } + Arrays.sort(nums); + List> list = new LinkedList<>(); + for (int i = 0; i < nums.length - 1; i++) { + // 避免添加相同的list + if (i == 0 || nums[i] != nums[i - 1]) { + int left = i + 1, right = nums.length - 1, sum = -nums[i]; + while (left < right) { + if (nums[left] + nums[right] == sum) { + // 添加进列表 + list.add(Arrays.asList(nums[left], nums[right], nums[i])); + // 避免添加相同的list + while (left < right && nums[left] == nums[left + 1]) { + left++; + } + while (left < right && nums[right] == nums[right - 1]) { + right--; + } + left++; + right--; + + //说明要找的数更大 + } else if (nums[left] + nums[right] < sum) { + left++; + } else { + //说明要找的数更小 + right--; + } + } + + } + } + return list; + + } +} \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_16_3num_closest.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_16_3num_closest.java new file mode 100644 index 0000000..3237510 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_16_3num_closest.java @@ -0,0 +1,61 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.Arrays; + +/** + * @Author: rtliu + * @Date: 2020/7/6 上午10:51 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: ` Given an array nums of n integers and an integer target, + * ` find three integers in nums such that the sum is closest to target. + * ` Return the sum of the three integers. + * ` You may assume that each input would have exactly one solution. + * ` Example 1: + * ` Input: + * ` nums = [-1,2,1,-4], target = 1 + * ` Output: 2 + * ` Explanation: + * ` The sum that is closest to the target is 2. (-1 + 2 + 1 = 2). + * @Version: 1.0 + */ +public class _16_3num_closest { + public static void main(String[] args) { + + int[] ints = {1, 2, 4, 8, 16, 32, 64, 128}; + System.out.println(threeSumClosest(ints, 82)); + } + + /** + * 时间复杂度O(n²) + * 设置两个游标,然后进行遍历 + * + * @param nums + * @param target + * @return + */ + public static int threeSumClosest(int[] nums, int target) { + int result = nums[0] + nums[1] + nums[nums.length - 1]; + int sum; + // 先对大小进行排序 + Arrays.sort(nums); + for (int i = 0; i < nums.length; i++) { + + // start 可以跳过之前的。因为之前的已经比较过 + int start = i + 1, end = nums.length - 1; + + while (start < end) { + sum = nums[i] + nums[start] + nums[end]; + + if (sum > target) { + end--; + } else { + start++; + } + if (Math.abs(result - target) > Math.abs(sum - target)) { + result = sum; + } + } + } + return result; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_17_letter_combinations_of_a_phone_number.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_17_letter_combinations_of_a_phone_number.java new file mode 100644 index 0000000..43dfc7f --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_17_letter_combinations_of_a_phone_number.java @@ -0,0 +1,65 @@ +package com.leosanqing.leetcode.medium.array; + +import com.alibaba.fastjson.JSON; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/6 上午11:22 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: ` ` Given a string containing digits from 2-9 inclusive, + * ` ` return all possible letter combinations that the number could represent. + * ` ` A mapping of digit to letters (just like on the telephone buttons) is given below. + * ` ` Note that 1 does not map to any letters. + * ` ` Example: + * ` ` Input: '23' + * ` ` Output: ['ad', 'ae', 'af', 'bd', 'be', 'bf', 'cd', 'ce', 'cf']. + * @Version: 1.0 + */ +public class _17_letter_combinations_of_a_phone_number { + + static char[][] num = { + {}, + {}, + {'a', 'b', 'c'}, + {'d', 'e', 'f'}, + {'g', 'h', 'i'}, + {'j', 'k', 'l'}, + {'m', 'n', 'o'}, + {'p', 'q', 'r', 's'}, + {'t', 'u', 'v'}, + {'w', 'x', 'y', 'z'} + }; + + public static void main(String[] args) { + System.out.println(JSON.toJSONString(letterCombinations("5465768"))); + } + + public static List letterCombinations(String digits) { + if (digits.length() == 0) { + return new ArrayList<>(); + } + + + List answer = new ArrayList<>(); + + backtrace(answer, 0, new StringBuilder(), digits); + + return answer; + } + + private static void backtrace(List answer, int position, StringBuilder sb, String digits) { + if (sb.length() == digits.length()) { + answer.add(new String(sb)); + return; + } + + for (int j = 0; j < num[digits.charAt(position) - '0'].length; j++) { + sb.append(num[digits.charAt(position) - '0'][j]); + backtrace(answer, position + 1, sb, digits); + sb.deleteCharAt(sb.length() - 1); + } + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_207_courseSchedule.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_207_courseSchedule.java new file mode 100644 index 0000000..706a577 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_207_courseSchedule.java @@ -0,0 +1,85 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * @Author: rtliu + * @Date: 2020/6/17 下午3:57 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: There are a total of numCourses courses you have to take, labeled from 0 to numCourses-1. + * Some courses may have prerequisites, for example to take course 0 you have to first take course 1, + * which is expressed as a pair: [0,1] + * Given the total number of courses and a list of prerequisite pairs, + * is it possible for you to finish all courses? + *

+ * 您必须参加总共numCourses课程,从0到numCourses-1标记。 + * 有些课程可能有先决条件,例如,要参加课程0,您必须先参加课程1,表示为一对:[0,1] + * 鉴于课程总数和先决条件对列表,您是否可以完成所有课程? + *

+ *

+ * Input: numCourses = 2, prerequisites = [[1,0]] + * Output: true + * Explanation: There are a total of 2 courses to take. + * To take course 1 you should have finished course 0. So it is possible. + * @Version: 1.0 + */ +public class _207_courseSchedule { + + public static void main(String[] args) { + int[][] courses = { + {0, 1}, + {1, 2}, + {2, 3}, + {5, 3}, + {4, 2} + }; + + System.out.println(canFinish(6, courses)); + + + } + + public static boolean canFinish(int numCourses, int[][] prerequisites) { + if (numCourses <= 0) { + return false; + } + Queue queue = new LinkedList<>(); + int[] inDegree = new int[numCourses]; + // 因为依赖的课程在第二个位置,所以可以查看有多少个课程依赖了这个课程 + for (int[] prerequisite : prerequisites) { + inDegree[prerequisite[1]]++; + } + + // 把最基础的课程(没有其他依赖的)加入队列 + for (int i = 0; i < inDegree.length; i++) { + if (inDegree[i] == 0) { + queue.offer(i); + } + } + while (!queue.isEmpty()) { + int x = queue.poll(); + for (int[] prerequisite : prerequisites) { + if (x == prerequisite[0]) { + inDegree[prerequisite[1]]--; + // 如果没有课程依赖了,那么这个课程就要被放入之前的队列中,再次循环 + if (inDegree[prerequisite[1]] == 0) { + queue.offer(prerequisite[1]); + } + } + } + } + + // 如果有一个不是0,那么就说明他没有上完 + for (int value : inDegree) { + if (value != 0) { + return false; + } + } + return true; + } + + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_209_minimumSizeSubarraySum.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_209_minimumSizeSubarraySum.java new file mode 100644 index 0000000..16dd77f --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_209_minimumSizeSubarraySum.java @@ -0,0 +1,62 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/6/17 下午2:38 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: + * Given an array of n positive integers and a positive integer s, + * find the minimal length of a contiguous subarray of which the sum ≥ s. + * If there isn't one, return 0 instead. + * + * 给定一个只有正整数的数组和一个正整数 s + * 返回 子数组之和大于 s 的长度 + * 如果没有,则返回 0 + * + * + * Example: + * + * Input: s = 7, nums = [2,3,1,2,4,3] + * Output: 2 + * Explanation: the subarray [4,3] has the minimal length under the problem constraint. + * + * + * + * @Version: 1.0 + */ +public class _209_minimumSizeSubarraySum { + + public static void main(String[] args) { + int a[] = {2,3,1,2,4,3}; + System.out.println(minSubArrayLen(7,a)); + } + + /** + * 使用滑动窗口,设置两个指针 i 和 j 充当窗口的界限 + * @param s + * @param a + * @return + */ + public static int minSubArrayLen(int s, int[] a) { + if (a == null || a.length == 0) { + return 0; + } + int i = 0, j = 0, sum = 0; + int min = Integer.MAX_VALUE; + + // 在数组范围内 + while (j < a.length) { + + sum += a[j++]; + // 如果和大于 s,就从前开始挨个减去 + while (sum >= s) { + min = Math.min(min, j - i); + sum -= a[i++]; + } + } + + return min == Integer.MAX_VALUE ? 0 : min; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_210_courseScheduleII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_210_courseScheduleII.java new file mode 100644 index 0000000..9c46f11 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_210_courseScheduleII.java @@ -0,0 +1,99 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.*; + +/** + * @Author: rtliu + * @Date: 2020/6/22 下午4:13 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: There are a total of n courses you have to take, labeled from 0 to n-1. Some courses may have + * prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1] + * Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take + * to finish all courses. There may be multiple correct orders, you just need to return one of them. If it is + * impossible to finish all courses, return an empty array. + * @Version: 1.0 + *

+ *

+ *

+ *

+ * Example 1: + *

+ * Input: 2, [[1,0]] + * Output: [0,1] + * Explanation: There are a total of 2 courses to take. To take course 1 you should have finished + * course 0. So the correct course order is [0,1] . + * Example 2: + *

+ * Input: 4, [[1,0],[2,0],[3,1],[3,2]] + * Output: [0,1,2,3] or [0,2,1,3] + * Explanation: There are a total of 4 courses to take. To take course 3 you should have finished both + * courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. + * So one correct course order is [0,1,2,3]. Another correct ordering is [0,2,1,3] . + */ +public class _210_courseScheduleII { + + public static void main(String[] args) { + int[][] courses = { + {0, 1}, + {1, 2}, + {2, 3}, + {5, 3}, + {4, 2} + }; + + canFinish(6, courses); + + } + + + public static int[] canFinish(int numCourses, int[][] prerequisites) { + + + int[] answer = new int[numCourses]; + int cur = numCourses - 1; + + + if (numCourses <= 0) { + return new int[]{}; + } + + Queue queue = new LinkedList<>(); + int[] inDegree = new int[numCourses]; + // 因为依赖的课程在第二个位置,所以可以查看有多少个课程依赖了这个课程 + for (int[] prerequisite : prerequisites) { + inDegree[prerequisite[1]]++; + } + + // 把最基础的课程(没有其他依赖的)加入队列 + for (int i = 0; i < inDegree.length; i++) { + if (inDegree[i] == 0) { + queue.offer(i); + answer[cur--] = i; + + } + } + + while (!queue.isEmpty()) { + int x = queue.poll(); + for (int[] prerequisite : prerequisites) { + if (x == prerequisite[0]) { + inDegree[prerequisite[1]]--; + // 如果没有课程依赖了,那么这个课程就要被放入之前的队列中,再次循环 + if (inDegree[prerequisite[1]] == 0) { + queue.offer(prerequisite[1]); + answer[cur--] = prerequisite[1]; + } + } + } + } + + // 如果有一个不是0,那么就说明他没有上完 + for (int value : inDegree) { + if (value != 0) { + return new int[]{}; + } + } + + return answer; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_213_houseRobberII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_213_houseRobberII.java new file mode 100644 index 0000000..1c08918 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_213_houseRobberII.java @@ -0,0 +1,65 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/2 下午2:20 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: + *` You are a professional robber planning to rob houses along a street. + *` Each house has a certain amount of money stashed. + *` All houses at this place are arranged in a circle. + *` That means the first house is the neighbor of the last one. + *` Meanwhile, adjacent houses have security system connected + *` and it will automatically contact the police if two adjacent houses were broken into on the same night. + *` Given a list of non-negative integers representing the amount of money of each house, + *` determine the maximum amount of money you can rob tonight without alerting the police. + * + *` Example 1: + *` Input: [2,3,2] + *` Output: 3 + *` Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2), + *` because they are adjacent houses. + * + *` Example 2: + *` Input: [1,2,3,1] + *` Output: 4 Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3). + *` Total amount you can rob = 1 + 3 = 4. + * @Version: 1.0 + */ +public class _213_houseRobberII { + + public static void main(String[] args) { + _213_houseRobberII houseRobberII = new _213_houseRobberII(); + + System.out.println(houseRobberII.rob(new int[]{1,5,4,1,8,7,5,14,8,4})); + } + public int rob(int[] nums) { + if (nums.length == 1) { + return nums[0]; + } + return Math.max(rob0(nums), rob1(nums)); + } + + public int rob0(int[] nums){ + int preMax = 0, curMax = 0; + for(int i = 0; i < nums.length - 1; i++){ + int t = curMax; + curMax = Math.max(preMax + nums[i], curMax); + preMax = t; + } + return curMax; + } + + public int rob1(int[] nums){ + int preMax = 0, curMax = 0; + for(int i = 1; i < nums.length; i++){ + int t = curMax; + curMax = Math.max(preMax + nums[i], curMax); + preMax = t; + } + return curMax; + } + +} + + diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_240_search_a_2D_matrixII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_240_search_a_2D_matrixII.java new file mode 100644 index 0000000..ae3d031 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_240_search_a_2D_matrixII.java @@ -0,0 +1,75 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/20 下午4:12 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` Write an efficient algorithm that searches for a value in an m x n matrix. + * ` This matrix has the following properties: + * ` Integers in each row are sorted in ascending from left to right. + * ` Integers in each column are sorted in ascending from top to bottom. + * ` Example: + * ` Consider the following matrix: + * ` [ + * ` [1, 4, 7, 11, 15], + * ` [2, 5, 8, 12, 19], + * ` [3, 6, 9, 16, 22], + * ` [10, 13, 14, 17, 24], + * ` [18, 21, 23, 26, 30] + * ` ] + * ` Given target = 5, return true. + * ` + * ` Given target = 20, return false. + * @Version: 1.0 + */ +public class _240_search_a_2D_matrixII { + + public static void main(String[] args) { + + int[][] nums = { + {1, 5, 7, 9}, + {1, 4, 7, 11, 15}, + {2, 5, 8, 12, 19}, + {3, 6, 9, 16, 22}, + {10, 13, 14, 17, 24}, + {18, 21, 23, 26, 30} + + }; + + System.out.println(searchMatrix(nums,17)); +} + + /** + * 这个题和 74题 很像。只不过这个下面一行不一定大于上面一行的任何一个数 + * 我们从右上角开始,因为这个是行中最大的,列中最小的 + * @param matrix + * @param target + * @return + */ + public static boolean searchMatrix(int[][] matrix, int target) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + return false; + } + if (matrix[0][0] > target || matrix[matrix.length - 1][matrix[0].length - 1] < target) { + return false; + } + + int row = 0; + int column = matrix[0].length - 1; + + int num; + while (row < matrix.length && column >= 0) { + num = matrix[row][column]; + if (num == target) { + return true; + } + if (num < target) { + row++; + } else { + column--; + } + } + return false; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_33_search_in_rotated_sorted_array.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_33_search_in_rotated_sorted_array.java new file mode 100644 index 0000000..6f5fef4 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_33_search_in_rotated_sorted_array.java @@ -0,0 +1,111 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/9 下午1:58 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: ` Suppose an array sorted in ascending order is rotated at some pivot unknown to you + * beforehand. + * ` (i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]). + * ` You are given a target value to search. + * ` If found in the array return its index, otherwise return -1. + * ` You may assume no duplicate exists in the array. + * ` Your algorithm's runtime complexity must be in the order of O(log n). + *

+ *

+ * ` 假设以升序排序的数组以您不知道的某个枢轴旋转。 + * ` (即[0,1,2,4,5,6,7]可能会变成[4,5,6,7,0,1,2])。 + * ` 为您提供了要搜索的目标值。 + * ` 如果在数组中找到,则返回其索引,否则返回-1。 + * ` 您可以假设数组中不存在重复项。 + * ` 算法的运行时复杂度必须为O(log n)的数量级。 + * ` + * ` Example 1: + * ` Input: nums = [4,5,6,7,0,1,2], target = 0 + * ` Output: 4 + * ` + * ` Example 2: + * ` Input: nums = [4,5,6,7,0,1,2], target = 3 + * ` Output: -1 + * @Version: 1.0 + */ +public class _33_search_in_rotated_sorted_array { + + public static void main(String[] args) { + int[] nums = new int[]{4, 5, 6, 7, 0, 1, 2}; + System.out.println(search2(nums, 0)); + } + + /** + * 虽然他不是全部从小到大排序,我们不能用二分法 + * 但是他有两个部分,两个都是从小到大排序 + * + * @param nums + * @param target + * @return + */ + public static int search(int[] nums, int target) { + if (nums == null || nums.length == 0) { + return -1; + } + + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + + if (target == nums[mid]) { + return mid; + } + + // 5,7,8,0,1,2,3,4 + if (nums[left] > nums[mid]) { + // target = 7 + if (target < nums[mid] || nums[left] <= target) { + right = mid - 1; + } else { + // target = 2 + left = mid + 1; + } + } else { + if (target > nums[mid] || target < nums[left]) { + left = mid + 1; + } else { + right = mid - 1; + } + } + } + + return -1; + } + + + private static int search2(int[] nums, int target) { + if (nums == null || nums.length == 0 || (nums.length == 1 && nums[0] != target)) { + return -1; + } + int left = 0, right = nums.length - 1; + + while (left < right) { + int mid = left + (right - left) / 2; + + // 说明 mid 和 target 在同一侧 + if ((nums[mid] - nums[nums.length - 1]) * (target - nums[nums.length - 1]) > 0) { + if (target > nums[mid]) { + left = mid + 1; + } else { + right = mid; + } + } else if (target - nums[nums.length - 1] > 0) { + // target 在左侧 + right = mid; + } else { + left = mid + 1; + } + } + if (nums[left] == target) { + return left; + } + + return -1; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_36_valid_sudoku.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_36_valid_sudoku.java new file mode 100644 index 0000000..c473d55 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_36_valid_sudoku.java @@ -0,0 +1,84 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.HashSet; +import java.util.Set; + +/** + * @Author: rtliu + * @Date: 2020/7/13 上午11:46 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: ` ` Determine if a 9x9 Sudoku board is valid. + * ` ` Only the filled cells need to be validated according to the following rules: + * ` ` 1. Each row must contain the digits 1-9 without repetition. + * ` ` 2. Each column must contain the digits 1-9 without repetition. + * ` ` 3. Each of the 9 3x3 sub-boxes of the grid must contain the digits 1-9 without repetition. + * 1` + * 1` + * 1` 确定9x9数独板是否有效。 + * 1` 仅需根据以下规则验证填充的单元格: + * 1` 1.每行必须包含数字1-9,不能重复。 + * 1` 2.每列必须包含数字1-9,且不能重复。 + * 1` 3.网格的9个3x3子框中的每个必须包含数字1-9(无重复)。 + * + *

+ * ` Example 1: + *

+ * ` Input: + * ` [ + * ` ["5","3",".",".","7",".",".",".","."], + * ` ["6",".",".","1","9","5",".",".","."], + * ` [".","9","8",".",".",".",".","6","."], + * ` ["8",".",".",".","6",".",".",".","3"], + * ` ["4",".",".","8",".","3",".",".","1"], + * ` ["7",".",".",".","2",".",".",".","6"], + * ` [".","6",".",".",".",".","2","8","."], + * ` [".",".",".","4","1","9",".",".","5"], + * ` [".",".",".",".","8",".",".","7","9"] + * ` ] + * ` Output: true + * ` Example 2: + *

+ * ` Input: + * ` [ + * ` ["8","3",".",".","7",".",".",".","."], + * ` ["6",".",".","1","9","5",".",".","."], + * ` [".","9","8",".",".",".",".","6","."], + * ` ["8",".",".",".","6",".",".",".","3"], + * ` ["4",".",".","8",".","3",".",".","1"], + * ` ["7",".",".",".","2",".",".",".","6"], + * ` [".","6",".",".",".",".","2","8","."], + * ` [".",".",".","4","1","9",".",".","5"], + * ` [".",".",".",".","8",".",".","7","9"] + * ` ] + * ` Output: false + * ` Explanation: Same as Example 1, except with the 5 in the top left corner being + * ` modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid. + * ` Note: + *

+ * ` A Sudoku board (partially filled) could be valid but is not necessarily solvable. + * ` Only the filled cells need to be validated according to the mentioned rules. + * ` The given board contain only digits 1-9 and the character '.'. + * ` The given board size is always 9x9. + * @Version: 1.0 + */ +public class _36_valid_sudoku { + public boolean isValidSudoku(char[][] board) { + + Set set = new HashSet<>(); + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board.length; j++) { + char c = board[i][j]; + if (c != '.') { + if (!set.add(c + "in row" + i) || + !set.add(c + "in column" + j) || + !set.add(c + "in block" + i / 3 + "-" + j/3) + ){ + return false; + } + } + } + } + + return true; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_39_combination_sum.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_39_combination_sum.java new file mode 100644 index 0000000..f8d1d5b --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_39_combination_sum.java @@ -0,0 +1,73 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/13 下午2:29 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), + * find all unique combinations in candidates where the candidate numbers sums to target. + * The same repeated number may be chosen from candidates unlimited number of times. + *

+ *

+ * 给定一组候选编号(候选)(无重复)和目标编号(target), + * 在候选人编号总和为目标的候选人中找到所有唯一组合。 + * 可以从候选人无限制的次数中选择相同的重复号码。 + * ` Note: + * ` All numbers (including target) will be positive integers. + * ` The solution set must not contain duplicate combinations. + * ` Example 1: + * ` Input: candidates = [2,3,6,7], target = 7, + * ` A solution set is: [ [7], [2,2,3] ] + * ` Example 2: + * ` Input: candidates = [2,3,5], target = 8, + * ` A solution set is: [ [2,2,2,2], [2,3,3], [3,5] ] + * @Version: 1.0 + */ +public class _39_combination_sum { + + public static void main(String[] args) { + int[] nums = {2, 3, 6, 7}; + + combinationSum(nums, 7); + + } + + /** + * 这种的做多了,就会发现基本都是一个套路,递归调用 + * + * @param candidates + * @param target + * @return + */ + public static List> combinationSum(int[] candidates, int target) { + List> answer = new ArrayList<>(); + + // 先排序 + Arrays.sort(candidates); + + backtrace(answer, candidates, target, new ArrayList<>(), 0); + + return answer; + } + + private static void backtrace(List> answer, int[] candidates, int target, List list, int position) { + if (target < 0) { + return; + } + + if (target == 0) { + answer.add(new ArrayList<>(list)); + return; + } + + for (int i = position; i < candidates.length; i++) { + list.add(candidates[i]); + backtrace(answer, candidates, target - candidates[i], list, i); + list.remove(list.size() - 1); + } + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_40_combination_sumII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_40_combination_sumII.java new file mode 100644 index 0000000..30ee10b --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_40_combination_sumII.java @@ -0,0 +1,72 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/13 下午4:04 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1` Given a collection of candidate numbers (candidates) and a target number (target), + * 1` find all unique combinations in candidates where the candidate numbers sums to target. + * 1` Each number in candidates may only be used once in the combination. + * 1` Note: + * 1` All numbers (including target) will be positive integers. + * 1` The solution set must not contain duplicate combinations. + *

+ *

+ * ` 给定一组候选编号(候选)和目标编号(target), + * ` 查找候选编号总和为目标的候选中的所有唯一组合。 + * ` 组合中的每个候选号码只能使用一次。 + * ` 注: + * ` 所有数字(包括目标)将为正整数。 + * ` 解决方案集不得包含重复的组合。 + *

+ * 1` Example 1: + * 1` Input: candidates = [10,1,2,7,6,1,5], target = 8, + * 1` A solution set is: [ [1, 7], [1, 2, 5], [2, 6], [1, 1, 6] ] + * 1` Example 2: + * 1` Input: candidates = [2,5,2,1,2], target = 5, + * 1` A solution set is: [ [1,2,2], [5] ] + * @Version: 1.0 + */ + +public class _40_combination_sumII { + + public static void main(String[] args) { + int[] nums = {10, 1, 2, 7, 6, 1, 5}; + combinationSum2(nums, 8); + } + + public static List> combinationSum2(int[] candidates, int target) { + + Arrays.sort(candidates); + + List> answer = new ArrayList<>(); + + backTrace(answer, new ArrayList<>(), candidates, target, 0); + return answer; + } + + private static void backTrace(List> answer, List list, int[] candidates, int remain, + int position) { + if (remain < 0) { + return; + } + if (remain == 0) { + answer.add(new ArrayList<>(list)); + return; + } + + for (int i = position; i < candidates.length; i++) { + // 去除重复 如 [1,1,2,3]. 去掉第2个1 的结果 + if (i > position && candidates[i] == candidates[i - 1]) { + continue; + } + list.add(candidates[i]); + backTrace(answer, list, candidates, remain - candidates[i], i + 1); + list.remove(list.size() - 1); + } + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_46_permutations.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_46_permutations.java new file mode 100644 index 0000000..de36af7 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_46_permutations.java @@ -0,0 +1,48 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/14 上午9:36 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` Given a collection of distinct integers, return all possible permutations. + * ` Example: + * ` Input: [1,2,3] + * ` Output: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] + * @Version: 1.0 + */ +public class _46_permutations { + + public static void main(String[] args) { + System.out.println(permute(new int[]{1, 2, 3})); + } + + public static List> permute(int[] nums) { + List> answer = new ArrayList<>(); + + backtrace(answer, nums, new ArrayList<>()); + return answer; + } + + + private static void backtrace(List> answer, int[] nums, List list) { + if (list.size() == nums.length) { + answer.add(new ArrayList<>(list)); + return; + } + + for (int num : nums) { + if (list.contains(num)) { + continue; + } + + list.add(num); + backtrace(answer, nums, list); + list.remove(list.size() - 1); + } + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_47_permutationsII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_47_permutationsII.java new file mode 100644 index 0000000..3236178 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_47_permutationsII.java @@ -0,0 +1,67 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/14 上午10:08 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` Given a collection of numbers that might contain duplicates, + * ` return all possible unique permutations. + * ` Example: + * ` Input: [1,1,2] + * ` Output: [ [1,1,2], [1,2,1], [2,1,1] ] + * @Version: 1.0 + */ +public class _47_permutationsII { + + public static void main(String[] args) { + System.out.println(permute(new int[]{1, 1, 3})); + + } + + public static List> permute(int[] nums) { + List> answer = new ArrayList<>(); + + if (nums == null || nums.length == 0) { + return answer; + } + Arrays.sort(nums); + boolean[] used = new boolean[nums.length]; + + backTrace(answer, new ArrayList<>(), nums, used); + return answer; + + } + + /** + * 递归遍历 + * + * @param answer + * @param list + * @param nums + */ + private static void backTrace(List> answer, List list, int[] nums, boolean[] used) { + if (list.size() == nums.length) { + answer.add(new ArrayList<>(list)); + return; + } + for (int i = 0; i < nums.length; i++) { + // 如果有这个数字,就跳过. 并且排除 相邻相同的数字两种情况。之前的排序就为了这个 + if (used[i] || (i > 0 && nums[i - 1] == nums[i] && !used[i - 1])) { + continue; + } + list.add(nums[i]); + used[i] = true; + backTrace(answer, list, nums, used); + list.remove(list.size() - 1); + used[i] = false; + + } + + + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_48_rotate_image.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_48_rotate_image.java new file mode 100644 index 0000000..807d56d --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_48_rotate_image.java @@ -0,0 +1,109 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/14 上午10:32 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * `` You are given an n x n 2D matrix representing an image. + * `` Rotate the image by 90 degrees (clockwise). + * `` Note: + * `` You have to rotate the image in-place, + * `` which means you have to modify the input 2D matrix directly. + * `` DO NOT allocate another 2D matrix and do the rotation. + * `` Example 1: + * `` Given input matrix = + * `` [ + * `` [1,2,3], + * `` [4,5,6], + * `` [7,8,9] + * `` ], + * `` rotate the input matrix in-place such that it becomes: + * `` [ + * `` [7,4,1], + * `` [8,5,2], + * `` [9,6,3] + * `` ] + * `` Example 2: + * `` Given input matrix = + * `` [ + * `` [ 5, 1, 9,11], + * `` [ 2, 4, 8,10], + * `` [13, 3, 6, 7], + * `` [15,14,12,16] + * `` ], + * `` rotate the input matrix in-place such that it becomes: + * `` [ + * `` [15,13, 2, 5], + * `` [14, 3, 4, 1], + * `` [12, 6, 8, 9], + * `` [16, 7,10,11] + * `` ] + * @Version: 1.0 + */ +public class _48_rotate_image { + public static void main(String[] args) { + + } + + + /** + * 分成两步进行旋转 + *

+ * 1 2 3 + * 4 5 6 + * 7 8 9 + *

+ * 1 4 7 + * 2 5 8 + * 3 6 9 + *

+ * 7 4 1 + * 8 5 2 + * 9 6 3 + * + * @param matrix + */ + public static void rotate(int[][] matrix) { + int temp; + + for (int i = 0; i < matrix.length; i++) { + for (int j = i; j < matrix[0].length; j++) { + temp = matrix[i][j]; + matrix[i][j] = matrix[j][i]; + matrix[j][i] = temp; + } + } + + for (int i = 0; i < matrix.length; i++) { + for (int j = 0; j < matrix.length / 2; j++) { + temp = matrix[i][j]; + matrix[i][j] = matrix[i][matrix.length - 1 - j]; + matrix[i][matrix.length - 1 - j] = temp; + } + } + } + + + public static void rotate1(int[][] matrix) { + int temp; + for (int i = 0; i < matrix.length; i++) { + for (int j = i; j < matrix[0].length; j++) { + if (i == j) { + continue; + } + temp = matrix[i][j]; + matrix[i][j] = matrix[j][i]; + matrix[j][i] = temp; + } + } + + for (int i = 0; i < matrix.length; i++) { + for (int j = 0; j < matrix[0].length / 2; j++) { + temp = matrix[i][j]; + matrix[i][j] = matrix[i][matrix[0].length - j - 1]; + matrix[i][matrix[0].length - j - 1] = temp; + } + } + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_49_group_anagrams.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_49_group_anagrams.java new file mode 100644 index 0000000..ef9489a --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_49_group_anagrams.java @@ -0,0 +1,54 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.*; + +/** + * @Author: rtliu + * @Date: 2020/7/14 下午2:18 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` ` Given an array of strings, group anagrams together. + * ` ` 给定一个字符串数组,将字谜分组在一起。 + * ` ` Example: + * ` ` Input: ["eat", "tea", "tan", "ate", "nat", "bat"], + * ` ` Output: + * ` ` [ + * ` ` ["ate","eat","tea"], + * ` ` ["nat","tan"], + * ` ` ["bat"] + * ` ` ] + * @Version: 1.0 + */ +public class _49_group_anagrams { + + public static void main(String[] args) { + String[] strings = {"eat", "tea", "tan", "ate", "nat", "bat"}; + System.out.println(groupAnagrams(strings)); + } + + public static List> groupAnagrams(String[] strs) { + List> answer = new ArrayList<>(); + + if (strs == null || strs.length == 0) { + return answer; + } + + Map> map = new HashMap<>(); + + for (String str : strs) { + char[] chars = new char[26]; + for (char c : str.toCharArray()) { + chars[c - 'a']++; + } + String s = Arrays.toString(chars); + + List list = map.getOrDefault(s, new ArrayList<>()); + list.add(str); + map.put(s, list); + + } + return new ArrayList<>(map.values()); + + + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_54_spiral_matrix.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_54_spiral_matrix.java new file mode 100644 index 0000000..4042a96 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_54_spiral_matrix.java @@ -0,0 +1,87 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/14 下午2:57 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` ` Given a matrix of m x n elements (m rows, n columns), + * ` ` return all elements of the matrix in spiral order. + * ` ` 给定一个由m x n个元素组成的矩阵(m行n列), + * ` ` 以螺旋顺序返回矩阵的所有元素。 + * ` ` Example 1: + * ` ` Input: + * ` ` [ + * ` ` [ 1, 2, 3 ], + * ` ` [ 4, 5, 6 ], + * ` ` [ 7, 8, 9 ] + * ` ` ] + * ` ` Output: [1,2,3,6,9,8,7,4,5] + * ` ` Example 2: + * ` ` Input: + * ` ` [ + * ` ` [1, 2, 3, 4], + * ` ` [5, 6, 7, 8], + * ` ` [9,10,11,12] + * ` ` ] + * ` ` Output: [1,2,3,4,8,12,11,10,9,5,6,7] + * @Version: 1.0 + */ +public class _54_spiral_matrix { + public static void main(String[] args) { + + int[][] ints = { + {1,2,3,4}, + {5,6,7,8}, + {9,10,11,12} + }; + + spiralOrder(ints); + } + + + public static List spiralOrder(int[][] matrix) { + List list = new ArrayList<>(); + + + if (matrix == null || matrix.length == 0) { + return list; + } + + int left = 0, top = 0, + right = matrix[0].length - 1, bottom = matrix.length - 1; + + + while (list.size() < matrix[0].length * matrix.length) { + for (int i = left; i <= right; i++) { + list.add(matrix[top][i]); + } + top++; + + for (int i = top; i <= bottom; i++) { + list.add(matrix[i][right]); + } + right--; + + for (int i = right; i >= left; i--) { + list.add(matrix[bottom][i]); + } + bottom--; + + for (int i = bottom; i >= top; i--){ + list.add(matrix[i][left]); + } + left++; + } + + while(list.size()!= matrix.length * matrix[0].length){ + list.remove(list.size()-1); + } + return list; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_55_jump_game.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_55_jump_game.java new file mode 100644 index 0000000..a274d72 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_55_jump_game.java @@ -0,0 +1,66 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/14 下午3:32 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` ` Given an array of non-negative integers, + * ` ` you are initially positioned at the first index of the array. + * ` ` Each element in the array represents your maximum jump length at that position. + * ` ` Determine if you are able to reach the last index. + * ` ` + * ` ` 给定一个非负整数数组, + * ` ` 您最初位于数组的第一个索引。 + * ` ` 数组中的每个元素代表该位置的最大跳转长度。 + * ` ` 确定您是否能够达到最后一个索引。 + * ` ` Example 1: + * ` ` Input: nums = [2,3,1,1,4] + * ` ` Output: true + * ` ` Explanation: + * ` ` Jump 1 step from index 0 to 1, then 3 steps to the last index. + * ` ` Example 2: + * ` ` Input: nums = [3,2,1,0,4] + * ` ` Output: false + * ` ` Explanation: + * ` ` You will always arrive at index 3 no matter what. + * ` ` Its maximum jump length is 0, which makes it impossible to reach the last index. + * @Version: 1.0 + */ +public class _55_jump_game { + public static void main(String[] args) { + System.out.println(canJump(new int[]{3, 2, 1, 1, 4})); + + System.out.println(canJump(new int[]{3, 2, 1, 0, 4})); + } + + + /** + * The basic idea is this: at each step, we keep track of the furthest reachable index. The nature of the problem + * (eg. maximal jumps where you can hit a range of targets instead of singular jumps where you can only hit one + * target) is that for an index to be reachable, each of the previous indices have to be reachable. + *

+ * Hence, it suffices that we iterate over each index, and If we ever encounter an index that is not reachable, + * we abort and return false. By the end, we will have iterated to the last index. If the loop finishes, then the + * last index is reachable. + *

+ * 基本思想是:在每个步骤中,我们都跟踪最远的可到达索引。 + * 问题的性质(例如,您可以击中一个目标范围的最大跳跃,而不是您只能击中一个目标的奇异跳跃)是要使一个索引可以到达,必须使每个先前的索引都可以到达。 + *

+ * 因此,我们迭代每个索引就足够了,如果遇到无法访问的索引,我们将中止并返回false。到最后,我们将迭代到最后一个索引。如果循环结束,则最后一个索引可达。 + * + * @param nums + * @return + */ + public static boolean canJump(int[] nums) { + int max = 0; + for (int i = 0; i < nums.length; i++) { + if (i > max) { + return false; + } + // 算出能到达的最远距离 + max = Math.max(max, i + nums[i]); + } + return true; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_56_merge_intervals.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_56_merge_intervals.java new file mode 100644 index 0000000..4343b06 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_56_merge_intervals.java @@ -0,0 +1,54 @@ +package com.leosanqing.leetcode.medium.array; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/14 下午4:23 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` Given a collection of intervals, merge all overlapping intervals. + * ` Example 1: + * ` Input: [[1,3],[2,6],[8,10],[15,18]] + * ` Output: [[1,6],[8,10],[15,18]] + * ` Explanation: + * ` Since intervals [1,3] and [2,6] overlaps, merge them into [1,6]. + * ` Example 2: + * ` Input: [[1,4],[4,5]] + * ` Output: [[1,5]] + * ` Explanation: Intervals [1,4] and [4,5] are considered overlapping. + * @Version: 1.0 + */ +public class _56_merge_intervals { + /** + * 先对给定的数组进行排列 + * @param intervals + * @return + */ + public static int[][] merge(int[][] intervals) { + // 先排序 + Arrays.sort(intervals, Comparator.comparingInt(i -> i[0])); + + List answer = new ArrayList<>(); + + for (int[] interval : intervals) { + int left = interval[0]; + int right = interval[1]; + + if (answer.isEmpty()) { + answer.add(new int[]{left, right}); + continue; + } + + if (answer.get(answer.size() - 1)[1] < left) { + answer.add(new int[]{left, right}); + } else { + answer.get(answer.size() - 1)[1] = Math.max(answer.get(answer.size() - 1)[1], right); + } + } + return answer.toArray(new int[answer.size()][]); + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_59_spiral_matrixII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_59_spiral_matrixII.java new file mode 100644 index 0000000..02f20af --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_59_spiral_matrixII.java @@ -0,0 +1,57 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/15 下午5:14 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` Given a positive integer n, + * ` generate a square matrix filled with elements from 1 to n2 in spiral order. + * ` Example: + * ` Input: 3 + * ` Output: + * ` [ + * ` [ 1, 2, 3 ], + * ` [ 8, 9, 4 ], + * ` [ 7, 6, 5 ] + * ` ] + * @Version: 1.0 + */ +public class _59_spiral_matrixII { + + public static void main(String[] args) { + System.out.println(generateMatrix(4)); + } + + public static int[][] generateMatrix(int n) { + if (n < 1) { + return new int[][]{}; + } + int[][] result = new int[n][n]; + int left = 0, right = n - 1, top = 0, bottom = n - 1; + int count = 1; + while (count <= n*n) { + for (int i = left; i <= right; i++, count++) { + result[top][i] = count; + } + top++; + + for (int i = top; i <= bottom; i++, count++) { + result[i][right] = count; + } + right--; + + for (int i = right; i >= left; i--, count++) { + result[bottom][i] = count; + } + bottom--; + + for (int i = bottom; i >= top; i--, count++) { + result[i][left] = count; + } + left++; + } + + return result; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_62_unique_paths.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_62_unique_paths.java new file mode 100644 index 0000000..b1dc68a --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_62_unique_paths.java @@ -0,0 +1,64 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/20 上午9:47 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). + * ` The robot can only move either down or right at any point in time. + * ` The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below). + * ` How many possible unique paths are there? + * ` Above is a 7 x 3 grid. How many possible unique paths are there? + * ` + * ` 机器人位于m x n网格的左上角(在下图中标记为“开始”)。 + * ` 机器人只能在任何时间点上下移动。 + * ` 机器人试图到达网格的右下角(在下图中标记为“完成”)。 + * ` 有多少可能的唯一路径? + * ` 上面是7 x 3的网格。有多少种可能的独特路径? + * ` Example 1: + * ` Input: m = 3, n = 2 + * ` Output: 3 + * ` Explanation: + * ` From the top-left corner, there are a total of 3 ways to reach the bottom-right corner: + * ` 1. Right -> Right -> Down + * ` 2. Right -> Down -> Right + * ` 3. Down -> Right -> Right + * ` Example 2: + * ` Input: m = 7, n = 3 + * ` Output: 28 + * @Version: 1.0 + */ +public class _62_unique_paths { + public static void main(String[] args) { + System.out.println(uniquePaths(3, 3)); + System.out.println(uniquePaths(3, 7)); + } + + /** + * 使用动态规划,机器人只能向下或者向右,所以当前到当前坐标的可能性就是 上边坐标的可能性加上左边坐标的可能性 + * + * @param m + * @param n + * @return + */ + public static int uniquePaths(int m, int n) { + int[] pre = new int[m]; + int[] cur = new int[m]; + + for (int i = 0; i < m; i++) { + cur[i] = 1; + pre[i] = 1; + } + + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + cur[j] = cur[j - 1] + pre[j]; + } + pre = cur; + } + + return cur[m - 1]; + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_63_unique_pathsII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_63_unique_pathsII.java new file mode 100644 index 0000000..56838ea --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_63_unique_pathsII.java @@ -0,0 +1,87 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/20 上午10:12 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). + * ` The robot can only move either down or right at any point in time. + * ` The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below). + * ` Now consider if some obstacles are added to the grids. How many unique paths would there be? + * ` An obstacle and empty space is marked as 1 and 0 respectively in the grid. + * ` + * ` Note: m and n will be at most 100. + * ` Example 1: + * ` Input: + * ` [ + * ` [0,0,0], + * ` [0,1,0], + * ` [0,0,0] + * ` ] + * ` Output: 2 + * ` Explanation: + * ` There is one obstacle in the middle of the 3x3 grid above. + * ` There are two ways to reach the bottom-right corner: + * ` 1. Right -> Right -> Down -> Down + * ` 2. Down -> Down -> Right -> Right + * @Version: 1.0 + */ +public class _63_unique_pathsII { + public static void main(String[] args) { + int[][] obstacleGrid = new int[][]{ + {0, 0, 0}, + {0, 1, 0}, + {0, 0, 0,} + }; + System.out.println(uniquePathsWithObstacles(obstacleGrid)); + } + + /** + * 思路和 62题 很像,只不过做些特殊处理 + * + * @param obstacleGrid + * @return + */ + public static int uniquePathsWithObstacles(int[][] obstacleGrid) { + if (obstacleGrid == null || obstacleGrid.length == 0 || obstacleGrid[0].length == 0) { + return 0; + } + + int rows = obstacleGrid.length; + int columns = obstacleGrid[0].length; + + int[] pre = new int[columns]; + int[] cur = new int[columns]; + // 先设置第一行 + for (int i = 0; i < columns; i++) { + if (obstacleGrid[0][0] == 1) { + return 0; + } + + if (obstacleGrid[0][i] == 1) { + break; + } + pre[i] = 1; + cur[i] = 1; + } + + // 处理第二行之后的 + for (int i = 1; i < rows; i++) { + for (int j = 0; j < columns; j++) { + // 处理 障碍物 + if (obstacleGrid[i][j] == 1) { + cur[j] = 0; + continue; + } + if (j != 0) { + cur[j] = cur[j - 1] + pre[j]; + } + } + + pre = cur; + } + + return cur[columns - 1]; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_64_minimum_path_sum.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_64_minimum_path_sum.java new file mode 100644 index 0000000..d57c29a --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_64_minimum_path_sum.java @@ -0,0 +1,55 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/16 下午4:50 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` Given a m x n grid filled with non-negative numbers, + * ` find a path from top left to bottom right which minimizes the sum of all numbers along its path. + * ` Note: + * ` You can only move either down or right at any point in time. + * ` Example: + * ` Input: + * ` [ + * ` [1,3,1], + * ` [1,5,1], + * ` [4,2,1] + * ` ] + * ` Output: 7 + * ` Explanation: Because the path 1→3→1→1→1 minimizes the sum. + * @Version: 1.0 + */ +public class _64_minimum_path_sum { + public static void main(String[] args) { + int[][] ints = { + {1, 3, 1, 1}, + {1, 5, 12, 1}, + {4, 2, 10, 2}, + {1, 1, 1, 10} + }; + + System.out.println(minPathSum(ints)); + } + + + private static int minPathSum(int[][] grid) { + for (int i = 1; i < grid.length; i++) { + grid[i][0] += grid[i - 1][0]; + } + + for (int i = 1; i < grid[0].length; i++) { + grid[0][i] += grid[0][i - 1]; + } + + for (int i = 1; i < grid.length; i++) { + for (int j = 1; j < grid[0].length; j++) { + grid[i][j] += Math.min(grid[i - 1][j], grid[i][j - 1]); + } + } + + return grid[grid.length - 1][grid[0].length - 1]; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_73_set_matrix_zeroes.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_73_set_matrix_zeroes.java new file mode 100644 index 0000000..8f239d6 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_73_set_matrix_zeroes.java @@ -0,0 +1,75 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/20 上午11:22 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + *` ` Given a m x n matrix, if an element is 0, set its entire row and column to 0. + *` ` Do it in-place. + *` ` Example 1: + *` ` Input: + *` ` [ + *` ` [1,1,1], + *` ` [1,0,1], + *` ` [1,1,1] + *` ` ] + *` ` Output: + *` ` [ + *` ` [1,0,1], + *` ` [0,0,0], + *` ` [1,0,1] + *` ` ] + *` ` Example 2: + *` ` Input: + *` ` [ + *` ` [0,1,2,0], + *` ` [3,4,5,2], + *` ` [1,3,1,5] + *` ` ] + *` ` Output: + *` ` [ + *` ` [0,0,0,0], + *` ` [0,4,5,0], + *` ` [0,3,1,0] + *` ` ] + * @Version: 1.0 + */ +public class _73_set_matrix_zeroes { + public static void main(String[] args) { + int[][] matrix = new int[][]{ + {1,1,1}, + {1,0,1}, + {1,1,1} + }; + setZeroes(matrix); + } + public static void setZeroes(int[][] matrix) { + if (matrix == null) { + return; + } + boolean row[] = new boolean[matrix.length]; + boolean column[] = new boolean[matrix[0].length]; + for (int i = 0; i < matrix.length; i++) { + for (int j = 0; j < matrix[0].length; j++) { + if(matrix[i][j] == 0){ + row[i] = true; + column[j] = true; + } + } + } + + for (int i = 0; i < matrix.length; i++) { + for (int j = 0; j < matrix[0].length; j++) { + if(row[i]){ + matrix[i][j] = 0; + } + if(column[j]){ + matrix[i][j] = 0; + } + } + } + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_74_search_a_2D_matrix.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_74_search_a_2D_matrix.java new file mode 100644 index 0000000..a73150e --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_74_search_a_2D_matrix.java @@ -0,0 +1,95 @@ +package com.leosanqing.leetcode.medium.array; + +import java.math.BigDecimal; +import java.math.BigInteger; + +/** + * @Author: rtliu + * @Date: 2020/7/20 下午2:40 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` Write an efficient algorithm that searches for a value in an m x n matrix. + * ` This matrix has the following properties: + * ` Integers in each row are sorted from left to right. + * ` The first integer of each row is greater than the last integer of the previous row. + * ` + * ` 编写一种有效的算法,在m x n矩阵中搜索值。 + * ` 该矩阵具有以下属性: + * ` 每行中的整数从左到右排序。 + * ` 每行的第一个整数大于前一行的最后一个整数。 + * ` Example 1: + * ` Input: matrix = + * ` [ + * ` [1, 3, 5, 7], + * ` [10, 11, 16, 20], + * ` [23, 30, 34, 50] + * ` ] + * ` target = 3 + * ` Output: true + * ` Example 2: + * ` Input: + * ` matrix = [ + * ` [1, 3, 5, 7], + * ` [10, 11, 16, 20], + * ` [23, 30, 34, 50] + * ` ] target = 13 + * ` Output: false + * @Version: 1.0 + */ +public class _74_search_a_2D_matrix { + public static void main(String[] args) { + int[][] ints = { + {1, 3, 5, 7}, + {10, 11, 16, 21}, + {22, 25, 27, 30}, + {35, 44, 56, 70} + }; + + int[][] nums = {{1,3}}; + System.out.println(searchMatrix(nums,2)); + + System.out.println(searchMatrix(ints, 1)); + System.out.println(searchMatrix(ints, 16)); + System.out.println(searchMatrix(ints, 27)); + System.out.println(searchMatrix(ints, 44)); + + } + + /** + * 把它不当成矩阵,当成一个排好序的列表 + * @param matrix + * @param target + * @return + */ + public static boolean searchMatrix(int[][] matrix, int target) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + return false; + } + + int m = matrix.length; + int n = matrix[0].length; + if (matrix[0][0] > target || matrix[m - 1][n - 1] < target) { + return false; + } + + int start = 0; + int end = m * n - 1; + int mid = (end - start) / 2 + start; + int num = Integer.MIN_VALUE; + while (start <= end) { + num = matrix[mid / n][mid % n]; + if (num == target) { + return true; + } + + if (num < target) { + start = mid + 1; + } else { + end = mid - 1; + } + mid = (end - start) / 2 + start; + } + + return false; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_75_sort_colors.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_75_sort_colors.java new file mode 100644 index 0000000..4a90260 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_75_sort_colors.java @@ -0,0 +1,70 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/20 下午7:21 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` Given an array with n objects colored red, white or blue, + * ` sort them in-place so that objects of the same color are adjacent, + * ` with the colors in the order red, white and blue. + * ` Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively. + * ` Note: You are not suppose to use the library's sort function for this problem. + * ` Example: + * ` Input: [2,0,2,1,1,0] + * ` Output: [0,0,1,1,2,2] + * @Version: 1.0 + */ +public class _75_sort_colors { + public static void main(String[] args) { + sortColors(new int[]{2, 0, 2, 1, 1, 0}); + } + + public static void sortColors(int[] nums) { + int n2 = -1, n1 = -1, n0 = -1; + + for (int i = 0; i < nums.length; i++) { + if (nums[i] == 0) { + nums[++n2] = 2; + nums[++n1] = 1; + nums[++n0] = 0; + } else if (nums[i] == 1) { + nums[++n2] = 2; + nums[++n1] = 1; + } else if (nums[i] == 2) { + nums[++n2] = 2; + } + + } + } + + + /** + * 使用两个指针,p1指向0,p2指向2 + * 然后遍历,找到0就和 P1上的数字交换,找到2就和p2上的数字交换 + * + * 但是这个时候有一个情况是,2交换后仍可能是2 + * 参考 0 2 1 2 1 0 2 自己手动交换一下就知道,所以才有 while里面的内容 + * @param nums + */ + public static void sortColors1(int[] nums) { + int n1 = 0; + int n2 = nums.length - 1; + + for (int i = 0; i <= n2; i++) { + // 交换过后 此时 nums[i] 可能是 0,也可能是2 ,还需要再继续交换 + while (i <= n2 && nums[i] == 2) { + int temp = nums[i]; + nums[i] = nums[n2]; + nums[n2] = temp; + --n2; + } + if (nums[i] == 0) { + int temp = nums[i]; + nums[i] = nums[n1]; + nums[n1] = temp; + ++n1; + } + } + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_79_word_search.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_79_word_search.java new file mode 100644 index 0000000..ff5adfd --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_79_word_search.java @@ -0,0 +1,93 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/21 上午9:07 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` Given a 2D board and a word, find if the word exists in the grid. + * ` The word can be constructed from letters of sequentially adjacent cell, + * ` where "adjacent" cells are those horizontally or vertically neighboring. + * ` The same letter cell may not be used more than once. + * ` 给定一个2D板和一个单词,查找单词是否存在于网格中。 + * ` 该单词可以由顺序相邻的单元格的字母构成, + * ` 其中“相邻”单元是水平或垂直相邻的单元。 + * ` 同一字母单元不得重复使用。 + * ` Example: + * ` board = [ + * ` ['A','B','C','E'], + * ` ['S','F','C','S'], + * ` ['A','D','E','E'] + * ` ] + * ` Given word = "ABCCED", return true. + * ` Given word = "SEE", return true. + * ` Given word = "ABCB", return false. + * @Version: 1.0 + */ +public class _79_word_search { + + + public static void main(String[] args) { + + char[][] board = { + {'A', 'B', 'C', 'E'}, + {'S', 'F', 'C', 'S'}, + {'A', 'D', 'E', 'E'} + }; + + + System.out.println(exist(board, "ABCCED")); + System.out.println(exist(board, "SEE")); + System.out.println(exist(board, "ABCB")); + } + + public static boolean exist(char[][] board, String word) { + + boolean[][] isUsed = new boolean[board.length][board[0].length]; + + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + if(backtrace(board, word, i, j, 0, isUsed)){ + return true; + } + } + } + + return false; + } + + private static boolean backtrace(char[][] board, String word, int x, int y, int index, boolean[][] isUsed) { + + // 超出边界 + if (x > board.length - 1 || y > board[0].length - 1 || x < 0 || y < 0) { + return false; + } + + if (isUsed[x][y]) { + return false; + } + + if (board[x][y] != word.charAt(index)) { + return false; + } + + isUsed[x][y] = true; + if (index == word.length() - 1) { + return true; + } + + if ( + backtrace(board, word, x + 1, y, index + 1, isUsed) + || backtrace(board, word, x - 1, y, index + 1, isUsed) + || backtrace(board, word, x, y - 1, index + 1, isUsed) + || backtrace(board, word, x, y + 1, index + 1, isUsed) + ) { + return true; + } + + isUsed[x][y] = false; + + return false; + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_81_search_in_rotated_sorted_arrayII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_81_search_in_rotated_sorted_arrayII.java new file mode 100644 index 0000000..ee7d776 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_81_search_in_rotated_sorted_arrayII.java @@ -0,0 +1,67 @@ +package com.leosanqing.leetcode.medium.array; + +/** + * @Author: rtliu + * @Date: 2020/7/21 上午11:40 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. + * (i.e., [0,0,1,2,2,5,6] might become [2,5,6,0,0,1,2]). + * You are given a target value to search. + * If found in the array return true, otherwise return false. + * Example 1: + * Input: nums = [2,5,6,0,0,1,2], target = 0 + * Output: true + * Example 2: + * Input: nums = [2,5,6,0,0,1,2], target = 3 + * Output: false + * @Version: 1.0 + */ +public class _81_search_in_rotated_sorted_arrayII { + + public static void main(String[] args) { + System.out.println(search(new int[]{4, 5, 6, 7, 0, 1, 2}, 0)); + } + + + public static boolean search(int[] nums, int target) { + if (nums == null || nums.length == 0) { + return false; + } + int start = 0, end = nums.length - 1; + + int mid = (end - start) / 2 + start; + + while (start <= end) { + if (nums[mid] == target || nums[start] == target || nums[end] == target) { + return true; + } + + // 说明 mid 没有越过分割点,那么中点左边部分是排好序的 + if (nums[mid] > nums[start]) { + // 如果 target 比左边点小 或者 比 中点大,那么 我们可以确定这个点 肯定不在 左边 + if (nums[mid] < target || target < nums[start]) { + start = mid; + } else { + end = mid; + } + } else if (nums[mid] < nums[start]) { + // 如果 target 比 中点小 或者 比 最右边的大,那么 target 肯定在 中点左侧 + if (nums[mid] > target || target > nums[end]) { + end = mid; + } else { + start = mid; + } + } else { + start++; + } + + mid = (end - start) / 2 + start; + + } + + return false; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_90_subsetsII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_90_subsetsII.java new file mode 100644 index 0000000..ac96f93 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/array/_90_subsetsII.java @@ -0,0 +1,62 @@ +package com.leosanqing.leetcode.medium.array; + +import com.alibaba.fastjson.JSON; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/22 下午3:00 + * @Package: com.leosanqing.leetcode.medium.array + * @Description: 1 + * ` Given a collection of integers that might contain duplicates, nums, return all possible subsets (the + * power set). + * ` Note: The solution set must not contain duplicate subsets. + * ` Example: + * ` Input: [1,2,2] + * ` Output: [ [2], [1], [1,2,2], [2,2], [1,2], [] ] + * @Version: 1.0 + */ +public class _90_subsetsII { + + public static void main(String[] args) { + + System.out.println(JSON.toJSONString(subsetsWithDup(new int[]{1, 2, 2}))); + } + + public static List> subsetsWithDup(int[] nums) { + if (nums == null) { + return null; + } + List> answer = new ArrayList<>(); + + // 先排序 + Arrays.sort(nums); + for (int i = 0; i <= nums.length; i++) { + backTrace(answer, new ArrayList<>(), nums, 0, i); + } + + return answer; + } + + private static void backTrace(List> answer, List list, int[] nums, int position, int max) { + + if (list.size() == max) { + answer.add(new ArrayList<>(list)); + return; + } + + for (int i = position; i < nums.length; i++) { + if (i > position && nums[i] == nums[i - 1]) { + continue; + } + list.add(nums[i]); + backTrace(answer, list, nums, i + 1, max); + list.remove(list.size() - 1); + } + + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/ListNode.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/ListNode.java new file mode 100644 index 0000000..ce488ce --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/ListNode.java @@ -0,0 +1,21 @@ +package com.leosanqing.leetcode.medium.list; + +/** + * @author zhuerchong + */ +public class ListNode { + public int val; + public ListNode next; + + public ListNode() { + } + + public ListNode(int val) { + this.val = val; + } + + public ListNode(int val, ListNode next) { + this.val = val; + this.next = next; + } +} \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_137_single_numberII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_137_single_numberII.java new file mode 100644 index 0000000..62bcbb8 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_137_single_numberII.java @@ -0,0 +1,45 @@ +package com.leosanqing.leetcode.medium.list; + +/** + * @Author: rtliu + * @Date: 2020/8/3 下午5:29 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: 1 + *` Given a non-empty array of integers, + *` every element appears three times except for one, + *` which appears exactly once. Find that single one. + *` Note: Your algorithm should have a linear runtime complexity. + *` Could you implement it without using extra memory? + *` Example 1: + *` Input: [2,2,3,2] + *` Output: 3 + *` Example 2: + *` Input: [0,1,0,1,0,1,99] + *` Output: 99 + *` + * @Version: 1.0 + */ +public class _137_single_numberII { + public static void main(String[] args) { + int[] ints = {2,2,3,2}; + System.out.println(singleNumber(ints)); + } + + public static int singleNumber(int[] nums) { + int ans = 0; + for(int i = 0; i < 32; i++) { + int sum = 0; + for (int num : nums) { + if (((num >> i) & 1) == 1) { + sum++; + sum %= 3; + } + } + if(sum != 0) { + ans |= sum << i; + } + } + return ans; + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_142_linked_list_cycleII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_142_linked_list_cycleII.java new file mode 100644 index 0000000..472e9d3 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_142_linked_list_cycleII.java @@ -0,0 +1,47 @@ +package com.leosanqing.leetcode.medium.list; + +/** + * @Author: rtliu + * @Date: 2020/8/4 下午4:50 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: 1 + * ` Given a linked list, return the node where the cycle begins. + * ` If there is no cycle, return null. + * ` To represent a cycle in the given linked list, + * ` we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. + * ` If pos is -1, then there is no cycle in the linked list. + * ` Note: Do not modify the linked list. + * ` Example 1: + * ` Input: head = [3,2,0,-4], pos = 1 + * ` Output: tail connects to node index 1 + * ` Explanation: + * ` There is a cycle in the linked list, where tail connects to the second node. + * ` Example 2: + * ` Input: head = [1,2], pos = 0 + * ` Output: tail connects to node index 0 + * ` Explanation: + * ` There is a cycle in the linked list, where tail connects to the first node. + * @Version: 1.0 + */ +public class _142_linked_list_cycleII { + + public ListNode detectCycle(ListNode head) { + ListNode slow = head; + ListNode fast = head; + + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + + if (slow == fast) { + ListNode n = head; + while (slow != n) { + slow = slow.next; + n = n.next; + } + return n; + } + } + return null; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_143_reorder_list.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_143_reorder_list.java new file mode 100644 index 0000000..1859da6 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_143_reorder_list.java @@ -0,0 +1,93 @@ +package com.leosanqing.leetcode.medium.list; + +/** + * @Author: rtliu + * @Date: 2020/8/4 下午5:03 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: 1 + * ` Given a singly linked list L: L0→L1→…→Ln-1→Ln, + * ` reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→… + * ` You may not modify the values in the list's nodes, only nodes itself may be changed. + * ` 给定一个单链表L:L0→L1→…→Ln-1→Ln, + * ` 将其重新排序为:L0→Ln→L1→Ln-1→L2→Ln-2→… + * ` 您不能修改列表节点中的值,只能更改节点本身。 + * ` Example 1: + * ` Given 1->2->3->4, + * ` reorder it to 1->4->2->3. + * ` Example 2: + * ` Given 1->2->3->4->5, + * ` reorder it to 1->5->2->4->3. + * @Version: 1.0 + */ +public class _143_reorder_list { + public static void main(String[] args) { + ListNode listNode = new ListNode(1); + listNode.next = new ListNode(2); + listNode.next.next = new ListNode(3); + listNode.next.next.next = new ListNode(4); +// listNode.next.next.next.next = new ListNode(5); +// listNode.next.next.next.next.next = new ListNode(6); + + reorderList(listNode); + } + + /** + * 分三步完成 + * 1. 找到中点 + * 2. 反转中点后的节点 + * 3. 然后挨个进行重组 + * + * @param head + */ + public static void reorderList(ListNode head) { + + if (head == null) { + return; + } + // 1。找到中点 + ListNode fakeNode = new ListNode(); + fakeNode.next = head; + ListNode fast = fakeNode; + ListNode slow = fakeNode; + while (fast != null && fast.next != null) { + fast = fast.next.next; + slow = slow.next; + } + + + // 2. 反转中点之后的节点 1 -> 2 -> 3 -> 4 -> 5 -> 6 变成 1 -> 2 -> 3 -> 6 -> 5 -> 4 + ListNode slowNext = reverse(slow.next); + + // 3. 重组 1 -> 2 -> 3 -> 6 -> 5 -> 4 变成 1 -> 6 -> 2 -> 5 -> 3 -> 4 + + slow = head; + ListNode firstNext; + fast = slowNext; + ListNode secondNext; + while (slow.next != null && fast != null) { + secondNext = fast.next; + firstNext = slow.next; + fast.next = slow.next; + slow.next = fast; + fast = secondNext; + slow = firstNext; + } + + slow.next = null; + System.out.println(); + + } + + private static ListNode reverse(ListNode node) { + + if (node == null || node.next == null) { + return node; + } + ListNode next = reverse(node.next); + + node.next.next = node; + node.next = null; + return next; + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_19_remove_Nth_node_from_end_of_list.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_19_remove_Nth_node_from_end_of_list.java new file mode 100644 index 0000000..8f3a2ba --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_19_remove_Nth_node_from_end_of_list.java @@ -0,0 +1,51 @@ +package com.leosanqing.leetcode.medium.list; + +/** + * @Author: rtliu + * @Date: 2020/7/7 下午3:47 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: Given a linked list, remove the n-th node from the end of list and return its head. + *

+ *

+ * ` `Example: + * ` ` Give linked list: 1->2->3->4->5, and n = 2. + * ` ` After removing the second node from the end, the linked list becomes + * ` ` 1->2->3->5. + * ` ` Note: Given n will always be valid. + * @Version: 1.0 + */ +public class _19_remove_Nth_node_from_end_of_list { + + public static void main(String[] args) { + + } + + /** + * 思路就是使用两个节点,一个快节点先走 n步,然后快节点走到最后,后面的那个节点就是我们要去掉的节点 + * 设置一个虚拟头结点,可以帮助我们解决边界值问题 + * + * @param head + * @param n + * @return + */ + public ListNode removeNthFromEnd(ListNode head, int n) { + ListNode fakeHead = new ListNode(); + + ListNode slow = fakeHead; + ListNode fast = fakeHead; + + fakeHead.next = head; + + for (int i = 0; i < n; i++) { + fast = fast.next; + } + + while (fast.next != null) { + fast = fast.next; + slow = slow.next; + } + slow.next = slow.next.next; + + return fakeHead.next; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_24_swap_nodes_in_pairs.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_24_swap_nodes_in_pairs.java new file mode 100644 index 0000000..7e66fa0 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_24_swap_nodes_in_pairs.java @@ -0,0 +1,57 @@ +package com.leosanqing.leetcode.medium.list; + +/** + * @Author: rtliu + * @Date: 2020/7/9 上午10:25 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: ` Given a linked list, swap every two adjacent nodes and return its head. + * ` You may not modify the values in the list's nodes, only nodes itself may be changed. + * ` Example: + * ` Given 1->2->3->4, + * ` you should return the list as 2->1->4->3. + * @Version: 1.0 + */ +public class _24_swap_nodes_in_pairs { + public static void main(String[] args) { + ListNode node1 = new ListNode(5); + ListNode node2 = new ListNode(2, node1); + ListNode node3 = new ListNode(6, node2); + ListNode node4 = new ListNode(1, node3); + + ListNode x = swapPairs(node4); + + while (x != null) { + System.out.println(x.val); + x= x.next; + } + } + + + public static ListNode swapPairs(ListNode head) { + + if (head == null) { + return null; + } + ListNode fakeHead = new ListNode(); + fakeHead.next = head; + + ListNode root = fakeHead; + ListNode pre = head; + ListNode curr = pre.next; + + while (pre.next != null) { + root.next = pre.next; + pre.next = curr.next; + curr.next = pre; + + root = curr.next; + if (pre.next == null) { + return fakeHead.next; + } + curr = pre.next.next; + pre = root.next; + } + return fakeHead.next; + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_2_addTwoNumbers.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_2_addTwoNumbers.java new file mode 100644 index 0000000..888c5d4 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_2_addTwoNumbers.java @@ -0,0 +1,72 @@ +package com.leosanqing.leetcode.medium.list; + +/** + * @Author: rtliu + * @Date: 2020/7/2 下午4:54 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: ` ` You are given two non-empty linked lists representing two non-negative integers. + * ` ` The digits are stored in reverse order and each of their nodes contain a single digit. + * ` ` Add the two numbers and return it as a linked list. + * ` ` You may assume the two numbers do not contain any leading zero, except the number 0 itself. + *

+ * ` ` 您将获得两个表示两个非负整数的非空链表。 + * ` ` 这些数字以相反的顺序存储,并且它们的每个节点都包含一个数字。 + * ` ` 将两个数字相加并作为链接列表返回。 + * ` ` 您可以假设两个数字除了数字0本身以外,都不包含任何前导零。 + *

+ * ` ` Example: + * ` ` Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) + * ` ` Output: 7 -> 0 -> 8 + * ` ` Explanation: 342 + 465 = 807. + * @Version: 1.0 + */ +public class _2_addTwoNumbers { + public static void main(String[] args) { + ListNode node1 = new ListNode(5); + ListNode node2 = new ListNode(2, node1); + ListNode node3 = new ListNode(6, node2); + ListNode node4 = new ListNode(5); + ListNode node5 = new ListNode(1, node4); + ListNode node6 = new ListNode(3, node5); + + ListNode listNode1 = addTwoNumbers(node3, node6); + } + + public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { + + ListNode cur1 = l1; + ListNode cur2 = l2; + + ListNode head = new ListNode(); + ListNode cur = head; + + int carry = 0; + // 定义在这里不需要新建对象 + int sum; + + while (cur1 != null || cur2 != null) { + if (cur1 == null) { + cur1 = new ListNode(0); + } + if (cur2 == null) { + cur2 = new ListNode(0); + } + + // 计算位数之和 + sum = carry + cur1.val + cur2.val; + // 是否大于0 + carry = sum / 10; + cur.next = new ListNode(sum % 10); + + cur = cur.next; + cur1 = cur1.next; + cur2 = cur2.next; + } + + if (carry != 0) { + cur.next = new ListNode(1); + } + return head.next; + } +} + diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_77_combinations.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_77_combinations.java new file mode 100644 index 0000000..065360e --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_77_combinations.java @@ -0,0 +1,54 @@ +package com.leosanqing.leetcode.medium.list; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/20 下午7:44 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: 1 + * ` Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. + * ` 给定两个整数n和k,返回1 ... n中k个数字的所有可能组合。 + * ` Example: + * ` Input: n = 4, k = 2 + * ` Output: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] + * @Version: 1.0 + */ +public class _77_combinations { + public static void main(String[] args) { + + combine(4, 2); + } + + public static List> combine(int n, int k) { + + if (n == 0 || k <= 0) { + + return new ArrayList<>(); + } + List> answer = new ArrayList<>(); + + backTrace(answer, new ArrayList<>(), k, n, 1); + + return answer; + } + + + public static void backTrace(List> answer, List list, int k, int n, int position) { + + if (list.size() == k) { + answer.add(new ArrayList<>(list)); + return; + } + + for (int i = position; i <= n; i++) { + if (list.contains(i)) { + continue; + } + list.add(i); + backTrace(answer, list, k, n, i + 1); + list.remove(list.size() - 1); + } + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_78_subsets.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_78_subsets.java new file mode 100644 index 0000000..0bffeea --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_78_subsets.java @@ -0,0 +1,53 @@ +package com.leosanqing.leetcode.medium.list; + +import com.alibaba.fastjson.JSON; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/20 下午8:08 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: 1 + * ` Given a set of distinct integers, nums, return all possible subsets (the power set). + * ` Note: The solution set must not contain duplicate subsets. + * ` Example: + * ` Input: nums = [1,2,3] + * ` Output: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ] + * @Version: 1.0 + */ +public class _78_subsets { + public static void main(String[] args) { + System.out.println(JSON.toJSONString(subsets(new int[]{1, 2, 3}))); + } + + /** + * 这个真的太经典了,回溯的经典题型,你会发现有很多很多这种的题 + * + * @param nums + * @return + */ + public static List> subsets(int[] nums) { + List> answer = new ArrayList<>(); + + for (int i = 0; i <= nums.length; i++) { + backtrace(answer, new ArrayList<>(), i, nums, 0); + } + + return answer; + } + + private static void backtrace(List> answer, List list, int max, int[] nums, int position) { + if (list.size() == max) { + answer.add(new ArrayList<>(list)); + return; + } + + for (int i = position; i < nums.length; i++) { + list.add(nums[i]); + backtrace(answer, list, max, nums, i + 1); + list.remove(list.size() - 1); + } + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_82_remove_duplicates_from_sorted_listII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_82_remove_duplicates_from_sorted_listII.java new file mode 100644 index 0000000..f5f2e62 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_82_remove_duplicates_from_sorted_listII.java @@ -0,0 +1,68 @@ +package com.leosanqing.leetcode.medium.list; + +/** + * @Author: rtliu + * @Date: 2020/7/21 下午4:48 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: 1 + * ` Given a sorted linked list, delete all nodes that have duplicate numbers, + * ` leaving only distinct numbers from the original list. + * ` Return the linked list sorted as well. + * ` Example 1: + * ` Input: 1->2->3->3->4->4->5 + * ` Output: 1->2->5 + * ` Example 2: + * ` Input: 1->1->1->2->3 + * ` Output: 2->3 + * @Version: 1.0 + */ +public class _82_remove_duplicates_from_sorted_listII { + public static void main(String[] args) { + ListNode node1 = new ListNode(4); + ListNode node2 = new ListNode(4, node1); + ListNode node3 = new ListNode(3, node2); + ListNode node4 = new ListNode(2,node3); + ListNode node5 = new ListNode(2, node4); + ListNode node6 = new ListNode(2, node5); + ListNode node7 = new ListNode(1, node6); + + deleteDuplicates(node7); + } + + public static ListNode deleteDuplicates(ListNode head) { + if (head == null) { + return null; + } + ListNode fakeNode = new ListNode(); + fakeNode.next = head; + + ListNode pre = fakeNode; + ListNode cur = fakeNode.next; + ListNode next = cur.next; + while (next != null) { + if(next.val != cur.val){ + pre = cur; + cur = next; + next = cur.next; + continue; + } + // 一直找到不重复的 + while(next != null && cur.val == next.val){ + cur = next; + next = next.next; + } + // 然后把 之前的 pre 节点直接链接到 next节点。这样中间重复的就相当于被删除了 + if (next != null){ + pre.next = next; + cur = next; + next = cur.next; + }else{ + pre.next = next; + } + + + } + + return fakeNode.next; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_83_remove_duplicates_from_sorted_list.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_83_remove_duplicates_from_sorted_list.java new file mode 100644 index 0000000..e4b1efc --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_83_remove_duplicates_from_sorted_list.java @@ -0,0 +1,50 @@ +package com.leosanqing.leetcode.medium.list; + +/** + * @Author: rtliu + * @Date: 2020/7/21 下午5:28 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: 1 + *` Given a sorted linked list, delete all duplicates such that each element appear only once. + *` Example 1: + *` Input: 1->1->2 + *` Output: 1->2 + *` Example 2: + *` Input: 1->1->2->3->3 + *` Output: 1->2->3 + * @Version: 1.0 + */ +public class _83_remove_duplicates_from_sorted_list { + public static void main(String[] args) { + ListNode node1 = new ListNode(1); + ListNode node2 = new ListNode(1, node1); + ListNode node3 = new ListNode(1, node2); + ListNode node4 = new ListNode(1,node3); + ListNode node5 = new ListNode(1, node4); + ListNode node6 = new ListNode(1, node5); + ListNode node7 = new ListNode(1, node6); + + System.out.println(deleteDuplicates(node7).val); + } + + public static ListNode deleteDuplicates(ListNode head) { + ListNode fakeNode = new ListNode(Integer.MIN_VALUE); + fakeNode.next = head; + + ListNode pre = fakeNode; + ListNode cur = pre.next; + + + while (cur != null){ + if(pre.val == cur.val){ + cur = cur.next; + pre.next = cur; + continue; + } + pre = cur; + cur = cur.next; + } + + return fakeNode.next; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_92_reverseLinkedList2.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_92_reverseLinkedList2.java new file mode 100644 index 0000000..c5d337c --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/list/_92_reverseLinkedList2.java @@ -0,0 +1,54 @@ +package com.leosanqing.leetcode.medium.list; + +/** + * @Author: rtliu + * @Date: 2020/6/1 下午7:01 + * @Package: com.leosanqing.leetcode.medium + * @Description: Reverse a linked list from position m to n. Do it in one-pass. + * 对反转给定范围的链表节点进行反转,只遍历一遍 + *

+ * Note: 1 ≤ m ≤ n ≤ length of list. + *

+ * Example: + *

+ * Input: 1->2->3->4->5->NULL, m = 2, n = 4 + * Output: 1->4->3->2->5->NULL + * @Version: 1.0 + */ +public class _92_reverseLinkedList2 { + + public ListNode reverseBetween(ListNode head, int m, int n) { + if (head == null) { + return null; + } + // 设置一个虚拟头结点 + ListNode fakeHead = new ListNode(0); + fakeHead.next = head; + ListNode cur1 = fakeHead; + ListNode pre1 = null; + + // 找到 m 的位置 + for (int i = 0; i < m; i++) { + pre1 = cur1; + cur1 = cur1.next; + } + + ListNode next; + ListNode pre2 = pre1; + ListNode cur2 = cur1; + for (int i = 0; i <= n - m; i++) { + next = cur2.next; + cur2.next = pre2; + pre2 = cur2; + cur2 = next; + } + + // 反转完之后,链接 m 之前的节点 和 n 后的节点 + pre1.next = pre2; + cur1.next = cur2; + + return fakeHead.next; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/num/_264_uglyNumberII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/num/_264_uglyNumberII.java new file mode 100644 index 0000000..3c024da --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/num/_264_uglyNumberII.java @@ -0,0 +1,52 @@ +package com.leosanqing.leetcode.medium.num; + +/** + * @Author: rtliu + * @Date: 2020/6/23 下午4:17 + * @Package: com.leosanqing.leetcode.medium.num + * @Description: Write a program to find the n-th ugly number. + * Ugly numbers are positive numbers whose prime factors + * only include 2, 3, 5. + * @Version: 1.0 + *

+ *

+ * Example: + *

+ * Input: n = 10 + * Output: 12 + * Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers. + * Note: + *

+ * 1 is typically treated as an ugly number. + * n does not exceed 1690. + */ +public class _264_uglyNumberII { + public int nthUglyNumber(int n) { + + // 创建一个数组,用来存储 uglyNumber + int[] ugly = new int[n]; + ugly[0] = 1; + + int index2 = 0, index3 = 0, index5 = 0; + int factor2 = 2, factor3 = 3, factor5 = 5; + for (int i = 1; i < n; i++) { + int min = Math.min(Math.min(factor2, factor3), factor5); + ugly[i] = min; + // 如果 这个数字是他的倍数,那就往后走, + // 比如 30 是 2 3 5 的共同的 uglyNumber,所以他们都要往后移一个 + if (factor2 == min) { + factor2 = 2 * ugly[++index2]; + } + if (factor3 == min) { + factor3 = 3 * ugly[++index3]; + } + if (factor5 == min) { + factor5 = 5 * ugly[++index5]; + } + } + return ugly[n - 1]; + } + + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_131_palindrome_partitioning.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_131_palindrome_partitioning.java new file mode 100644 index 0000000..1b29a54 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_131_palindrome_partitioning.java @@ -0,0 +1,58 @@ +package com.leosanqing.leetcode.medium.string; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/8/3 下午5:43 + * @Package: com.leosanqing.leetcode.medium.string + * @Description: 1 + * ` Given a string s, partition s such that every substring of the partition is a palindrome. + * ` Return all possible palindrome partitioning of s. + * ` Example: + * ` Input: "aab" + * ` Output: + * ` [ + * ` ["aa","b"], + * ` ["a","a","b"] + * ` ] + * @Version: 1.0 + */ +public class _131_palindrome_partitioning { + public static void main(String[] args) { + partition("aab"); + } + public static List> partition(String s) { + + List> answer = new ArrayList<>(); + for (int i = 1; i < s.length(); i++) { + backTrace(answer,new ArrayList<>(), s, 0, i); + } + return answer; + } + + private static void backTrace(List> answer, List list, String s, int position, int length) { + if (position >= s.length()) { + answer.add(new ArrayList<>(list)); + return; + } + + + String substring = s.substring(position, position + length); + if (isPalindrome(substring)) { + list.add(substring); + return; + } + backTrace(answer, list, s, position + length, length); + } + + private static boolean isPalindrome(String s) { + for (int i = 0; i < s.length() / 2; i++) { + if (s.charAt(i) != s.charAt(s.length() - 1 - i)) { + return false; + } + } + return true; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_139_word_break.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_139_word_break.java new file mode 100644 index 0000000..b16fbac --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_139_word_break.java @@ -0,0 +1,80 @@ +package com.leosanqing.leetcode.medium.string; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @Author: rtliu + * @Date: 2020/8/4 上午11:38 + * @Package: com.leosanqing.leetcode.medium.string + * @Description: 1 + * 1 Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, + * 1 determine if s can be segmented into a space-separated sequence of one or more dictionary words. + * 1 给定一个非空字符串s和一个包含非空单词列表的字典wordDict, + * 1 确定是否可以将s分割为一个或多个词典单词的以空格分隔的序列 + * 1 + * 1 Note: + * 1 The same word in the dictionary may be reused multiple times in the segmentation. + * 1 You may assume the dictionary does not contain duplicate words. + * 1 Example 1: + * 1 Input: s = "leetcode", wordDict = ["leet", "code"] + * 1 Output: true + * 1 Explanation: + * 1 Return true because "leetcode" can be segmented as "leet code". + * 1 Example 2: + * 1 Input: s = "applepenapple", wordDict = ["apple", "pen"] + * 1 Output: true + * 1 Explanation: + * 1 Return true because "applepenapple" can be segmented as "apple pen apple". + * 1 Note that you are allowed to reuse a dictionary word. + * 1 Example 3: + * 1 Input: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] + * 1 Output: false + * 1 + * @Version: 1.0 + */ +public class _139_word_break { + + static Set set; + + public static void main(String[] args) { + String s = "leetcode"; + + System.out.println(wordBreak(s, Arrays.asList("leet", "code"))); + } + + public static boolean wordBreak(String s, List wordDict) { + set = new HashSet<>(wordDict); + return backtrace(s, 0, new HashSet<>()); + + } + + + private static boolean backtrace(String s, int position, Set words) { + if (position == s.length()) { + return true; + } + + // 如果存在,则说明已经尝试过这种方法,就直接返回 + if (words.contains(position)) { + return false; + } + + for (int i = position + 1; i <= s.length(); i++) { + if (!set.contains(s.substring(position, i))) { + continue; + } + + if (backtrace(s, i, words)) { + return true; + } + + words.add(i); + } + + words.add(position); + return false; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_22_generate_parentheses.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_22_generate_parentheses.java new file mode 100644 index 0000000..2b746b8 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_22_generate_parentheses.java @@ -0,0 +1,60 @@ +package com.leosanqing.leetcode.medium.string; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/8 下午3:44 + * @Package: com.leosanqing.leetcode.medium.string + * @Description: ` Given n pairs of parentheses, write a function to generate all combinations of well-formed + * parentheses. + * ` + * ` For example, + * ` given n = 3, a solution set is: + * ` [ + * ` "((()))", + * ` "(()())", + * ` "(())()", + * ` "()(())", + * ` "()()()" + * ` ] + * @Version: 1.0 + */ +public class _22_generate_parentheses { + + + public static void main(String[] args) { + System.out.println(generateParenthesis(3)); + } + + public static List generateParenthesis(int n) { + List list = new ArrayList<>(); + + backtrace(list, new StringBuilder(), 0, 0, n); + + return list; + } + + + private static void backtrace(List result, StringBuilder sb, int left, int right, int max) { + if (left == max && right == max) { + result.add(sb.toString()); + return; + } + + if (left <= max) { + sb.append("("); + backtrace(result, sb, left + 1, right, max); + sb.deleteCharAt(sb.length() - 1); + } + + // 避免出现 ())这种情况 + if (right < left) { + sb.append(")"); + backtrace(result, sb, left, right + 1, max); + sb.deleteCharAt(sb.length() - 1); + } + + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_31_next_permutation.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_31_next_permutation.java new file mode 100644 index 0000000..ecdabb3 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_31_next_permutation.java @@ -0,0 +1,70 @@ +package com.leosanqing.leetcode.medium.string; + +import com.alibaba.fastjson.JSON; + +import java.util.Arrays; + +/** + * @description: ` 实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。 + * ` + * ` 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。 + * ` + * ` 必须 原地 修改,只允许使用额外常数空间。 + * ` + * ` 示例 1: + * ` + * ` 输入:nums = [1,2,3] + * ` 输出:[1,3,2] + * ` 示例 2: + * ` + * ` 输入:nums = [3,2,1] + * ` 输出:[1,2,3] + * ` 示例 3: + * ` + * ` 输入:nums = [1,1,5] + * ` 输出:[1,5,1] + * ` 示例 4: + * ` + * ` 输入:nums = [1] + * ` 输出:[1] + * @author: rtliu + * @date: 2021/4/8 2:07 下午 + */ +public class _31_next_permutation { + public static void main(String[] args) { + nextPermutation(new int[]{1, 3, 2}); + } + + /** + * 1.从右到左找升序数字 + * 2.找到右边比当前数字大的数字,两个交换位置 + * 3.右边数字再重新升序排列 + * + * @param nums + */ + public static void nextPermutation(int[] nums) { + + for (int i = nums.length - 1; i > 0; i--) { + if (nums[i] < nums[i - 1]) { + continue; + } + + for (int j = nums.length - 1; j >= i; j--) { + if (nums[i - 1] > nums[j]) { + continue; + } + + // 从后面找比 num 大的数字,交换 + int temp = nums[i - 1]; + nums[i - 1] = nums[j]; + nums[j] = temp; + + Arrays.sort(nums, i, nums.length); + return; + + } + + } + Arrays.sort(nums); + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_3_longest_substring_without_repeating_characters.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_3_longest_substring_without_repeating_characters.java new file mode 100644 index 0000000..9f0589e --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_3_longest_substring_without_repeating_characters.java @@ -0,0 +1,66 @@ +package com.leosanqing.leetcode.medium.string; + +import java.util.HashMap; +import java.util.Map; + +/** + * @description: Given a string s, find the length of the longest substring without repeating characters. + *

+ * 给定字符串s,找到最长子字符串的长度而不重复字符。 + *

+ * ` Example 1: + *

+ * ` Input: s = "abcabcbb" + * ` Output: 3 + * ` Explanation: The answer is "abc", with the length of 3. + * ` Example 2: + *

+ * ` Input: s = "bbbbb" + * ` Output: 1 + * ` Explanation: The answer is "b", with the length of 1. + * ` Example 3: + *

+ * ` Input: s = "pwwkew" + * ` Output: 3 + * ` Explanation: The answer is "wke", with the length of 3. + * ` Notice that the answer must be a substring, "pwke" is a subsequence and not a substring. + * ` Example 4: + *

+ * ` Input: s = "" + * ` Output: 0 + *

+ * ` @author: rtliu + * ` @date: 2021/4/6 3:41 下午 + */ +public class _3_longest_substring_without_repeating_characters { + public static void main(String[] args) { + System.out.println(lengthOfLongestSubstring("abba")); + } + + /** + * 这个是典型的滑动窗口类的题型 + * + * 我们遇到相同的字符就丢弃之前字符左边的所有字符 + * @param s + * @return + */ + public static int lengthOfLongestSubstring(String s) { + Map map = new HashMap<>(s.length() * 2); + + int result = 0; + int head = 0; + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + if (map.containsKey(c) && head < map.get(c)) { + head = map.get(c); + } + // i+1 表示当前字符的实际位置 + result = Math.max(i + 1 - head, result); + map.put(c, i + 1); + } + + return result; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_43_multiply_strings.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_43_multiply_strings.java new file mode 100644 index 0000000..4e191d8 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_43_multiply_strings.java @@ -0,0 +1,63 @@ +package com.leosanqing.leetcode.medium.string; + +/** + * @Author: rtliu + * @Date: 2020/7/13 下午5:05 + * @Package: com.leosanqing.leetcode.medium.string + * @Description: 1 + * ` Given two non-negative integers num1 and num2 represented as strings, + * ` return the product of num1 and num2, also represented as a string. + * ` + * ` 给定两个表示为字符串的非负整数num1和num2, + * ` 返回num1和num2的乘积,也表示为字符串。 + * ` Example 1: + * ` Input: num1 = "2", num2 = "3" + * ` Output: "6" + * ` Example 2: + * ` Input: num1 = "123", num2 = "456" + * ` Output: "56088" + * @Version: 1.0 + */ +public class _43_multiply_strings { + public static void main(String[] args) { + + System.out.println(multiply("999", "999").equals(String.valueOf(999 * 999))); + + } + + /** + * 我们做乘法也是这样做 + * @param num1 + * @param num2 + * @return + */ + public static String multiply(String num1, String num2) { + + int m = num1.length(); + int n = num2.length(); + + int[] result = new int[m + n]; + + for (int i = m - 1; i >= 0; i--) { + for (int j = n - 1; j >= 0; j--) { + int temp = (num1.charAt(i) - '0') * (num2.charAt(j) - '0'); + int p1 = i + j, p2 = i + j + 1; + + int sum = temp + result[p2]; + + result[p1] += sum / 10; + result[p2] = sum % 10; + + } + } + + StringBuilder stringBuilder = new StringBuilder(); + for (int i : result) { + if (stringBuilder.length() == 0 && i == 0) { + continue; + } + stringBuilder.append(i); + } + return stringBuilder.length() == 0 ? "0" : stringBuilder.toString(); + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_5_longestPalindromicSubstring.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_5_longestPalindromicSubstring.java new file mode 100644 index 0000000..464db5c --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_5_longestPalindromicSubstring.java @@ -0,0 +1,56 @@ +package com.leosanqing.leetcode.medium.string; + +/** + * @Author: rtliu + * @Date: 2020/7/3 上午11:16 + * @Package: com.leosanqing.leetcode.medium.string + * @Description: ` ` Given a string s, find the longest palindromic substring in s. + * ` ` You may assume that the maximum length of s is 1000. + * ` + * ` ` 给定字符串s,找到s中最长的回文子字符串。 + * ` 您可以假设s的最大长度为1000。 + * ` ` Example 1: + * ` ` Input: "babad" + * ` ` Output: "bab" + * ` ` Note: "aba" is also a valid answer. + * ` ` Example 2: + * ` ` Input: "cbbd" + * ` ` Output: "bb" + * @Version: 1.0 + */ +public class _5_longestPalindromicSubstring { + public static void main(String[] args) { + String s = "abasasaiug"; + System.out.println(longestPalindrome(s)); + } + + public static String longestPalindrome(String s) { + if (s.length() < 2) { + return s; + } + String longStr = ""; + + for (int i = 0; i < s.length(); i++) { + String s1 = findStr(s, i, i); + String s2 = findStr(s, i, i + 1); + + if (s1.length() > longStr.length()) { + longStr = s1; + } + if (s2.length() > longStr.length()) { + longStr = s2; + } + } + + return longStr; + } + + private static String findStr(String s, int i, int j) { + for (; i >= 0 && j < s.length(); i--, j++) { + if (s.charAt(i) != s.charAt(j)) { + break; + } + } + return s.substring(i + 1, j); + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_71_simplify_path.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_71_simplify_path.java new file mode 100644 index 0000000..417c455 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_71_simplify_path.java @@ -0,0 +1,90 @@ +package com.leosanqing.leetcode.medium.string; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Stack; + +/** + * @Author: rtliu + * @Date: 2020/7/20 下午1:56 + * @Package: com.leosanqing.leetcode.medium.string + * @Description: 1 + * ` Given an absolute path for a file (Unix-style), simplify it. + * ` Or in other words, convert it to the canonical path. + * ` In a UNIX-style file system, a period . + * ` refers to the current directory. Furthermore, a double period .. moves the directory up a level. + * ` + * ` Note that the returned canonical path must always begin with a slash /, + * ` and there must be only a single slash / between two directory names. + * ` The last directory name (if it exists) must not end with a trailing /. + * ` Also, the canonical path must be the shortest string representing the absolute path. + * ` + * ` 给定文件的绝对路径(Unix风格),请简化它。 + * ` 或者换句话说,将其转换为规范路径。 + * ` 在UNIX样式的文件系统中,为period。 + * ` 指当前目录。此外,双倍..将目录上移 + * ` 请注意,返回的规范路径必须始终以斜杠/开头。 + * ` 并且两个目录名称之间只能有一个斜杠/。 + * ` 最后的目录名称(如果存在)不得以/结尾。 + * ` 同样,规范路径必须是代表绝对路径的最短字符串。 + * ` + * ` Example 1: + * ` Input: "/home/" + * ` Output: "/home" + * ` Explanation: + * ` Note that there is no trailing slash after the last directory name. + * ` Example 2: + * ` Input: "/../" + * ` Output: "/" + * ` Explanation: + * ` Going one level up from the root directory is a no-op, + * ` as the root level is the highest level you can go. + * ` Example 3: + * ` Input: "/home//foo/" + * ` Output: "/home/foo" + * ` Explanation: + * ` In the canonical path, multiple consecutive slashes are replaced by a single one. + * ` Example 4: + * ` Input: "/a/./b/../../c/" + * ` Output: "/c" + * ` Example 5: + * ` Input: "/a/../../b/../c//.//" + * ` Output: "/c" + * ` Example 6: + * ` Input: "/a//b////c/d//././/.." + * ` Output: "/a/b/c" + * @Version: 1.0 + */ +public class _71_simplify_path { + public static void main(String[] args) { + System.out.println(simplifyPath("/a//b////c/d//././/..")); + } + + public static String simplifyPath(String path) { + if (path == null || "".equals(path)) { + return ""; + } + Stack stack = new Stack<>(); + String[] split = path.split("/"); + HashSet pathSet = new HashSet<>(Arrays.asList("..", ".", "")); + for (String s : split) { + if ("..".equals(s) && !stack.isEmpty()) { + stack.pop(); + } else if (!pathSet.contains(s)) { + stack.push(s); + } + } + + if (stack.isEmpty()) { + return "/"; + } + + StringBuilder sb = new StringBuilder(); + for (String s : stack) { + sb.append("/").append(s); + } + return sb.toString(); + + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_91_decode_ways.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_91_decode_ways.java new file mode 100644 index 0000000..fd36509 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_91_decode_ways.java @@ -0,0 +1,55 @@ +package com.leosanqing.leetcode.medium.string; + +/** + * @Author: rtliu + * @Date: 2020/7/22 下午4:16 + * @Package: com.leosanqing.leetcode.medium.string + * @Description: 1 + * ` A message containing letters from A-Z is being encoded to numbers using the following mapping: + * ` 'A' -> 1 'B' -> 2 ... 'Z' -> 26 + * ` Given a non-empty string containing only digits, determine the total number of ways to decode it. + * ` Example 1: + * ` Input: "12" + * ` Output: 2 + * ` Explanation: + * ` It could be decoded as "AB" (1 2) or "L" (12). + * ` Example 2: + * ` Input: "226" + * ` Output: 3 + * ` Explanation: + * ` It could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6). + * @Version: 1.0 + */ +public class _91_decode_ways { + public static void main(String[] args) { + + System.out.println(numDecodings("2262")); + } + + public static int numDecodings(String s) { + int[] dp = new int[s.length() + 1]; + dp[0] = 1; + dp[1] = s.charAt(0) != '0' ? 1 : 0; + + for (int i = 2; i <= s.length(); i++) { + int first = Integer.parseInt(s.substring(i - 1, i)); + int second = Integer.parseInt(s.substring(i - 2, i)); + + + // 如果这位数是 1-9, 那么 他可以就等于之前的位数,按照单个算 + // 如 2221 我如果只看最后一位1,那么他的可能性肯定只会等于 222的可能性 + if (first >= 1 && first <= 9) { + dp[i] = dp[i - 1]; + } + + // 如果 我们 两位 两位看,他的可能性就是之前一位的加上 两位的可能性 + // 如 1211 最后 1 的可能性就是 121 + 12 的可能性 + if (second >= 10 && second <= 26) { + dp[i] += dp[i - 2]; + } + } + return dp[s.length()]; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_93_restore_IP_addresses.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_93_restore_IP_addresses.java new file mode 100644 index 0000000..d4eae09 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/string/_93_restore_IP_addresses.java @@ -0,0 +1,90 @@ +package com.leosanqing.leetcode.medium.string; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/23 下午4:47 + * @Package: com.leosanqing.leetcode.medium.string + * @Description: 1 + * ` Given a string containing only digits, restore it by returning all possible valid IP address combinations. + * ` A valid IP address consists of exactly four integers (each integer is between 0 and 255) separated by + * single points. + * ` Example: + * ` Input: "25525511135" + * ` Output: ["255.255.11.135", "255.255.111.35"] + * @Version: 1.0 + */ +public class _93_restore_IP_addresses { + + public static void main(String[] args) { + String s = "25525511135"; + restoreIpAddresses(s); + + System.out.println(s.substring(0,1)); + } + + public static List restoreIpAddresses(String s) { + if (s.length() < 4 || s.length() > 12) { + return new ArrayList<>(); + } + + List result = new ArrayList<>(); + doRestore(result, "", s, 0); + return result; + } + + public static List restoreIpAddresses1(String s) { + if (s.length() < 4 || s.length() > 12) { + return new ArrayList<>(); + } + List result = new ArrayList<>(); + for (int a = 1; a <= 3; a++) { + for (int b = 1; b <= 3; b++) { + for (int c = 1; c <= 3; c++) { + for (int d = 1; d <= 3; d++) { + if (a + b + c + d == s.length()) { + int num1 = Integer.parseInt(s.substring(0, a)); + int num2 = Integer.parseInt(s.substring(a, a + b)); + int num3 = Integer.parseInt(s.substring(a + b, a + b + c)); + int num4 = Integer.parseInt(s.substring(a + b + c)); + + if (num1 <= 255 && num2 <= 255 && num3 <= 255 && num4 <= 255) { + result.add(num1 + "." + num2 + "." + num3 + "." + num4); + } + } + } + } + } + } + return result; + } + + + /** + * + * @param result + * @param path 已经组成的ip地址 + * @param s 去掉path 后的 剩余的字符 如初始为 2222,path 为 2.2 str 为22 + * @param k 已经有几段ip地址了 如 运行到 k=2 ,这个时候 path 为 22.22 + */ + private static void doRestore(List result, String path, String s, int k) { + if (k == 4 || s.isEmpty()) { + if (k == 4 && s.isEmpty()) { + result.add(path.substring(1)); + } + return; + } + + // 如果 s开头为0,只能截取1个字符,不然会出现 22.02 不符合规则 + for (int i = 1; i <= (s.charAt(0) == '0' ? 1 : 3) && i <= s.length(); i++) { + // + String part = s.substring(0, i); + // 必须小于 255 + if (Integer.parseInt(part) <= 255) { + doRestore(result, path + "." + part, s.substring(i), k + 1); + } + } + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/struct/_146_LRU_Cache.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/struct/_146_LRU_Cache.java new file mode 100644 index 0000000..c0ad5f0 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/struct/_146_LRU_Cache.java @@ -0,0 +1,131 @@ +package com.leosanqing.leetcode.medium.struct; + +import java.util.HashMap; +import java.util.Map; + +/** + * @description: 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制 。 + * 实现 LRUCache 类: + *

+ * LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存 + * int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。 + * void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。 + *

+ * 进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作? + *

+ * 示例: + *

+ * 输入 + * ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"] + * [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]] + * 输出 + * [null, null, null, 1, null, -1, null, -1, 3, 4] + *

+ * 解释 + * LRUCache lRUCache = new LRUCache(2); + * lRUCache.put(1, 1); // 缓存是 {1=1} + * lRUCache.put(2, 2); // 缓存是 {1=1, 2=2} + * lRUCache.get(1); // 返回 1 + * lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3} + * lRUCache.get(2); // 返回 -1 (未找到) + * lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3} + * lRUCache.get(1); // 返回 -1 (未找到) + * lRUCache.get(3); // 返回 3 + * lRUCache.get(4); // 返回 4 + * @author: rtliu + * @date: 2021/4/25 9:57 上午 + */ +public class _146_LRU_Cache { + public static void main(String[] args) { + LRUCache lruCache = new LRUCache(1); + lruCache.put(2,1); + System.out.println(lruCache.get(2)); + } + + static class DLinkedNode { + int value; + int key; + DLinkedNode pre; + DLinkedNode next; + + public DLinkedNode() { + } + + public DLinkedNode(int key, int value) { + this.value = value; + this.key = key; + } + } + + static class LRUCache { + private Map map = new HashMap<>(); + private int size; + private int capacity; + private DLinkedNode head; + private DLinkedNode tail; + + public LRUCache(int capacity) { + this.size = 0; + this.capacity = capacity; + + // 使用虚拟的头尾节点,防止出现极限问题 + head = new DLinkedNode(); + tail = new DLinkedNode(); + head.next = tail; + tail.pre = head; + } + + public int get(int key) { + DLinkedNode node = map.get(key); + if (node == null) { + return -1; + } + moveToHead(node); + return node.value; + } + + public void put(int key, int value) { + DLinkedNode node = map.get(key); + if (node == null) { + DLinkedNode dLinkedNode = new DLinkedNode(key, value); + map.put(key, dLinkedNode); + + // 设置 头节点 + addToHead(dLinkedNode); + + ++size; + if (size > capacity) { + map.remove(removeTail().key); + --size; + } + } else { + node.value = value; + moveToHead(node); + } + } + + private DLinkedNode removeTail() { + DLinkedNode pre = tail.pre; + removeNode(pre); + return pre; + } + + private void removeNode(DLinkedNode node) { + node.pre.next = node.next; + node.next.pre = node.pre; + } + + private void addToHead(DLinkedNode dLinkedNode) { + dLinkedNode.pre = head; + dLinkedNode.next = head.next; + + head.next.pre = dLinkedNode; + head.next = dLinkedNode; + } + + private void moveToHead(DLinkedNode dLinkedNode) { + removeNode(dLinkedNode); + addToHead(dLinkedNode); + } + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/Node.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/Node.java new file mode 100644 index 0000000..417f73d --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/Node.java @@ -0,0 +1,21 @@ +package com.leosanqing.leetcode.medium.tree; + +public class Node { + public int val; + public Node left; + public Node right; + public Node next; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, Node _left, Node _right, Node _next) { + val = _val; + left = _left; + right = _right; + next = _next; + } +} \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/TreeNode.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/TreeNode.java new file mode 100644 index 0000000..ad4431f --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/TreeNode.java @@ -0,0 +1,17 @@ +package com.leosanqing.leetcode.medium.tree; + +/** + * @author zhuerchong + */ +public class TreeNode { + public int val; + public TreeNode left; + public TreeNode right; + public TreeNode() {} + public TreeNode(int val) { this.val = val; } + public TreeNode(int val, TreeNode left, TreeNode right) { + this.val = val; + this.left = left; + this.right = right; + } +} \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_102_binary_tree_level_order_traversal.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_102_binary_tree_level_order_traversal.java new file mode 100644 index 0000000..a11fa00 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_102_binary_tree_level_order_traversal.java @@ -0,0 +1,65 @@ +package com.leosanqing.leetcode.medium.tree; + +import com.alibaba.fastjson.JSON; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/27 下午4:07 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * ` Given a binary tree, return the level order traversal of its nodes' values. + * ` (ie, from left to right, level by level). + * ` For example: Given binary tree [3,9,20,null,null,15,7], + * ` 3 + * ` / \ + * ` 9 20 + * ` / \ + * ` 15 7 + * ` return its level order traversal as: + * ` [ + * ` [3], + * ` [9,20], + * ` [15,7] + * ` ] + * @Version: 1.0 + */ +public class _102_binary_tree_level_order_traversal { + public static void main(String[] args) { + TreeNode treeNode = new TreeNode(3); + treeNode.left = new TreeNode(9); + treeNode.right = new TreeNode(20); + treeNode.right.left = new TreeNode(1); + treeNode.right.right = new TreeNode(7); + + System.out.println(JSON.toJSONString(levelOrder(treeNode))); + } + + public static List> levelOrder(TreeNode root) { + List> answer = new ArrayList<>(); + + backtrace(answer, 0, root); + return answer; + } + + private static void backtrace(List> answer, int depth, TreeNode node) { + if (node == null) { + return; + } + + if (depth >= answer.size()) { + List list = new ArrayList<>(); + list.add(node.val); + answer.add(list); + } else { + answer.get(depth).add(node.val); + } + + backtrace(answer, depth + 1, node.left); + backtrace(answer, depth + 1, node.right); + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_103_binary_tree_zigzag_level_order_traversal.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_103_binary_tree_zigzag_level_order_traversal.java new file mode 100644 index 0000000..2b4075a --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_103_binary_tree_zigzag_level_order_traversal.java @@ -0,0 +1,93 @@ +package com.leosanqing.leetcode.medium.tree; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/27 下午5:29 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * ` Given a binary tree, return the zigzag level order traversal of its nodes' values. + * ` (ie, from left to right, then right to left for the next level and alternate between). + * ` 给定一棵二叉树,返回其节点值的之字形级别顺序遍历。 + * ` (即,从左到右,然后从右到左进入下一个级别,并在之间切换)。 + * ` For example: + * ` Given binary tree [3,9,20,null,null,15,7], + * ` 3 + * ` / \ + * ` 9 20 + * ` / \ + * ` 15 7 + * ` return its zigzag level order traversal as: + * ` [ + * ` [3], + * ` [20,9], + * ` [15,7] + * ` ] + * @Version: 1.0 + */ +public class _103_binary_tree_zigzag_level_order_traversal { + public List> zigzagLevelOrder(TreeNode root) { + if (root == null) { + return new ArrayList<>(); + } + List> answer = new ArrayList<>(); + answer.add(Arrays.asList(root)); + + List> res = new ArrayList<>(); + res.add(Arrays.asList(root.val)); + findAnswer(answer, new ArrayList<>(), res, new ArrayList<>()); + return res; + } + + /** + * 这个就简单的改造一下 102的解法,加一个条件判断 + * @param lists + * @param list + * @param answer + * @param temp + */ + private static void findAnswer(List> lists, List list, List> answer, + List temp) { + boolean flag = true; + while (true) { + List treeNodes = lists.get(lists.size() - 1); + for (int i = treeNodes.size() - 1; i >= 0; i--) { + if (flag) { + if (treeNodes.get(i).right != null) { + list.add(treeNodes.get(i).right); + temp.add(treeNodes.get(i).right.val); + } + if (treeNodes.get(i).left != null) { + list.add(treeNodes.get(i).left); + temp.add(treeNodes.get(i).left.val); + } + } else { + if (treeNodes.get(i).left != null) { + list.add(treeNodes.get(i).left); + temp.add(treeNodes.get(i).left.val); + } + + if (treeNodes.get(i).right != null) { + list.add(treeNodes.get(i).right); + temp.add(treeNodes.get(i).right.val); + } + } + + } + + + if (list.isEmpty()) { + return; + } + lists.add(new ArrayList<>(list)); + answer.add(new ArrayList<>(temp)); + list.clear(); + temp.clear(); + + flag = !flag; + } + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_105_construct_binary_tree_from_preorder_and_inorder_traversal.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_105_construct_binary_tree_from_preorder_and_inorder_traversal.java new file mode 100644 index 0000000..c2dd3ea --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_105_construct_binary_tree_from_preorder_and_inorder_traversal.java @@ -0,0 +1,74 @@ +package com.leosanqing.leetcode.medium.tree; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Author: rtliu + * @Date: 2020/7/28 下午7:29 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * ` Given preorder and inorder traversal of a tree, construct the binary tree. + * ` Note: You may assume that duplicates do not exist in the tree. + * ` For example, given preorder = [3,9,20,15,7] inorder = [9,3,15,20,7] + * ` Return the following binary tree: + * ` + * ` 给定一棵树的前序和有序遍历,构造二叉树。 + * ` 注意:您可以假定树中不存在重复项。 + * ` 例如,给定的先序遍历 = [3,9,20,15,7] 中序遍历 = [9,3,15,20,7] + * ` 3 + * ` / \ + * ` 9 20 + * ` / \ + * ` 15 7 + * @Version: 1.0 + */ +public class _105_construct_binary_tree_from_preorder_and_inorder_traversal { + + public static void main(String[] args) { + int[] preorder = {3, 9, 2, 11, 14, 8, 20, 15, 16, 7, 22}; + int[] inorder = {11, 2, 14, 9, 8, 3, 16, 15, 20, 22, 7}; + + +// TreeNode treeNode1 = backTrace(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1); + + + TreeNode treeNode = buildTree(preorder, inorder); + + + } + + private static Map indexMap; + + public static TreeNode buildTree(int[] preorder, int[] inorder) { + + // 构造哈希映射,帮助我们快速定位根节点 + indexMap = new HashMap<>(preorder.length * 2); + for (int i = 0; i < preorder.length; i++) { + indexMap.put(inorder[i], i); + } + return backtrace(preorder, 0, preorder.length - 1, inorder, 0, preorder.length - 1); + } + + private static TreeNode backtrace(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd) { + if (preStart > preEnd) { + return null; + } + + // 在中序遍历中定位根节点 + int inorderRoot = indexMap.get(preorder[preStart]); + + // 先把根节点建立出来 + TreeNode root = new TreeNode(preorder[preStart]); + // 得到左子树中的节点数目 + int sizeLeftSubtree = inorderRoot - inStart; + // 递归地构造左子树,并连接到根节点 + // 先序遍历中「从 左边界+1 开始的 sizeLeftSubtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素 + root.left = backtrace(preorder, preStart + 1, preStart + sizeLeftSubtree, inorder, inStart, inorderRoot - 1); + // 递归地构造右子树,并连接到根节点 + // 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素 + root.right = backtrace(preorder, preStart + sizeLeftSubtree + 1, preEnd, inorder, inorderRoot + 1, inEnd); + + return root; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_106_construct_binary_tree_from_inorder_and_postorder_traversal.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_106_construct_binary_tree_from_inorder_and_postorder_traversal.java new file mode 100644 index 0000000..74dac3c --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_106_construct_binary_tree_from_inorder_and_postorder_traversal.java @@ -0,0 +1,61 @@ +package com.leosanqing.leetcode.medium.tree; + +/** + * @Author: rtliu + * @Date: 2020/7/29 上午10:43 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * ` Given inorder and postorder traversal of a tree, construct the binary tree. + * ` Note: You may assume that duplicates do not exist in the tree. + * ` For example, + * ` given inorder = [9,3,15,20,7] postorder = [9,15,7,20,3] + * ` Return the following binary tree: + * ` 3 + * ` / \ + * ` 9 20 + * ` / \ + * ` 15 7 + * @Version: 1.0 + */ +public class _106_construct_binary_tree_from_inorder_and_postorder_traversal { + + public static void main(String[] args) { + + + } + + public TreeNode buildTree(int[] inorder, int[] postorder) { + + return backTrace(inorder, 0, inorder.length - 1, postorder, postorder.length - 1); + } + + /** + * 这个跟 之前 105题解法思路一样,只不过顺序不一样 + * + * @param inorder + * @param inStart + * @param inEnd + * @param postorder + * @param postEnd + * @return + */ + private static TreeNode backTrace(int[] inorder, int inStart, int inEnd, int[] postorder, int postEnd) { + + if (postEnd < 0 || inStart > inEnd) { + return null; + } + + TreeNode root = new TreeNode(postorder[postEnd]); + + int inIndex = 0; + for (int i = inEnd; i >= inStart; i--) { + if (root.val == inorder[i]) { + inIndex = i; + } + } + + root.right = backTrace(inorder, inIndex + 1, inEnd, postorder, postEnd - 1); + root.left = backTrace(inorder, inStart, inIndex - 1, postorder, postEnd + inIndex - inEnd - 1); + return root; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_109_convert_sorted_list_to_binary_search_tree.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_109_convert_sorted_list_to_binary_search_tree.java new file mode 100644 index 0000000..8e3ff06 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_109_convert_sorted_list_to_binary_search_tree.java @@ -0,0 +1,50 @@ +package com.leosanqing.leetcode.medium.tree; + +import com.leosanqing.leetcode.medium.list.ListNode; + +/** + * @Author: rtliu + * @Date: 2020/7/30 上午9:56 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * ` Given a singly linked list where elements are sorted in ascending order, convert it to a height + * balanced BST. + * ` For this problem, + * ` a height-balanced binary tree is defined as a binary tree in which + * ` the depth of the two subtrees of every node never differ by more than 1. + * ` Example: + * ` Given the sorted linked list: [-10,-3,0,5,9], + * ` One possible answer is: [0,-3,9,-10,null,5], + * ` which represents the following height balanced BST: + * ` 0 + * ` / \ + * ` -3 9 + * ` / / + * ` -10 5 + * @Version: 1.0 + */ +public class _109_convert_sorted_list_to_binary_search_tree { + + + public TreeNode sortedListToBST(ListNode head) { + return backTrace(head, null); + } + + private static TreeNode backTrace(ListNode head, ListNode tail) { + ListNode slow = head; + ListNode fast = head; + if (head == tail) { + return null; + } + + while (fast != tail && fast.next != tail) { + fast = fast.next.next; + slow = slow.next; + } + + TreeNode root = new TreeNode(slow.val); + root.left = backTrace(head, slow); + root.right = backTrace(slow.next, tail); + return root; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_112_path_sum.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_112_path_sum.java new file mode 100644 index 0000000..5d432ac --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_112_path_sum.java @@ -0,0 +1,54 @@ +package com.leosanqing.leetcode.medium.tree; + +/** + * @Author: rtliu + * @Date: 2020/7/30 下午5:24 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * Given a binary tree and a sum, + * determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum. + * Note: A leaf is a node with no children. + * Example: + * Given the below binary tree and sum = 22, + * 5 + * / \ + * 4 8 + * / / \ + * 11 13 4 + * / \ \ + * 7 2 1 return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22. + * @Version: 1.0 + */ +public class _112_path_sum { + public static void main(String[] args) { + TreeNode treeNode = new TreeNode(5); + treeNode.left = new TreeNode(4); + treeNode.right = new TreeNode(8); + treeNode.left.left = new TreeNode(11); + treeNode.right.left = new TreeNode(13); + treeNode.right.right = new TreeNode(4); + treeNode.left.left.left = new TreeNode(7); + treeNode.left.left.right = new TreeNode(2); + treeNode.right.right.right = new TreeNode(1); + + System.out.println(hasPathSum(treeNode, 22)); + } + + public static boolean hasPathSum(TreeNode root, int sum) { + + + return backTrace(root, sum); + } + + private static boolean backTrace(TreeNode root, int sum) { + if (root == null) { + return false; + } + if (root.left == null && root.right == null && root.val == sum) { + return true; + } + + return backTrace(root.left, sum-root.val) || backTrace(root.right, sum-root.val); + + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_113_path_sumII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_113_path_sumII.java new file mode 100644 index 0000000..91f7c34 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_113_path_sumII.java @@ -0,0 +1,64 @@ +package com.leosanqing.leetcode.medium.tree; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @Author: rtliu + * @Date: 2020/7/31 上午11:26 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * Given a binary tree and a sum, + * find all root-to-leaf paths where each path's sum equals the given sum. + * Note: A leaf is a node with no children. + * Example: + * Given the below binary tree and sum = 22, + * 5 + * / \ 4 8 / / \ 11 13 4 / \ / \ 7 2 5 1 Return: [ [5,4,11,2], [5,8,4,5] ] + * @Version: 1.0 + */ +public class _113_path_sumII { + public static void main(String[] args) { + TreeNode treeNode = new TreeNode(5); + treeNode.left = new TreeNode(4); + treeNode.right = new TreeNode(8); + treeNode.left.left = new TreeNode(11); + treeNode.right.left = new TreeNode(13); + treeNode.right.right = new TreeNode(4); + treeNode.left.left.left = new TreeNode(7); + treeNode.left.left.right = new TreeNode(2); + treeNode.right.right.right = new TreeNode(1); + treeNode.right.right.left = new TreeNode(5); + + pathSum(treeNode, 22); + } + + public static List> pathSum(TreeNode root, int sum) { + + if (root == null) { + return new ArrayList<>(); + } + + List> answer = new ArrayList<>(); + backTrace(answer, new ArrayList<>(), root, sum); + return answer; + } + + private static void backTrace(List> answer, List list, TreeNode root, int sum) { + if (root == null) { + return; + } + list.add(root.val); + + if (root.left == null && root.right == null && sum == root.val) { + answer.add(new ArrayList<>(list)); + list.remove(list.size() - 1); + return; + } + + backTrace(answer, list, root.left, sum - root.val); + backTrace(answer, list, root.right, sum - root.val); + list.remove(list.size() - 1); + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_114_flatten_binary_tree_to_linked_list.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_114_flatten_binary_tree_to_linked_list.java new file mode 100644 index 0000000..3a72eab --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_114_flatten_binary_tree_to_linked_list.java @@ -0,0 +1,55 @@ +package com.leosanqing.leetcode.medium.tree; + +/** + * @Author: rtliu + * @Date: 2020/7/31 下午2:03 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * ` Given a binary tree, flatten it to a linked list in-place. + * ` For example, given the following tree: + * ` 1 + * ` / \ + * ` 2 5 + * ` / \ \ + * ` 3 4 6 + * ` The flattened tree should look like: + * ` 1 + * ` \ + * ` 2 + * ` \ + * ` 3 + * ` \ + * ` 4 + * ` \ + * ` 5 + * ` \ + * ` 6 + * @Version: 1.0 + */ +public class _114_flatten_binary_tree_to_linked_list { + + public void flatten(TreeNode root) { + if (root == null) { + return; + } + + TreeNode left = root.left; + TreeNode right = root.right; + + right.left = null; + + flatten(left); + flatten(right); + + root.right = left; + + // 找到 左子树 最后一个节点,将其连接上 + TreeNode cur = root; + while (cur.right != null) { + cur = cur.right; + } + cur.right = right; + + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_116_populating_next_right_pointers_in_each_node.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_116_populating_next_right_pointers_in_each_node.java new file mode 100644 index 0000000..c1ff4e8 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_116_populating_next_right_pointers_in_each_node.java @@ -0,0 +1,64 @@ +package com.leosanqing.leetcode.medium.tree; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.Stack; + +/** + * @Author: rtliu + * @Date: 2020/7/31 下午2:50 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * ` https://leetcode.com/problems/populating-next-right-pointers-in-each-node/ + * @Version: 1.0 + */ +public class _116_populating_next_right_pointers_in_each_node { + + public static void main(String[] args) { + Node treeNode = new Node(1); + treeNode.left = new Node(2); + treeNode.right = new Node(3); + treeNode.left.left = new Node(4); + treeNode.left.right = new Node(5); + treeNode.right.left = new Node(6); + treeNode.right.right = new Node(7); + + connect(treeNode); + } + + public static Node connect(Node root) { + + if (root == null) { + return null; + } + Queue queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + + int queueSize = queue.size() - 1; + Node node = queue.poll(); + + // because of perfect binary tree + if (node == null) { + break; + } + + for (int i = 0; i <= queueSize; i++) { + queue.offer(node.left); + queue.offer(node.right); + + if (i == queueSize) { + node.next = null; + break; + } + + Node temp = queue.poll(); + node.next = temp; + node = temp; + } + } + return root; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_117_populating_next_right_pointers_in_each_nodeII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_117_populating_next_right_pointers_in_each_nodeII.java new file mode 100644 index 0000000..325a64a --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_117_populating_next_right_pointers_in_each_nodeII.java @@ -0,0 +1,52 @@ +package com.leosanqing.leetcode.medium.tree; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * @Author: rtliu + * @Date: 2020/7/31 下午3:59 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * ` https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/ + * @Version: 1.0 + */ +public class _117_populating_next_right_pointers_in_each_nodeII { + public static Node connect(Node root) { + + if (root == null) { + return null; + } + Queue queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + + int queueSize = queue.size() - 1; + Node node = queue.poll(); + + // because of perfect binary tree + if (node == null) { + break; + } + + for (int i = 0; i <= queueSize; i++) { + if (node.left != null) { + queue.offer(node.left); + } + if (node.right != null) { + queue.offer(node.right); + } + + if (i == queueSize) { + node.next = null; + break; + } + + Node temp = queue.poll(); + node.next = temp; + node = temp; + } + } + return root; + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_129_sum_root_to_leaf_numbers.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_129_sum_root_to_leaf_numbers.java new file mode 100644 index 0000000..8df008e --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_129_sum_root_to_leaf_numbers.java @@ -0,0 +1,77 @@ +package com.leosanqing.leetcode.medium.tree; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/8/3 上午11:26 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * ` Given a binary tree containing digits from 0-9 only, + * ` each root-to-leaf path could represent a number. + * ` An example is the root-to-leaf path 1->2->3 which represents the number 123. + * ` Find the total sum of all root-to-leaf numbers. + * ` Note: A leaf is a node with no children. + * ` Example: + * ` Input: [1,2,3] + * ` 1 + * ` / \ + * ` 2 3 + * ` Output: 25 + * ` Explanation: + * ` The root-to-leaf path 1->2 represents the number 12. + * ` The root-to-leaf path 1->3 represents the number 13. + * ` Therefore, sum = 12 + 13 = 25. + * ` Example 2: + * ` Input: [4,9,0,5,1] + * ` 4 + * ` / \ + * ` 9 0 + * ` / \ + * ` 5 1 + * ` Output: 1026 + * ` Explanation: + * ` The root-to-leaf path 4->9->5 represents the number 495. + * ` The root-to-leaf path 4->9->1 represents the number 491. + * ` The root-to-leaf path 4->0 represents the number 40. Therefore, sum = 495 + 491 + 40 = 1026. + * @Version: 1.0 + */ +public class _129_sum_root_to_leaf_numbers { + + public static void main(String[] args) { + TreeNode treeNode = new TreeNode(1); + treeNode.right = new TreeNode(3); + treeNode.left = new TreeNode(2); + treeNode.left.left = new TreeNode(4); + treeNode.left.right = new TreeNode(5); + + sumNumbers(treeNode); + } + + public static int sumNumbers(TreeNode root) { + List list = new ArrayList<>(); + backTrace(root, 0, list); + int sum = 0; + for (Integer integer : list) { + sum += integer; + } + return sum; + } + + + private static void backTrace(TreeNode root, int val, List list) { + if(root == null){ + return; + } + val = val * 10 +root.val; + + if(root.left == null && root.right == null){ + + list.add(val); + return; + } + backTrace(root.left, val, list); + backTrace(root.right, val, list); + } +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_208_implementTrie.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_208_implementTrie.java new file mode 100644 index 0000000..f5dd11f --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_208_implementTrie.java @@ -0,0 +1,162 @@ +package com.leosanqing.leetcode.medium.tree; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Author: rtliu + * @Date: 2020/6/17 上午10:33 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 实现 一个 Trie + * Implement a trie with insert, search, and startsWith methods. + * + * Example: + * + * Trie trie = new Trie(); + * + * trie.insert("apple"); + * trie.search("apple"); // returns true + * trie.search("app"); // returns false + * trie.startsWith("app"); // returns true + * trie.insert("app"); + * trie.search("app"); // returns true + * + * + * 很多人可能不了解 Trie + * 在计算机科学中,trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。 + * 与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。 + * 一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。 + * 一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。 + * @Version: 1.0 + */ +public class _208_implementTrie { + + public static void main(String[] args) { + Trie trie = new Trie(); + trie.insert("apple"); + boolean apple = trie.search("apple"); + System.out.println(apple); + } +} + +class TrieNode{ + private final Map children = new HashMap<>(); + + public boolean isEnd = false; + + public void putChildIfAbsent(char c){ + // 直接调用 HashMap 的代码,创建 子节点 + children.putIfAbsent(c,new TrieNode()); + } + + public TrieNode getChildren(char c){ + return children.get(c); + } +} + +class Trie { + + + TrieNode root = new TrieNode(); + + /** Initialize your data structure here. */ + public Trie() { + + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode curr = root; + for (char ch : word.toCharArray()) { + curr.putChildIfAbsent(ch); + curr = curr.getChildren(ch); + } + curr.isEnd = true; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode curr = root; + for (char ch : word.toCharArray()) { + curr = curr.getChildren(ch); + if (curr == null) { + return false; + } + } + return curr.isEnd; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode curr = root; + for (char c : prefix.toCharArray()) { + curr = curr.getChildren(c); + if (curr == null) { + return false; + } + } + + return true; + } +} + + +/** + * 使用 数组实现 + */ +class Trie2 { + + + TrieNode2 root = new TrieNode2(); + + /** Initialize your data structure here. */ + public Trie2() { + + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode2 curr = root; + for (char ch : word.toCharArray()) { + if(curr.children[ch - 'a'] != null){ + curr = curr.children[ch - 'a']; + }else{ + curr.children[ch - 'a'] = new TrieNode2(); + } + } + curr.isEnd = true; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode2 curr = root; + for (char ch : word.toCharArray()) { + curr = curr.children[ch - 'a']; + if (curr == null) { + return false; + } + } + return curr.isEnd; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode2 curr = root; + for (char c : prefix.toCharArray()) { + curr = curr.children[c - 'a']; + if (curr == null) { + return false; + } + } + return true; + } +} + +class TrieNode2{ + /** 因为有26个字符 */ + public TrieNode2[] children = new TrieNode2[26]; + + public boolean isEnd = false; + + +} \ No newline at end of file diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_211_addAndSearchWord_dataStructureDesign.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_211_addAndSearchWord_dataStructureDesign.java new file mode 100644 index 0000000..45fc7ac --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_211_addAndSearchWord_dataStructureDesign.java @@ -0,0 +1,83 @@ +package com.leosanqing.leetcode.medium.tree; + +/** + * @Author: rtliu + * @Date: 2020/6/28 下午3:58 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: Design a data structure that supports the following two operations: + * void addWord(word) bool search(word) search(word) can search a literal word + * or a regular expression string containing only letters a-z or .. A . means it can represent any one letter. + * Example: + * addWord("bad") + * addWord("dad") + * addWord("mad") + * search("pad") -> false + * search("bad") -> true + * search(".ad") -> true + * search("b..") -> true + * @Version: 1.0 + */ +public class _211_addAndSearchWord_dataStructureDesign { + +} + +class WordDictionary { + TrieNode1 root = new TrieNode1(); + + /** Initialize your data structure here. */ + public WordDictionary() { + + } + + /** Adds a word into the data structure. */ + public void addWord(String word) { + TrieNode1 curr = root; + if(word != null && word.length() > 0){ + + for (char c : word.toCharArray()) { + if (curr.children[c - 'a'] == null) { + curr.children[c - 'a'] = new TrieNode1(); + } + curr = curr.children[c -'a']; + + } + curr.isEnd = true; + + } + } + + /** Returns if the word is in the data structure. + * A word could contain the dot character '.' to represent any one letter. */ + public boolean search(String word) { + return helper(word, 0 , root); + } + + + private boolean helper(String word, int index, TrieNode1 curr){ + if(index >= word.length()){ + return curr.isEnd; + } + char c = word.charAt(index); + + if('.' == c){ + for (int i = 0; i < curr.children.length; i++) { + // 当出现 . 的时候,递归遍历 + if(curr.children[i] != null && helper(word, index+1, curr.children[i])){ + return true; + } + } + return false; + }else { + return (curr.children[c - 'a'] != null) && helper(word,index +1, curr.children[c - 'a']); + } + } +} + +class TrieNode1 { + TrieNode1[] children = new TrieNode1[26]; + + boolean isEnd = false; + +} + + diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_257_binaryTreePaths.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_257_binaryTreePaths.java new file mode 100644 index 0000000..15f7951 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_257_binaryTreePaths.java @@ -0,0 +1,57 @@ +package com.leosanqing.leetcode.medium.tree; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/6/22 下午3:08 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: Given a binary tree, return all root-to-leaf paths. + * @Version: 1.0 + *

+ *

+ *

+ * Example: + *

+ * Input: + *

+ * 1 + * / \ + * 2 3 + * \ + * 5 + *

+ * Output: ["1->2->5", "1->3"] + *

+ * Explanation: All root-to-leaf paths are: 1->2->5, 1->3 + */ +public class _257_binaryTreePaths { + + public List binaryTreePaths(TreeNode root) { + List strings = new ArrayList<>(); + + if (root != null) { + searchBT(root,"",strings); + } + + + return strings; + } + + private void searchBT(TreeNode node, String path, List list) { + if (node.left == null && node.right == null) { + list.add(path + node.val); + + } + if (node.right != null) { + searchBT(node.right, path + node.val + "->", list); + } + if(node.left != null){ + searchBT(node.left, path + node.val + "->", list); + } + } + +} + + diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_94_binary_tree_inorder_traversal.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_94_binary_tree_inorder_traversal.java new file mode 100644 index 0000000..61ace0b --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_94_binary_tree_inorder_traversal.java @@ -0,0 +1,61 @@ +package com.leosanqing.leetcode.medium.tree; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * @Author: rtliu + * @Date: 2020/7/24 上午9:49 + * @Package: com.leosanqing.leetcode.medium.list + * @Description: 1 + * ` Given a binary tree, return the inorder traversal of its nodes' values. + * ` 给定一个二叉树,返回其节点值的有序遍历。 + * ` Example: + * ` Input: + * ` [1,null,2,3] + * ` 1 + * ` \ + * ` 2 + * ` / + * ` 3 + * ` Output: [1,3,2] + * @Version: 1.0 + */ +public class _94_binary_tree_inorder_traversal { + + // 不使用递归 + public List inorderTraversal(TreeNode root) { + List list = new ArrayList<>(); + + Stack stack = new Stack<>(); + TreeNode cur = root; + while (cur != null || !stack.isEmpty()) { + while (cur != null) { + stack.push(cur); + cur = cur.left; + } + + cur = stack.pop(); + list.add(cur.val); + cur = cur.right; + } + + return list; + + } + + + // 使用递归 + private void backTrace(List list, TreeNode node){ + + if(node == null){ + return; + } + backTrace(list, node.left); + list.add(node.val); + backTrace(list, node.right); + + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_95_unique_binary_search_treesII.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_95_unique_binary_search_treesII.java new file mode 100644 index 0000000..f8f7f63 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_95_unique_binary_search_treesII.java @@ -0,0 +1,84 @@ +package com.leosanqing.leetcode.medium.tree; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/24 上午10:29 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * ` Given an integer n, generate all structurally unique BST's (binary search trees) that store values 1 .. + * . n. + * ` Example: + * ` Input: 3 + * ` Output: + * ` [ + * ` [1,null,3,2], + * ` [3,2,null,1], + * ` [3,1,null,null,2], + * ` [2,1,3], + * ` [1,null,2,null,3] + * ` ] + * ` Explanation: + * ` The above output corresponds to the 5 unique BST's shown below: + * ` 1 3 3 2 1 + * ` \ / / / \ \ + * ` 3 2 1 1 3 2 + * ` / / \ \ + * ` 2 1 2 3 + * @Version: 1.0 + */ +public class _95_unique_binary_search_treesII { + + public static void main(String[] args) { + generateTrees(8); + } + + public static List generateTrees(int n) { + + List[] res = new List[n + 1]; + res[0] = new ArrayList<>(); + if (n == 0) { + return res[0]; + } + res[0].add(null); + res[1] = new ArrayList<>(); + res[1].add(new TreeNode(1)); + for (int i = 2; i <= n; i++) { + res[i] = new ArrayList<>(); + for (int j = 1; j <= i; j++) { + for (TreeNode nodeL : res[j - 1]) { + for (TreeNode nodeR : res[i - j]) { + TreeNode node = new TreeNode(j); + node.left = nodeL; + node.right = clone(nodeR, j); + res[i].add(node); + } + } + } + } + return res[n]; + } + + + static TreeNode clone(TreeNode node, int offset) { + if (node == null) { + return null; + } + TreeNode newNode = new TreeNode(node.val + offset); + newNode.left = clone(node.left, offset); + newNode.right = clone(node.right, offset); + return newNode; + } + + + private void backTrace(List result, TreeNode cur, TreeNode root, int position, int max) { + if (position == max) { + result.add(root); + } + + + } + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_96_unique_binary_search_trees.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_96_unique_binary_search_trees.java new file mode 100644 index 0000000..22351d9 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_96_unique_binary_search_trees.java @@ -0,0 +1,55 @@ +package com.leosanqing.leetcode.medium.tree; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Author: rtliu + * @Date: 2020/7/24 上午10:29 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * ` Given an integer n, generate all structurally unique BST's (binary search trees) that store values 1 .. + * . n. + * ` Example: + * ` Input: 3 + * ` Output: 5 + * ` + * ` Explanation: + * ` The above output corresponds to the 5 unique BST's shown below: + * ` 1 3 3 2 1 + * ` \ / / / \ \ + * ` 3 2 1 1 3 2 + * ` / / \ \ + * ` 2 1 2 3 + * @Version: 1.0 + */ +public class _96_unique_binary_search_trees { + + public static void main(String[] args) { + generateTrees(3); + } + + + /** + * 解释 :https://leetcode.com/problems/unique-binary-search-trees/discuss/31666/DP-Solution-in-6-lines-with + * -explanation.-F(i-n)-G(i-1)-*-G(n-i) + * + * @param n + * @return + */ + public static int generateTrees(int n) { + int[] res = new int[n + 1]; + + res[0] = res[1] = 1; + + for (int i = 2; i <= n; i++) { + for (int j = 1; j <= i; j++) { + res[i] += res[j - 1] * res[i - j]; + } + } + + return res[n]; + } + + +} diff --git a/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_98_validate_binary_search_tree.java b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_98_validate_binary_search_tree.java new file mode 100644 index 0000000..f96d6b5 --- /dev/null +++ b/java-note-algorithm/src/main/java/com/leosanqing/leetcode/medium/tree/_98_validate_binary_search_tree.java @@ -0,0 +1,71 @@ +package com.leosanqing.leetcode.medium.tree; + +/** + * @Author: rtliu + * @Date: 2020/7/27 上午10:31 + * @Package: com.leosanqing.leetcode.medium.tree + * @Description: 1 + * ` Given a binary tree, determine if it is a valid binary search tree (BST). + * ` Assume a BST is defined as follows: + * ` The left subtree of a node contains only nodes with keys less than the node's key. + * ` The right subtree of a node contains only nodes with keys greater than the node's key. + * ` Both the left and right subtrees must also be binary search trees. + * ` Example 1: + * ` 2 + * ` / \ + * ` 1 3 + * ` Input: [2,1,3] + * ` Output: true + * ` Example 2: 5 + * ` / \ + * ` 1 4 + * ` / \ + * ` 3 6 + * ` Input: [5,1,4,null,null,3,6] + * ` Output: false + * ` Explanation: The root node's value is 5 but its right child's value is 4. + * @Version: 1.0 + */ +public class _98_validate_binary_search_tree { + public static void main(String[] args) { + TreeNode treeNode = new TreeNode(2); + treeNode.left = new TreeNode(1); + treeNode.right = new TreeNode(3); + + System.out.println(isValidBST(treeNode)); + } + + public static boolean isValidBST(TreeNode root) { + return backTrace(root, null, null); + + } + + // 又是递归 + private static boolean backTrace(TreeNode treeNode, Integer min, Integer max) { + if (treeNode == null) { + return true; + } + + // 左子树一定小于父节点,右子树一定大于父节点 + if ((max != null && treeNode.val >= max) + || (min != null && treeNode.val <= min)) { + return false; + } + return backTrace(treeNode.left, min, treeNode.val) && backTrace(treeNode.right, treeNode.val, max); + } + + private static boolean backtrace(TreeNode treeNode, Integer max, Integer min) { + if (treeNode == null) { + return true; + } + + if ( + (max != null && treeNode.val >= max) + || (min != null && treeNode.val <= min) + ) { + return false; + } + return backtrace(treeNode.left, max, treeNode.val)&&backtrace(treeNode.right, treeNode.val, min); + } + +} diff --git a/java-note-algorithm/target/classes/META-INF/java-note-algorithm.kotlin_module b/java-note-algorithm/target/classes/META-INF/java-note-algorithm.kotlin_module new file mode 100644 index 0000000..a49347a Binary files /dev/null and b/java-note-algorithm/target/classes/META-INF/java-note-algorithm.kotlin_module differ diff --git a/knife4j-demo/.idea/$CACHE_FILE$ b/knife4j-demo/.idea/$CACHE_FILE$ new file mode 100644 index 0000000..6cb8985 --- /dev/null +++ b/knife4j-demo/.idea/$CACHE_FILE$ @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/knife4j-demo/.idea/.gitignore b/knife4j-demo/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/knife4j-demo/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/knife4j-demo/.idea/compiler.xml b/knife4j-demo/.idea/compiler.xml new file mode 100644 index 0000000..8adfac0 --- /dev/null +++ b/knife4j-demo/.idea/compiler.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/knife4j-demo/.idea/inspectionProfiles/Project_Default.xml b/knife4j-demo/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..6560a98 --- /dev/null +++ b/knife4j-demo/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,36 @@ + + + + \ No newline at end of file diff --git a/knife4j-demo/.idea/jarRepositories.xml b/knife4j-demo/.idea/jarRepositories.xml new file mode 100644 index 0000000..2d9362f --- /dev/null +++ b/knife4j-demo/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/knife4j-demo/.idea/misc.xml b/knife4j-demo/.idea/misc.xml new file mode 100644 index 0000000..3ccb27b --- /dev/null +++ b/knife4j-demo/.idea/misc.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/knife4j-demo/.idea/vcs.xml b/knife4j-demo/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/knife4j-demo/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/knife4j-demo/knife4j-demo.iml b/knife4j-demo/knife4j-demo.iml new file mode 100644 index 0000000..78b2cc5 --- /dev/null +++ b/knife4j-demo/knife4j-demo.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/knife4j-demo/pom.xml b/knife4j-demo/pom.xml new file mode 100644 index 0000000..c3694d6 --- /dev/null +++ b/knife4j-demo/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + + org.example + knife4j-demo + 1.0-SNAPSHOT + + + + + + com.github.xiaoymin + knife4j-spring-boot-starter + + 2.0.2 + + + + org.springframework.boot + spring-boot-starter-web + 2.2.5.RELEASE + + + \ No newline at end of file diff --git a/knife4j-demo/src/main/java/com/leosanqing/demo/App.java b/knife4j-demo/src/main/java/com/leosanqing/demo/App.java new file mode 100644 index 0000000..72af763 --- /dev/null +++ b/knife4j-demo/src/main/java/com/leosanqing/demo/App.java @@ -0,0 +1,18 @@ +package com.leosanqing.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @Author: rtliu + * @Date: 2020/6/5 上午9:37 + * @Package: com.leosanqing.demo + * @Description: 启动类 + * @Version: 1.0 + */ +@SpringBootApplication +public class App { + public static void main(String[] args) { + SpringApplication.run(App.class); + } +} diff --git a/knife4j-demo/src/main/java/com/leosanqing/demo/config/SwaggerConfiguration.java b/knife4j-demo/src/main/java/com/leosanqing/demo/config/SwaggerConfiguration.java new file mode 100644 index 0000000..3177333 --- /dev/null +++ b/knife4j-demo/src/main/java/com/leosanqing/demo/config/SwaggerConfiguration.java @@ -0,0 +1,53 @@ +package com.leosanqing.demo.config; + +import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@Configuration +@EnableSwagger2 +@EnableKnife4j +@Import(BeanValidatorPluginsConfiguration.class) +public class SwaggerConfiguration { + + + @Bean(value = "defaultApi2") + public Docket defaultApi2() { + Docket docket=new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + //分组名称 + .groupName("2.X版本") + .select() + //这里指定Controller扫描包路径 + .apis(RequestHandlerSelectors.basePackage("com.leosanqing.demo.controller")) + .paths(PathSelectors.any()) + .build(); + return docket; + } + + + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("knife4j-demo接口API") // 标题 + .contact(new Contact("leosanqing", + "https://github.com/leosanqing/Java-Notes", + "stormleo@qq.com")) // 联系人 + .version("1.0.1") + .termsOfServiceUrl("https://github.com/leosanqing/Java-Notes") // 网站地址 + .description("knife4j-demo API") // 描述 + .build(); + + + } +} \ No newline at end of file diff --git a/knife4j-demo/src/main/java/com/leosanqing/demo/controller/TestController.java b/knife4j-demo/src/main/java/com/leosanqing/demo/controller/TestController.java new file mode 100644 index 0000000..c42d2e2 --- /dev/null +++ b/knife4j-demo/src/main/java/com/leosanqing/demo/controller/TestController.java @@ -0,0 +1,34 @@ +package com.leosanqing.demo.controller; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * @Author: rtliu + * @Date: 2020/6/5 上午9:33 + * @Package: com.leosanqing.demo.controller + * @Description: 测试 + * @Version: 1.0 + */ +@RestController +@Api(value = "购物车相关接口api", tags = {"用于购物车相关操作"}) +public class TestController { + + @GetMapping("/app") + @ApiOperation(value = "查询购物车", notes = "查询购物车", httpMethod = "GET") + + public String queryData(@RequestParam String cartId){ + return cartId; + } + + @PostMapping("cart") + @ApiOperation(value = "添加购物车", notes = "添加购物车", httpMethod = "POST") + + public void updateCart(){ + + } +} diff --git "a/spring/aop/JDK\345\222\214CGlib\345\212\250\346\200\201\344\273\243\347\220\206/README.md" "b/spring/aop/JDK\345\222\214CGlib\345\212\250\346\200\201\344\273\243\347\220\206/README.md" new file mode 100644 index 0000000..262e3bd --- /dev/null +++ "b/spring/aop/JDK\345\222\214CGlib\345\212\250\346\200\201\344\273\243\347\220\206/README.md" @@ -0,0 +1,588 @@ +# 什么是代理 + +代理 的字面意思就是 代替别人处理事情。 举一个比较简单的例子,艺人要接商演,但是艺人时间宝贵,很忙,不可能什么都自己处理,所以有一个经济人的角色,这个经纪人就用来代替艺人处理一些不太重要的事情,比如商演薪酬洽谈,行程安排等等,**只有唱歌等演出才由艺人自己做** + +经纪人就是我们的代理类,而艺人就是 被代理的类。 + +代理又分静态代理和动态代理 + +# 静态代理 + +**静态代理的代理对象和被代理对象在代理之前就已经确定,它们都实现相同的接口或继承相同的抽象类.** + +用个例子看下,某公司要*徐坤商演,但是收钱和洽谈这方面肯定交给 经纪人(代理类)来做,所以我们就这样写 + +```java +public interface Star { + /** + * 跳舞 + */ + void dance(); +} +``` + +```java +public class Cxk implements Star { + @Override + public void dance() { + System.out.println("我是 练习时长两年半的练习生 " + this.getClass() + " ,我来 跳舞...."); + } +} +``` + +```java +public class CxkProxy implements Star { + + + private Star star; + + // 或者直接写死 +// private Star star = new Cxk(); + + public CxkProxy(Star star){ + this.star = star; + } + + @Override + public void dance() { + System.out.println("... 我是 cxk 的经纪人, 跳舞前 收钱 ..."); + star.dance(); + } +} +``` + +```java +public class Company { + public static void main(String[] args) { + + Star cxkProxy = new CxkProxy(new Cxk()); + cxkProxy.dance(); + } +} +``` + +``` +输出结果 +... 我是 cxk 的经纪人, 跳舞前 收钱 ... +我是 练习时长两年半的练习生 class com.leosanqing.proxy.static1.Cxk ,我来 跳舞.... +``` + + + +我们看上面的调用,其实我们一直是找 经纪人这个角色来进行 dance ,但最后 他还是调用了 真正的 跳舞的人,。 + +我们从这方面想一下我们的业务,我们只要 dance 这个业务(你可以想成其他实际业务,比如 扣库存),而 经纪人 的种种行为,我们可以看成是 在做业务之前 进行了 log 日志打印。相当于增强了 我们 之前的业务。这也是 Spring AOP Advise 所做的事。所以应该翻译成 **增强**更贴切语境。 + +但是 Spring 不可能使用 静态代理,所以下面就要介绍 动态代理了 + +# JDK 动态代理 + +动态代理有两种,一种是 JDK 的动态代理,一种是 CGlib 的动态代理。我们看下他们两个分别是什么 + +```java +public class ZhangSan implements Star { + + @Override + public void dance() { + System.out.println("我是 " + this.getClass().getName() +" 我来跳舞"); + } +} + + +public class ZhangSanProxy implements InvocationHandler { + private Object target; + + public Object newObject(Object o){ + this.target = o; + return Proxy.newProxyInstance(o.getClass().getClassLoader(),o.getClass().getInterfaces(),this); + } + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + System.out.println("------ 我是张三经纪人,唱歌前先收钱 -------"); + return method.invoke(target, args); + } +} + + +public class Test { + public static void main(String[] args) { + ZhangSanProxy zhangSanProxy = new ZhangSanProxy(); + Star star = (Star) zhangSanProxy.newObject(new ZhangSan()); + star.dance(); + } +} + +// 输出结果 +------ 我是张三经纪人,唱歌前先收钱 ------- +我是 com.leosanqing.proxy.dynamic.jdk.ZhangSan 我来跳舞 +``` + +我们看到,代理类 实现了 InvocationHandler 这个接口,然后重写他的 invoke 方法,在这里我们添加了某些其他的业务,比如收钱 + +当代码执行到 star.dance()方法时,他会调用 ZhangSanProxy 的 invoke 方法,这是为啥?,肯定是我们 的 `zhangSanProxy.newObject(new ZhangSan());`这里做了什么,我们看下源码 + +## 走进源码 + +```java +@CallerSensitive +public static Object newProxyInstance(ClassLoader loader, + Class[] interfaces, + InvocationHandler h) + throws IllegalArgumentException +{ + Objects.requireNonNull(h); + + final Class[] intfs = interfaces.clone(); + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + checkProxyAccess(Reflection.getCallerClass(), loader, intfs); + } + + /* + * Look up or generate the designated proxy class + * 查找或生成指定的代理类,这个是生成的主要的方法 + */ + Class cl = getProxyClass0(loader, intfs); + + /* + * Invoke its constructor with the designated invocation handler. + */ + try { + if (sm != null) { + checkNewProxyPermission(Reflection.getCallerClass(), cl); + } + + final Constructor cons = cl.getConstructor(constructorParams); + final InvocationHandler ih = h; + if (!Modifier.isPublic(cl.getModifiers())) { + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + cons.setAccessible(true); + return null; + } + }); + } + return cons.newInstance(new Object[]{h}); + } catch (IllegalAccessException|InstantiationException e) { + throw new InternalError(e.toString(), e); + } catch (InvocationTargetException e) { + Throwable t = e.getCause(); + if (t instanceof RuntimeException) { + throw (RuntimeException) t; + } else { + throw new InternalError(t.toString(), t); + } + } catch (NoSuchMethodException e) { + throw new InternalError(e.toString(), e); + } +} +``` + +```java + /** + * Generate a proxy class. Must call the checkProxyAccess method + * to perform permission checks before calling this. + */ + private static Class getProxyClass0(ClassLoader loader, + Class... interfaces) { + if (interfaces.length > 65535) { + throw new IllegalArgumentException("interface limit exceeded"); + } + + // If the proxy class defined by the given loader implementing + // the given interfaces exists, this will simply return the cached copy; + // otherwise, it will create the proxy class via the ProxyClassFactory + // 返回代理类,如果有缓存返回缓存,没有则创建 + return proxyClassCache.get(loader, interfaces); + } +``` + +```java + /** + * Look-up the value through the cache. This always evaluates the + * {@code subKeyFactory} function and optionally evaluates + * {@code valueFactory} function if there is no entry in the cache for given + * pair of (key, subKey) or the entry has already been cleared. + * + * @param key possibly null key + * @param parameter parameter used together with key to create sub-key and + * value (should not be null) + * @return the cached value (never null) + * @throws NullPointerException if {@code parameter} passed in or + * {@code sub-key} calculated by + * {@code subKeyFactory} or {@code value} + * calculated by {@code valueFactory} is null. + */ + public V get(K key, P parameter) { + Objects.requireNonNull(parameter); + + expungeStaleEntries(); + + // 能不能从缓存中获取对象,这里使用的是 弱引用,可能会被内存回收 + Object cacheKey = CacheKey.valueOf(key, refQueue); + + // lazily install the 2nd level valuesMap for the particular cacheKey + ConcurrentMap> valuesMap = map.get(cacheKey); + if (valuesMap == null) { + //putIfAbsent这个方法在key不存在的时候加入一个值,如果key存在就不放入 + ConcurrentMap> oldValuesMap + = map.putIfAbsent(cacheKey, + valuesMap = new ConcurrentHashMap<>()); + if (oldValuesMap != null) { + valuesMap = oldValuesMap; + } + } + + // create subKey and retrieve the possible Supplier stored by that + // subKey from valuesMap + Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); + Supplier supplier = valuesMap.get(subKey); + Factory factory = null; + + // 一直循环,直到生成好对象并返回 + while (true) { + if (supplier != null) { + // supplier might be a Factory or a CacheValue instance + // 在这里是返回 + V value = supplier.get(); + if (value != null) { + return value; + } + } + // else no supplier in cache + // or a supplier that returned null (could be a cleared CacheValue + // or a Factory that wasn't successful in installing the CacheValue) + + // lazily construct a Factory + // + if (factory == null) { + factory = new Factory(key, parameter, subKey, valuesMap); + } + + if (supplier == null) { + supplier = valuesMap.putIfAbsent(subKey, factory); + if (supplier == null) { + // successfully installed Factory + supplier = factory; + } + // else retry with winning supplier + } else { + if (valuesMap.replace(subKey, supplier, factory)) { + // successfully replaced + // cleared CacheEntry / unsuccessful Factory + // with our Factory + supplier = factory; + } else { + // retry with current supplier + supplier = valuesMap.get(subKey); + } + } + } + } +``` + +```java +// 我们会从上一步 的 V value = supplier.get(); 进入到这里,这里就是真正生成代理类的地方 + +private static final class ProxyClassFactory + implements BiFunction[], Class> +{ + // prefix for all proxy class names + private static final String proxyClassNamePrefix = "$Proxy"; + + // next number to use for generation of unique proxy class names + private static final AtomicLong nextUniqueNumber = new AtomicLong(); + + @Override + public Class apply(ClassLoader loader, Class[] interfaces) { + + Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); + for (Class intf : interfaces) { + /* + * Verify that the class loader resolves the name of this + * interface to the same Class object. + */ + Class interfaceClass = null; + try { + interfaceClass = Class.forName(intf.getName(), false, loader); + } catch (ClassNotFoundException e) { + } + if (interfaceClass != intf) { + throw new IllegalArgumentException( + intf + " is not visible from class loader"); + } + /* + * Verify that the Class object actually represents an + * interface. + */ + if (!interfaceClass.isInterface()) { + throw new IllegalArgumentException( + interfaceClass.getName() + " is not an interface"); + } + /* + * Verify that this interface is not a duplicate. + */ + if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { + throw new IllegalArgumentException( + "repeated interface: " + interfaceClass.getName()); + } + } + + String proxyPkg = null; // package to define proxy class in + int accessFlags = Modifier.PUBLIC | Modifier.FINAL; + + /* + * Record the package of a non-public proxy interface so that the + * proxy class will be defined in the same package. Verify that + * all non-public proxy interfaces are in the same package. + */ + for (Class intf : interfaces) { + int flags = intf.getModifiers(); + if (!Modifier.isPublic(flags)) { + accessFlags = Modifier.FINAL; + String name = intf.getName(); + int n = name.lastIndexOf('.'); + String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); + if (proxyPkg == null) { + proxyPkg = pkg; + } else if (!pkg.equals(proxyPkg)) { + throw new IllegalArgumentException( + "non-public interfaces from different packages"); + } + } + } + + if (proxyPkg == null) { + // if no non-public proxy interfaces, use com.sun.proxy package + proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; + } + + /* + * Choose a name for the proxy class to generate. + * 生成的代理类的名称 + */ + long num = nextUniqueNumber.getAndIncrement(); + String proxyName = proxyPkg + proxyClassNamePrefix + num; + + /* + * Generate the specified proxy class. + */ + byte[] proxyClassFile = ProxyGenerator.generateProxyClass( + proxyName, interfaces, accessFlags); + try { + return defineClass0(loader, proxyName, + proxyClassFile, 0, proxyClassFile.length); + } catch (ClassFormatError e) { + /* + * A ClassFormatError here means that (barring bugs in the + * proxy class generation code) there was some other + * invalid aspect of the arguments supplied to the proxy + * class creation (such as virtual machine limitations + * exceeded). + */ + throw new IllegalArgumentException(e.toString()); + } + } +} +``` + +```java +/* + * Generate the specified proxy class. + * 这里是重点,这里生成代理类的Class文件 + */ +byte[] proxyClassFile = ProxyGenerator.generateProxyClass( + proxyName, interfaces, accessFlags); +``` + +后面就看不到源码了,只能看到编译优化好的代码 + +```java +public static byte[] generateProxyClass(final String var0, Class[] var1, int var2) { + ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2); + // 这里生成文件 + final byte[] var4 = var3.generateClassFile(); + if (saveGeneratedFiles) { + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + try { + int var1 = var0.lastIndexOf(46); + Path var2; + if (var1 > 0) { + Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar)); + Files.createDirectories(var3); + var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class"); + } else { + var2 = Paths.get(var0 + ".class"); + } + + Files.write(var2, var4, new OpenOption[0]); + return null; + } catch (IOException var4x) { + throw new InternalError("I/O exception saving generated file: " + var4x); + } + } + }); + } + + return var4; +} +``` + +我们看到代理对象的类型是 ![](img/Xnip2020-09-28_15-06-45.jpg) + +这个名字在哪里生成的,可以看看前面两三个类,我有一行注释 + +最后绑定完之后,我们看 Star 生成的class 文件 + +```java +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +import com.leosanqing.proxy.Star; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.lang.reflect.UndeclaredThrowableException; + +public final class zhangSanProxy extends Proxy implements Star { + private static Method m1; + private static Method m3; + private static Method m2; + private static Method m0; + + public zhangSanProxy(InvocationHandler var1) throws { + super(var1); + } + + public final boolean equals(Object var1) throws { + try { + return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); + } catch (RuntimeException | Error var3) { + throw var3; + } catch (Throwable var4) { + throw new UndeclaredThrowableException(var4); + } + } + + public final void dance() throws { + try { + super.h.invoke(this, m3, (Object[])null); + } catch (RuntimeException | Error var2) { + throw var2; + } catch (Throwable var3) { + throw new UndeclaredThrowableException(var3); + } + } + + public final String toString() throws { + try { + return (String)super.h.invoke(this, m2, (Object[])null); + } catch (RuntimeException | Error var2) { + throw var2; + } catch (Throwable var3) { + throw new UndeclaredThrowableException(var3); + } + } + + public final int hashCode() throws { + try { + return (Integer)super.h.invoke(this, m0, (Object[])null); + } catch (RuntimeException | Error var2) { + throw var2; + } catch (Throwable var3) { + throw new UndeclaredThrowableException(var3); + } + } + + static { + try { + m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); + m3 = Class.forName("com.leosanqing.proxy.Star").getMethod("dance"); + m2 = Class.forName("java.lang.Object").getMethod("toString"); + m0 = Class.forName("java.lang.Object").getMethod("hashCode"); + } catch (NoSuchMethodException var2) { + throw new NoSuchMethodError(var2.getMessage()); + } catch (ClassNotFoundException var3) { + throw new NoClassDefFoundError(var3.getMessage()); + } + } +} + +``` + +我们看到 他的 dance 方法,调用了`super.h.invoke(this, m3, (Object[])null);` 而那个 h 就是我们的`ZhangSanProxy`,然后就有了 我们写的 `ZhangSanProxy.invoke()`里面的内容 + +# CGlib + +```java +public class LiSi { + public void dance() { + System.out.println("我是 "+this.getClass().getName() + ", 我来唱歌"); + } +} + + +public class LiSiProxy implements MethodInterceptor { + + public static Object createProxyObject(Object o){ + Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(o.getClass()); + enhancer.setCallback(new LiSiProxy()); + return enhancer.create(); + } + + @Override + public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { + System.out.println("我是李四经纪人,演出前先收钱"); + methodProxy.invokeSuper(o, objects); + return null; + } +} + + + +public class Test { + public static void main(String[] args) { + LiSi proxyObject = (LiSi)LiSiProxy.createProxyObject(new LiSi()); + proxyObject.dance(); + } +} + + +我是李四经纪人,演出前先收钱 +我是 com.leosanqing.proxy.dynamic.cglib.LiSi$$EnhancerByCGLIB$$d5e54c2b, 我来唱歌 +``` + + + +在使用 CGlib 的时候,**我们并没有 使用 Star 接口**,这也是 JDK 动态代理和 CGlib 的主要区别, + + + +# 区别 + +1. JDK 动态代理只能代理实现了接口的类,没有实现接口的类是不能使用 JDK 动态代理的 +2. CGlib 是对类进行代理,运行时动态生成被代理类的子类 拦截父类的方法调用,所以类和方法不能声明成 final 类,不然会报错 `Exception in thread "main" java.lang.IllegalArgumentException: Cannot subclass final class com.leosanqing.proxy.dynamic.cglib.LiSi` + +# 结合Spring + +做Javaweb 项目,都是 三层结构,controller、service、dao,一层调用一层,但是我们在创建 service的时候,总是要先生成一个 ServiceInterface 然后再编写他的实现类,为什么会这样?难道不能不这样? + +**当然可以不这样**,不过这样子是因为 Spring 他 可以采用 CGlib 进行AOP,如果没有 CGlib,那么肯定要有 接口才行 + +早期由于 Spring 只有 JDK的动态代理,所以必须 要写接口,然后接口实现,甚至你在 controller 层注入 的时候都不能这样写 + +```java +@Autowired +private ServiceImpl servcieImpl +``` + +如果你这样,他会直接报错,因为他是用的是 JDK 的动态代理,你只能注入他的接口,而不能注入他的实现 + +好在现在 Spring 引入了 CGlib,我们如果项目不大,或者不对外交互,可以少去 Service 的 interface 层。 + +我们有一个项目就没有 interface层,直接编写他的实现类 `public class DealService extends ServiceImpl `,配合Mybatis-plus 直接进行快速开发 + diff --git "a/spring/aop/JDK\345\222\214CGlib\345\212\250\346\200\201\344\273\243\347\220\206/img/Xnip2020-09-28_15-06-45.jpg" "b/spring/aop/JDK\345\222\214CGlib\345\212\250\346\200\201\344\273\243\347\220\206/img/Xnip2020-09-28_15-06-45.jpg" new file mode 100644 index 0000000..a152f5a Binary files /dev/null and "b/spring/aop/JDK\345\222\214CGlib\345\212\250\346\200\201\344\273\243\347\220\206/img/Xnip2020-09-28_15-06-45.jpg" differ diff --git "a/spring/ioc/bean\347\232\204\345\210\235\345\247\213\345\214\226/REDME.md" "b/spring/ioc/bean\347\232\204\345\210\235\345\247\213\345\214\226/REDME.md" new file mode 100644 index 0000000..f295bc3 --- /dev/null +++ "b/spring/ioc/bean\347\232\204\345\210\235\345\247\213\345\214\226/REDME.md" @@ -0,0 +1,1766 @@ +Spring IOC 容器 + +构建一个 IOC 容器 + +```java +public class App { + public static void main(String[] args) { + // 用我们的配置文件来启动一个 ApplicationContext + + + // 使用注解配置 + ann(); + // 使用XML 配置 + xml(); + + } + + private static void xml() { + ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml"); + + + System.out.println("context 启动成功"); + + + // 从 context 中取出我们的 Bean,而不是用 new MessageServiceImpl() 这种方式 + MessageService messageService = context.getBean(MessageService.class); + // 这句将输出: hello world + System.out.println(messageService.getMessage()); + } + + private static void ann(){ + AnnotationConfigApplicationContext annotationConfigApplicationContext = + new AnnotationConfigApplicationContext(SpringConfiguration.class); + HelloWorldService bean = (HelloWorldService) annotationConfigApplicationContext.getBean("userService"); + + bean.say(); + } +} + + + +public interface MessageService { + String getMessage(); +} + + +public class MessageServiceImpl implements MessageService { + + public String getMessage() { + return "hello world"; + } +} +``` + +```javascript + + + + + +``` + + + +我们肯定很好奇,Spring 到底是怎么把 各个 Bean 放在 容器中管理的,他是怎么生成的。那就跟着源码来看下他是怎么初始化各个类,然后又怎么对其属性进行赋值的吧 + + + +我们就从 `App.class` 入手 + +我们 new 了一个 `ClassPathXmlApplicationContext`, 这个 就是我们使用 XML 这种配置方式进行配置的时候加载的 + +而 另一边 `AnnotationConfigApplicationContext` 这个 就是我们使用注解时调用的 容器了。 + +我们先从 XML 开始,只是一开始处理的方式不同,后面调用的 还是一模一样的 + + + +```java +/** + * Create a new ClassPathXmlApplicationContext, loading the definitions + * from the given XML file and automatically refreshing the context. + * @param configLocation resource location + * @throws BeansException if context creation failed + */ +// 我们可以使用这个 创建或者刷新容器 +public ClassPathXmlApplicationContext(String configLocation) throws BeansException { + this(new String[] {configLocation}, true, null); +} +``` + +```java +public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) + throws BeansException { + + super(parent); + // 设置 配置文件路径,再加上一些标点符号的处理 + setConfigLocations(configLocations); + if (refresh) { + // 这个是核心方法 + refresh(); + } +} +``` + + + +# 核心方法Refresh + +```java + +@Override +public void refresh() throws BeansException, IllegalStateException { + // 上来先加个锁 + synchronized (this.startupShutdownMonitor) { + // Prepare this context for refreshing. + // 1.准备工作 主要是 设置开始时间,检验xml文件,不是重点 + prepareRefresh(); + + // 2.Tell the subclass to refresh the internal bean factory. + // 这一步比较关键,不仅解析了 XML, 还把每一个Bean 的名称(定义),放到容器中(以map的形式) + // 当然,这里只有定义,没有初始化,相当于你爸老早给你取好了名字,但是你还没有出生 + ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); + + // 3.Prepare the bean factory for use in this context. + // 准备 Bean 容器 + prepareBeanFactory(beanFactory); + + try { + // 4.Allows post-processing of the bean factory in context subclasses. + postProcessBeanFactory(beanFactory); + + // 5.Invoke factory processors registered as beans in the context. + invokeBeanFactoryPostProcessors(beanFactory); + + // 6.Register bean processors that intercept bean creation. + registerBeanPostProcessors(beanFactory); + + // 7.Initialize message source for this context. + // 初始化一些 + initMessageSource(); + + // 8.Initialize event multicaster for this context. + // 初始化一些 事件广播 + initApplicationEventMulticaster(); + + // 9.Initialize other special beans in specific context subclasses. + // 初始化 子类的一些东西 + onRefresh(); + + // 10.Check for listener beans and register them. + // 注册事件监听器 + registerListeners(); + + + // 11.Instantiate all remaining (non-lazy-init) singletons. + // !!! 重点,初始化所有 非懒加载的单例 + finishBeanFactoryInitialization(beanFactory); + + // 12.Last step: publish corresponding event. + // 完成所有初始化信息 + finishRefresh(); + } +``` + +## 1. 创建 刷新前的准备工作 + +```java +/** + * Prepare this context for refreshing, setting its startup date and + * active flag as well as performing any initialization of property sources. + */ +protected void prepareRefresh() { + this.startupDate = System.currentTimeMillis(); + this.closed.set(false); + this.active.set(true); + + if (logger.isInfoEnabled()) { + logger.info("Refreshing " + this); + } + + // Initialize any placeholder property sources in the context environment + initPropertySources(); + + // Validate that all properties marked as required are resolvable + // see ConfigurablePropertyResolver#setRequiredProperties + getEnvironment().validateRequiredProperties(); + + // Allow for the collection of early ApplicationEvents, + // to be published once the multicaster is available... + this.earlyApplicationEvents = new LinkedHashSet(); +} + +``` + +## 2. 获得BeanFactory + +```java +/** + * Tell the subclass to refresh the internal bean factory. + * @return the fresh BeanFactory instance + * @see #refreshBeanFactory() + * @see #getBeanFactory() + */ +protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { + refreshBeanFactory(); + ConfigurableListableBeanFactory beanFactory = getBeanFactory(); + if (logger.isDebugEnabled()) { + logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); + } + return beanFactory; +} +``` + +```java +/** + * This implementation performs an actual refresh of this context's underlying + * bean factory, shutting down the previous bean factory (if any) and + * initializing a fresh bean factory for the next phase of the context's lifecycle. + */ +@Override +protected final void refreshBeanFactory() throws BeansException { + // 如果已经创建过工厂了,就销毁,然后重新初始化。 + // 没有就直接初始化 + if (hasBeanFactory()) { + destroyBeans(); + closeBeanFactory(); + } + try { + // !!!!!!! + // 记住这个 DefaultListableBeanFactory 类,他很重要,等下说 + DefaultListableBeanFactory beanFactory = createBeanFactory(); + // 设置他的序列号 + beanFactory.setSerializationId(getId()); + // 自定义一些参数,如是否允许覆盖 是否允许循环依赖 + customizeBeanFactory(beanFactory); + // 加载 BeanDefinition + loadBeanDefinitions(beanFactory); + synchronized (this.beanFactoryMonitor) { + this.beanFactory = beanFactory; + } + } + catch (IOException ex) { + throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); + } +} +``` + + + +虽然 ApplicationContext 继承自 BeanFactory,但是 **他并不应该被理解为 BeanFactory 的实现(子类)**,而是他内部实例化了一个 BeanFactory(DefaultListableBeanFactory),这个类很厉害,之后所有的 BeanFactory 相关的操作都是委托给他来干的 + +我们看图,他左边 继承自 `ConfigurableListableBeanFactory` ,而这个接口实现了 `BeanFactory`接口的 下一层的 所有的接口(三个接口)。 而他 右边 通过 实现 `AbstractAutowireCapableBeanFactory` 打通了右边所有的接口。所以`DefaultListableBeanFactory`他真的很牛皮 + +而我们 使用 ApplicationContext 的时候 能通过 `context.getAutowireCapableBeanFactory()`直接拿到 `AutowireCapableBeanFactory`,然后再经过转型就能拿到 `DefaultListableBeanFactory`。 + +### BeanDefinition + +既然是 BeanFactory ,那么 我们的 Bean 是什么东西 + +spring 他不会直接管理你定义的 class 或者你自己定义的 bean,他会把他们转换成 BeanDefinition ,然后再用容器管理他们。这个 BeanDefinition 对象 存储了很多很多东西,如是否懒加载,是否单例,依赖哪些类,等等 + +```java +public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { + + String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; + + String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; + + int ROLE_APPLICATION = 0; + int ROLE_SUPPORT = 1; + int ROLE_INFRASTRUCTURE = 2; + + + // Modifiable attributes + + void setParentName(String parentName); + String getParentName(); + + void setBeanClassName(String beanClassName); + String getBeanClassName(); + + // 作用域 + void setScope(String scope); + String getScope(); + + // 是否懒加载 + void setLazyInit(boolean lazyInit); + boolean isLazyInit(); + + // 依赖的类 + void setDependsOn(String... dependsOn); + String[] getDependsOn(); + + // 设置该 Bean 是否可以注入到其他 Bean 中,只对根据类型注入有效, + // 如果根据名称注入,即使这边设置了 false,也是可以的 + void setAutowireCandidate(boolean autowireCandidate); + boolean isAutowireCandidate(); + + void setPrimary(boolean primary); + boolean isPrimary(); + + void setFactoryBeanName(String factoryBeanName); + String getFactoryBeanName(); + + void setFactoryMethodName(String factoryMethodName); + String getFactoryMethodName(); + + ConstructorArgumentValues getConstructorArgumentValues(); + + MutablePropertyValues getPropertyValues(); + + // Read-only attributes + + boolean isSingleton(); + + boolean isPrototype(); + + boolean isAbstract(); + + int getRole(); + + String getDescription(); + + String getResourceDescription(); + + BeanDefinition getOriginatingBeanDefinition(); + +} +``` + +```java +/** + * Loads the bean definitions via an XmlBeanDefinitionReader. + * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader + * @see #initBeanDefinitionReader + * @see #loadBeanDefinitions + */ +@Override +protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { + // Create a new XmlBeanDefinitionReader for the given BeanFactory. + // 实例化一个 XmlBeanDefinition 解析器 + XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); + + // Configure the bean definition reader with this context's + // resource loading environment. + beanDefinitionReader.setEnvironment(this.getEnvironment()); + beanDefinitionReader.setResourceLoader(this); + beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); + + // Allow a subclass to provide custom initialization of the reader, + // then proceed with actually loading the bean definitions. + initBeanDefinitionReader(beanDefinitionReader); + + loadBeanDefinitions(beanDefinitionReader); +} + + +/** + * Load the bean definitions with the given XmlBeanDefinitionReader. + *

The lifecycle of the bean factory is handled by the {@link #refreshBeanFactory} + * method; hence this method is just supposed to load and/or register bean definitions. + * @param reader the XmlBeanDefinitionReader to use + * @throws BeansException in case of bean registration errors + * @throws IOException if the required XML document isn't found + * @see #refreshBeanFactory + * @see #getConfigLocations + * @see #getResources + * @see #getResourcePatternResolver + */ + protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { + Resource[] configResources = getConfigResources(); + // 往下看,最后这两个都会走到 下面这个方法里面 + if (configResources != null) { + reader.loadBeanDefinitions(configResources); + } + // 获取配置文件地址 + String[] configLocations = getConfigLocations(); + if (configLocations != null) { + reader.loadBeanDefinitions(configLocations); + } + } +``` + +```java +@Override +public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException { + Assert.notNull(locations, "Location array must not be null"); + int counter = 0; + // 加载每个配置文件中的 配置信息 + for (String location : locations) { + counter += loadBeanDefinitions(location); + } + // 返回 加载了 多少个 BeanDefinition + return counter; +} + +@Override +public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { + return loadBeanDefinitions(location, null); +} + + + +public int loadBeanDefinitions(String location, Set actualResources) throws BeanDefinitionStoreException { + ResourceLoader resourceLoader = getResourceLoader(); + if (resourceLoader == null) { + throw new BeanDefinitionStoreException( + "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); + } + + if (resourceLoader instanceof ResourcePatternResolver) { + // Resource pattern matching available. + try { + Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); + // 加载 BeanDefinition + int loadCount = loadBeanDefinitions(resources); + if (actualResources != null) { + for (Resource resource : resources) { + actualResources.add(resource); + } + } + if (logger.isDebugEnabled()) { + logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); + } + return loadCount; + } + catch (IOException ex) { + throw new BeanDefinitionStoreException( + "Could not resolve bean definition resource pattern [" + location + "]", ex); + } + } + else { + // Can only load single resources by absolute URL. + Resource resource = resourceLoader.getResource(location); + int loadCount = loadBeanDefinitions(resource); + if (actualResources != null) { + actualResources.add(resource); + } + if (logger.isDebugEnabled()) { + logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); + } + return loadCount; + } +} +``` + + + +// org/springframework/beans/factory/support/AbstractBeanDefinitionReader.java + +```java + +@Override + public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { + Assert.notNull(resources, "Resource array must not be null"); + int counter = 0; + for (Resource resource : resources) { + counter += loadBeanDefinitions(resource); + } + return counter; + } + + + /** + * Load bean definitions from the specified XML file. + * @param resource the resource descriptor for the XML file + * @return the number of bean definitions found + * @throws BeanDefinitionStoreException in case of loading or parsing errors + */ + @Override + public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { + return loadBeanDefinitions(new EncodedResource(resource)); + } + + +public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { + Assert.notNull(encodedResource, "EncodedResource must not be null"); + if (logger.isInfoEnabled()) { + logger.info("Loading XML bean definitions from " + encodedResource.getResource()); + } + + Set currentResources = this.resourcesCurrentlyBeingLoaded.get(); + if (currentResources == null) { + currentResources = new HashSet(4); + this.resourcesCurrentlyBeingLoaded.set(currentResources); + } + if (!currentResources.add(encodedResource)) { + throw new BeanDefinitionStoreException( + "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); + } + try { + InputStream inputStream = encodedResource.getResource().getInputStream(); + try { + InputSource inputSource = new InputSource(inputStream); + if (encodedResource.getEncoding() != null) { + inputSource.setEncoding(encodedResource.getEncoding()); + } + // !!!! 这里是重点 + return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); + } + finally { + inputStream.close(); + } + } + catch (IOException ex) { + throw new BeanDefinitionStoreException( + "IOException parsing XML document from " + encodedResource.getResource(), ex); + } + finally { + currentResources.remove(encodedResource); + if (currentResources.isEmpty()) { + this.resourcesCurrentlyBeingLoaded.remove(); + } + } + } +``` + +```java +protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) + throws BeanDefinitionStoreException { + try { + // 将 xml 解析成 Doc 文件 + Document doc = doLoadDocument(inputSource, resource); + return registerBeanDefinitions(doc, resource); + } + catch (BeanDefinitionStoreException ex) { + throw ex; + } + catch (SAXParseException ex) { + throw new XmlBeanDefinitionStoreException(resource.getDescription(), + "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex); + } + catch (SAXException ex) { + throw new XmlBeanDefinitionStoreException(resource.getDescription(), + "XML document from " + resource + " is invalid", ex); + } + catch (ParserConfigurationException ex) { + throw new BeanDefinitionStoreException(resource.getDescription(), + "Parser configuration exception parsing XML from " + resource, ex); + } + catch (IOException ex) { + throw new BeanDefinitionStoreException(resource.getDescription(), + "IOException parsing XML document from " + resource, ex); + } + catch (Throwable ex) { + throw new BeanDefinitionStoreException(resource.getDescription(), + "Unexpected exception parsing XML document from " + resource, ex); + } +} + +public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { + BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); + int countBefore = getRegistry().getBeanDefinitionCount(); +// 这 + documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); + // 加载后减去 之前的 就是加载了 几个 + return getRegistry().getBeanDefinitionCount() - countBefore; + } +``` + +```java +/** + * Register each bean definition within the given root {@code } element. + */ +protected void doRegisterBeanDefinitions(Element root) { + // Any nested elements will cause recursion in this method. In + // order to propagate and preserve default-* attributes correctly, + // keep track of the current (parent) delegate, which may be null. Create + // the new (child) delegate with a reference to the parent for fallback purposes, + // then ultimately reset this.delegate back to its original (parent) reference. + // this behavior emulates a stack of delegates without actually necessitating one. + + // 我们看名字就知道,BeanDefinitionParserDelegate 必定是一个重要的类,它负责解析 Bean 定义, + // 这里为什么要定义一个 parent? 看到后面就知道了,是递归问题, + // 因为 内部是可以定义 的,所以这个方法的 root 其实不一定就是 xml 的根节点,也可以是嵌套在里面的 节点,从源码分析的角度,我们当做根节点就好了 + BeanDefinitionParserDelegate parent = this.delegate; + this.delegate = createDelegate(getReaderContext(), root, parent); + + // 判断他是否是当前环境下的配置文件 + if (this.delegate.isDefaultNamespace(root)) { + String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); + if (StringUtils.hasText(profileSpec)) { + String[] specifiedProfiles = StringUtils.tokenizeToStringArray( + profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); + if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { + if (logger.isInfoEnabled()) { + logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + + "] not matching: " + getReaderContext().getResource()); + } + return; + } + } + } + + preProcessXml(root); + parseBeanDefinitions(root, this.delegate); + postProcessXml(root); + + this.delegate = parent; +} +``` + +```java +/** + * Parse the elements at the root level in the document: + * "import", "alias", "bean". + * @param root the DOM root element of the document + */ +protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { + if (delegate.isDefaultNamespace(root)) { + NodeList nl = root.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node node = nl.item(i); + if (node instanceof Element) { + Element ele = (Element) node; + if (delegate.isDefaultNamespace(ele)) { + // 解析 默认节点元素 + parseDefaultElement(ele, delegate); + } + else { + delegate.parseCustomElement(ele); + } + } + } + } + else { + delegate.parseCustomElement(root); + } +} + + +// import alias bean beans 这几个标签 是默认的,如果不是这几个但又在 默认标签下,他是不会处理的 +private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { + if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { + importBeanDefinitionResource(ele); + } + else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { + processAliasRegistration(ele); + } + else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { + processBeanDefinition(ele, delegate); + } + else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { + // recurse + doRegisterBeanDefinitions(ele); + } + } +``` + +### 解析xml中 Bean 标签 + +```java +/** + * Process the given bean element, parsing the bean definition + * and registering it with the registry. + */ +protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { + // 生成 BeanDefinitionHolder 里面包含了 BeanDefinition 对象 + BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); + if (bdHolder != null) { + bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); + try { + // Register the final decorated instance. + BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); + } + catch (BeanDefinitionStoreException ex) { + getReaderContext().error("Failed to register bean definition with name '" + + bdHolder.getBeanName() + "'", ele, ex); + } + // Send registration event. + getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); + } +} +``` + +```java +/** + * Parses the supplied {@code } element. May return {@code null} + * if there were errors during parse. Errors are reported to the + * {@link org.springframework.beans.factory.parsing.ProblemReporter}. + */ +public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { + String id = ele.getAttribute(ID_ATTRIBUTE); + String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); + // 将名字按照 以下标点切分 + // public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; "; + List aliases = new ArrayList(); + if (StringUtils.hasLength(nameAttr)) { + String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); + aliases.addAll(Arrays.asList(nameArr)); + } + + String beanName = id; + // 如果 没有 id,但是有别名,就将别名中的第一个名字 作为beanName + if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { + beanName = aliases.remove(0); + if (logger.isDebugEnabled()) { + logger.debug("No XML 'id' specified - using '" + beanName + + "' as bean name and " + aliases + " as aliases"); + } + } + + if (containingBean == null) { + // a.校验 名称是否唯一 + checkNameUniqueness(beanName, aliases, ele); + } + + // b.这个执行完 一个 BeanDefinition 对象就生成了,属性值那些都会在这里赋值处理 + AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); + if (beanDefinition != null) { + // 如果我们没有设置到 beanName + if (!StringUtils.hasText(beanName)) { + try { + if (containingBean != null) { + // 生成 beanName,{类名}#{第几个beanDefinition} + beanName = BeanDefinitionReaderUtils.generateBeanName( + beanDefinition, this.readerContext.getRegistry(), true); + } + else { + beanName = this.readerContext.generateBeanName(beanDefinition); + // Register an alias for the plain bean class name, if still possible, + // if the generator returned the class name plus a suffix. + // This is expected for Spring 1.2/2.0 backwards compatibility. + String beanClassName = beanDefinition.getBeanClassName(); + if (beanClassName != null && + beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && + !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { + aliases.add(beanClassName); + } + } + if (logger.isDebugEnabled()) { + logger.debug("Neither XML 'id' nor 'name' specified - " + + "using generated bean name [" + beanName + "]"); + } + } + catch (Exception ex) { + error(ex.getMessage(), ele); + return null; + } + } + String[] aliasesArray = StringUtils.toStringArray(aliases); + return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); + } + + return null; +} +``` + +### a.校验名称的唯一性 + +```java +protected void checkNameUniqueness(String beanName, List aliases, Element beanElement) { + String foundName = null; + + if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) { + foundName = beanName; + } + if (foundName == null) { + foundName = CollectionUtils.findFirstMatch(this.usedNames, aliases); + } + if (foundName != null) { + error("Bean name '" + foundName + "' is already used in this element", beanElement); + } + + this.usedNames.add(beanName); + this.usedNames.addAll(aliases); +} +``` + +### b.生成BeanDefinition对象 + +```java +public AbstractBeanDefinition parseBeanDefinitionElement( + Element ele, String beanName, BeanDefinition containingBean) { + + this.parseState.push(new BeanEntry(beanName)); + + String className = null; + if (ele.hasAttribute(CLASS_ATTRIBUTE)) { + className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); + } + + try { + String parent = null; + if (ele.hasAttribute(PARENT_ATTRIBUTE)) { + parent = ele.getAttribute(PARENT_ATTRIBUTE); + } + AbstractBeanDefinition bd = createBeanDefinition(className, parent); + + parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); + bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); + + parseMetaElements(ele, bd); + parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); + parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); + + parseConstructorArgElements(ele, bd); + parsePropertyElements(ele, bd); + parseQualifierElements(ele, bd); + + bd.setResource(this.readerContext.getResource()); + bd.setSource(extractSource(ele)); + + return bd; + } + catch (ClassNotFoundException ex) { + error("Bean class [" + className + "] not found", ele, ex); + } + catch (NoClassDefFoundError err) { + error("Class that bean class [" + className + "] depends on not found", ele, err); + } + catch (Throwable ex) { + error("Unexpected failure during bean definition parsing", ele, ex); + } + finally { + this.parseState.pop(); + } + + return null; +} +``` + +### 注册 Bean + +```java +/** + * Process the given bean element, parsing the bean definition + * and registering it with the registry. + */ +protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { + // 刚刚看过了,就是上面一坨 + BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); + if (bdHolder != null) { + bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); + try { + // Register the final decorated instance. + // 注册 bean实例 + BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); + } + catch (BeanDefinitionStoreException ex) { + getReaderContext().error("Failed to register bean definition with name '" + + bdHolder.getBeanName() + "'", ele, ex); + } + // Send registration event. + getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); + } +} +``` + +```java +@Override +public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) + throws BeanDefinitionStoreException { + + Assert.hasText(beanName, "Bean name must not be empty"); + Assert.notNull(beanDefinition, "BeanDefinition must not be null"); + + if (beanDefinition instanceof AbstractBeanDefinition) { + try { + ((AbstractBeanDefinition) beanDefinition).validate(); + } + catch (BeanDefinitionValidationException ex) { + throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, + "Validation of bean definition failed", ex); + } + } + + BeanDefinition oldBeanDefinition; + + // 如果之前已经有这个 名字 + oldBeanDefinition = this.beanDefinitionMap.get(beanName); + if (oldBeanDefinition != null) { + // 如果不允许重载 + if (!isAllowBeanDefinitionOverriding()) { + throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, + "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + + "': There is already [" + oldBeanDefinition + "] bound."); + } + // bean 等级 三个 + else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { + // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE + if (this.logger.isWarnEnabled()) { + this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + + "' with a framework-generated bean definition: replacing [" + + oldBeanDefinition + "] with [" + beanDefinition + "]"); + } + } + // 新的覆盖旧的 + else if (!beanDefinition.equals(oldBeanDefinition)) { + if (this.logger.isInfoEnabled()) { + this.logger.info("Overriding bean definition for bean '" + beanName + + "' with a different definition: replacing [" + oldBeanDefinition + + "] with [" + beanDefinition + "]"); + } + } + else { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Overriding bean definition for bean '" + beanName + + "' with an equivalent definition: replacing [" + oldBeanDefinition + + "] with [" + beanDefinition + "]"); + } + } + this.beanDefinitionMap.put(beanName, beanDefinition); + } + else { + // 判断是否有Bean 已经开始初始化 + if (hasBeanCreationStarted()) { + // Cannot modify startup-time collection elements anymore (for stable iteration) + synchronized (this.beanDefinitionMap) { + this.beanDefinitionMap.put(beanName, beanDefinition); + List updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1); + updatedDefinitions.addAll(this.beanDefinitionNames); + updatedDefinitions.add(beanName); + this.beanDefinitionNames = updatedDefinitions; + if (this.manualSingletonNames.contains(beanName)) { + Set updatedSingletons = new LinkedHashSet(this.manualSingletonNames); + updatedSingletons.remove(beanName); + this.manualSingletonNames = updatedSingletons; + } + } + } + else { + // Still in startup registration phase + // 放入map + this.beanDefinitionMap.put(beanName, beanDefinition); + this.beanDefinitionNames.add(beanName); + // 这是个 LinkedHashSet,代表的是手动注册的 singleton bean, + // 注意这里是 remove 方法,到这里的 Bean 当然不是手动注册的 + // 手动指的是通过调用以下方法注册的 bean : + // registerSingleton(String beanName, Object singletonObject) + // 这不是重点,解释只是为了不让大家疑惑。Spring 会在后面"手动"注册一些 Bean, + // 如 "environment"、"systemProperties" 等 bean,我们自己也可以在运行时注册 Bean 到容器中的 + this.manualSingletonNames.remove(beanName); + } + this.frozenBeanDefinitionNames = null; + } + + if (oldBeanDefinition != null || containsSingleton(beanName)) { + resetBeanDefinition(beanName); + } +} +``` + +------ + +到目前为止,我们才相当于声明了 BeanDefinition ,才走完Refresh 中的 第二个方法 后面才是实例化他 + +## 3.准备Bean容器 + +```java +/** + * Configure the factory's standard context characteristics, + * such as the context's ClassLoader and post-processors. + * @param beanFactory the BeanFactory to configure + */ +protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { + // Tell the internal bean factory to use the context's class loader etc. + beanFactory.setBeanClassLoader(getClassLoader()); + beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); + beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); + + // Configure the bean factory with context callbacks. + beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); + beanFactory.ignoreDependencyInterface(EnvironmentAware.class); + beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); + beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); + beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); + beanFactory.ignoreDependencyInterface(MessageSourceAware.class); + beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); + + // BeanFactory interface not registered as resolvable type in a plain factory. + // MessageSource registered (and found for autowiring) as a bean. + beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); + beanFactory.registerResolvableDependency(ResourceLoader.class, this); + beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); + beanFactory.registerResolvableDependency(ApplicationContext.class, this); + + // Register early post-processor for detecting inner beans as ApplicationListeners. + beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); + + // Detect a LoadTimeWeaver and prepare for weaving, if found. + if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { + beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); + // Set a temporary ClassLoader for type matching. + beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); + } + + // 如果还没有注册 默认的 一些 bean ,spring会自动帮你注册 + // Register default environment beans. + if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { + beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); + } + if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { + beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); + } + if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { + beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); + } +} +``` + +## 11.实例化Bean + +这里是重点 + +他会初始化所有 **非懒加载**的 **单例** 的Bean + +```java +/** + * Finish the initialization of this context's bean factory, + * initializing all remaining singleton beans. + */ +protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { + // Initialize conversion service for this context. + // 寻找并初始化 conversionService + if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && + beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { + beanFactory.setConversionService( + beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); + } + + // Register a default embedded value resolver if no bean post-processor + // (such as a PropertyPlaceholderConfigurer bean) registered any before: + // at this point, primarily for resolution in annotation attribute values. + if (!beanFactory.hasEmbeddedValueResolver()) { + beanFactory.addEmbeddedValueResolver(new StringValueResolver() { + @Override + public String resolveStringValue(String strVal) { + return getEnvironment().resolvePlaceholders(strVal); + } + }); + } + + // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. + // 初始化 LoadTimeWeaverAware 类型的 bean + String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); + for (String weaverAwareName : weaverAwareNames) { + getBean(weaverAwareName); + } + + // Stop using the temporary ClassLoader for type matching. + beanFactory.setTempClassLoader(null); + + // Allow for caching all bean definition metadata, not expecting further changes. + // 马上就要进行 初始化了,防止再出现 bean的改变 + beanFactory.freezeConfiguration(); + + // Instantiate all remaining (non-lazy-init) singletons. + beanFactory.preInstantiateSingletons(); +} +``` + +```java +@Override +public void preInstantiateSingletons() throws BeansException { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Pre-instantiating singletons in " + this); + } + + // Iterate over a copy to allow for init methods which in turn register new bean definitions. + // While this may not be part of the regular factory bootstrap, it does otherwise work fine. + List beanNames = new ArrayList(this.beanDefinitionNames); + + // Trigger initialization of all non-lazy singleton beans... + for (String beanName : beanNames) { + // 合并父类中的配置信息 + RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); + // 如果不是抽象类 且 是单例 且 非懒加载 + if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { + // 处理 FactoryBean + if (isFactoryBean(beanName)) { + // FactoryBean 前面需要 加 & 符号 + final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName); + boolean isEagerInit; + if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { + isEagerInit = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Boolean run() { + return ((SmartFactoryBean) factory).isEagerInit(); + } + }, getAccessControlContext()); + } + else { + isEagerInit = (factory instanceof SmartFactoryBean && + ((SmartFactoryBean) factory).isEagerInit()); + } + if (isEagerInit) { + getBean(beanName); + } + } + else { + // getBean 就进行了 初始化 + getBean(beanName); + } + } + } + + // Trigger post-initialization callback for all applicable beans... + for (String beanName : beanNames) { + Object singletonInstance = getSingleton(beanName); + if (singletonInstance instanceof SmartInitializingSingleton) { + final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; + if (System.getSecurityManager() != null) { + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Object run() { + smartSingleton.afterSingletonsInstantiated(); + return null; + } + }, getAccessControlContext()); + } + else { + smartSingleton.afterSingletonsInstantiated(); + } + } + } +} +``` + +```java +// org.springframework.beans.factory.support.AbstractBeanFactory + +@Override +public Object getBean(String name) throws BeansException { + return doGetBean(name, null, null, false); +} + + + +/** + * Return an instance, which may be shared or independent, of the specified bean. + * @param name the name of the bean to retrieve + * @param requiredType the required type of the bean to retrieve + * @param args arguments to use when creating a bean instance using explicit arguments + * (only applied when creating a new instance as opposed to retrieving an existing one) + * @param typeCheckOnly whether the instance is obtained for a type check, + * not for actual use + * @return an instance of the bean + * @throws BeansException if the bean could not be created + */ + @SuppressWarnings("unchecked") + protected T doGetBean( + final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) + throws BeansException { + + final String beanName = transformedBeanName(name); + Object bean; + + // Eagerly check singleton cache for manually registered singletons. + // a.检查是否已经创建过 + Object sharedInstance = getSingleton(beanName); + // 如果传入的 args 不是 null,那么他肯定是想创建 bean,而不是 获取bean + if (sharedInstance != null && args == null) { + if (logger.isDebugEnabled()) { + if (isSingletonCurrentlyInCreation(beanName)) { + logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + + "' that is not fully initialized yet - a consequence of a circular reference"); + } + else { + logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); + } + } + bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); + } + + else { + // Fail if we're already creating this bean instance: + // We're assumably within a circular reference. + // 如果我们已经在创建此bean实例,则失败:大概在循环引用中。 + if (isPrototypeCurrentlyInCreation(beanName)) { + throw new BeanCurrentlyInCreationException(beanName); + } + + // Check if bean definition exists in this factory. + // 检查这个 bean 是否存在 这个 factory + BeanFactory parentBeanFactory = getParentBeanFactory(); + if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { + // Not found -> check parent. + // 没有 去 父工厂 找找 + String nameToLookup = originalBeanName(name); + if (args != null) { + // Delegation to parent with explicit args. + return (T) parentBeanFactory.getBean(nameToLookup, args); + } + else { + // No args -> delegate to standard getBean method. + return parentBeanFactory.getBean(nameToLookup, requiredType); + } + } + + if (!typeCheckOnly) { + // typeCheckOnly 为 false,将当前 beanName 放入一个 alreadyCreated 的 Set 集合中。 + markBeanAsCreated(beanName); + } + + try { + final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); + checkMergedBeanDefinition(mbd, beanName, args); + + // Guarantee initialization of beans that the current bean depends on. + // 确保 初始化的 这些 bean 所依赖的那些 bean 已经初始化成功。 + // 这里 依赖 是指 我们 配置中显式 depend-on 指定的 bean, + // 如果细看之前的步骤,那么对这个应该不陌生,之前有提到过 + String[] dependsOn = mbd.getDependsOn(); + if (dependsOn != null) { + for (String dep : dependsOn) { + if (isDependent(beanName, dep)) { + throw new BeanCreationException(mbd.getResourceDescription(), beanName, + "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); + } + registerDependentBean(dep, beanName); + getBean(dep); + } + } + + // Create bean instance. + // 创建 bean实例 + if (mbd.isSingleton()) { + sharedInstance = getSingleton(beanName, new ObjectFactory() { + @Override + public Object getObject() throws BeansException { + try { + return createBean(beanName, mbd, args); + } + catch (BeansException ex) { + // Explicitly remove instance from singleton cache: It might have been put there + // eagerly by the creation process, to allow for circular reference resolution. + // Also remove any beans that received a temporary reference to the bean. + destroySingleton(beanName); + throw ex; + } + } + }); + bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); + } + + else if (mbd.isPrototype()) { + // It's a prototype -> create a new instance. + Object prototypeInstance = null; + try { + beforePrototypeCreation(beanName); + prototypeInstance = createBean(beanName, mbd, args); + } + finally { + afterPrototypeCreation(beanName); + } + bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); + } + + else { + String scopeName = mbd.getScope(); + final Scope scope = this.scopes.get(scopeName); + if (scope == null) { + throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); + } + try { + Object scopedInstance = scope.get(beanName, new ObjectFactory() { + @Override + public Object getObject() throws BeansException { + beforePrototypeCreation(beanName); + try { + return createBean(beanName, mbd, args); + } + finally { + afterPrototypeCreation(beanName); + } + } + }); + bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); + } + catch (IllegalStateException ex) { + throw new BeanCreationException(beanName, + "Scope '" + scopeName + "' is not active for the current thread; consider " + + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", + ex); + } + } + } + catch (BeansException ex) { + cleanupAfterBeanCreationFailure(beanName); + throw ex; + } + } + + // Check if required type matches the type of the actual bean instance. + if (requiredType != null && bean != null && !requiredType.isInstance(bean)) { + try { + return getTypeConverter().convertIfNecessary(bean, requiredType); + } + catch (TypeMismatchException ex) { + if (logger.isDebugEnabled()) { + logger.debug("Failed to convert bean '" + name + "' to required type '" + + ClassUtils.getQualifiedName(requiredType) + "'", ex); + } + throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); + } + } + return (T) bean; + } + +``` + +```java +/** + * Central method of this class: creates a bean instance, + * populates the bean instance, applies post-processors, etc. + * @see #doCreateBean + */ +@Override +protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { + if (logger.isDebugEnabled()) { + logger.debug("Creating instance of bean '" + beanName + "'"); + } + RootBeanDefinition mbdToUse = mbd; + + // Make sure bean class is actually resolved at this point, and + // clone the bean definition in case of a dynamically resolved Class + // which cannot be stored in the shared merged bean definition. + Class resolvedClass = resolveBeanClass(mbd, beanName); + if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { + mbdToUse = new RootBeanDefinition(mbd); + mbdToUse.setBeanClass(resolvedClass); + } + + // Prepare method overrides. + try { + mbdToUse.prepareMethodOverrides(); + } + catch (BeanDefinitionValidationException ex) { + throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), + beanName, "Validation of method overrides failed", ex); + } + + try { + // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. + // 让 InstantiationAwareBeanPostProcessor 在这一步有机会返回代理, + Object bean = resolveBeforeInstantiation(beanName, mbdToUse); + if (bean != null) { + return bean; + } + } + catch (Throwable ex) { + throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, + "BeanPostProcessor before instantiation of bean failed", ex); + } + + Object beanInstance = doCreateBean(beanName, mbdToUse, args); + if (logger.isDebugEnabled()) { + logger.debug("Finished creating instance of bean '" + beanName + "'"); + } + return beanInstance; +} +``` + +### 真正生成Bean实例 + +```java +/** + * Actually create the specified bean. Pre-creation processing has already happened + * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks. + *

Differentiates between default bean instantiation, use of a + * factory method, and autowiring a constructor. + * @param beanName the name of the bean + * @param mbd the merged bean definition for the bean + * @param args explicit arguments to use for constructor or factory method invocation + * @return a new instance of the bean + * @throws BeanCreationException if the bean could not be created + * @see #instantiateBean + * @see #instantiateUsingFactoryMethod + * @see #autowireConstructor + */ +protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) + throws BeanCreationException { + + // Instantiate the bean. + BeanWrapper instanceWrapper = null; + if (mbd.isSingleton()) { + instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); + } + // 说明不是 FactoryBean + if (instanceWrapper == null) { + instanceWrapper = createBeanInstance(beanName, mbd, args); + } + final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); + Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); + mbd.resolvedTargetType = beanType; + + // Allow post-processors to modify the merged bean definition. + synchronized (mbd.postProcessingLock) { + if (!mbd.postProcessed) { + try { + applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); + } + catch (Throwable ex) { + throw new BeanCreationException(mbd.getResourceDescription(), beanName, + "Post-processing of merged bean definition failed", ex); + } + mbd.postProcessed = true; + } + } + + // Eagerly cache singletons to be able to resolve circular references + // even when triggered by lifecycle interfaces like BeanFactoryAware. + // 为了解决循环依赖问题 + boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && + isSingletonCurrentlyInCreation(beanName)); + if (earlySingletonExposure) { + if (logger.isDebugEnabled()) { + logger.debug("Eagerly caching bean '" + beanName + + "' to allow for resolving potential circular references"); + } + addSingletonFactory(beanName, new ObjectFactory() { + @Override + public Object getObject() throws BeansException { + return getEarlyBeanReference(beanName, mbd, bean); + } + }); + } + + // Initialize the bean instance. + Object exposedObject = bean; + try { + // 为实例 设值 + populateBean(beanName, mbd, instanceWrapper); + if (exposedObject != null) { + exposedObject = initializeBean(beanName, exposedObject, mbd); + } + } + catch (Throwable ex) { + if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { + throw (BeanCreationException) ex; + } + else { + throw new BeanCreationException( + mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); + } + } + + if (earlySingletonExposure) { + Object earlySingletonReference = getSingleton(beanName, false); + if (earlySingletonReference != null) { + if (exposedObject == bean) { + exposedObject = earlySingletonReference; + } + else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { + String[] dependentBeans = getDependentBeans(beanName); + Set actualDependentBeans = new LinkedHashSet(dependentBeans.length); + for (String dependentBean : dependentBeans) { + if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { + actualDependentBeans.add(dependentBean); + } + } + if (!actualDependentBeans.isEmpty()) { + throw new BeanCurrentlyInCreationException(beanName, + "Bean with name '" + beanName + "' has been injected into other beans [" + + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + + "] in its raw version as part of a circular reference, but has eventually been " + + "wrapped. This means that said other beans do not use the final version of the " + + "bean. This is often the result of over-eager type matching - consider using " + + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); + } + } + } + } + + // Register bean as disposable. + try { + registerDisposableBeanIfNecessary(beanName, bean, mbd); + } + catch (BeanDefinitionValidationException ex) { + throw new BeanCreationException( + mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); + } + + return exposedObject; +} +``` + +```java +/** + * Create a new instance for the specified bean, using an appropriate instantiation strategy: + * factory method, constructor autowiring, or simple instantiation. + * @param beanName the name of the bean + * @param mbd the bean definition for the bean + * @param args explicit arguments to use for constructor or factory method invocation + * @return BeanWrapper for the new instance + * @see #instantiateUsingFactoryMethod + * @see #autowireConstructor + * @see #instantiateBean + */ +// 根据 不同的策略生成 bean 如通常 构造器注入 等等 +protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { + // Make sure bean class is actually resolved at this point. + Class beanClass = resolveBeanClass(mbd, beanName); + + if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { + throw new BeanCreationException(mbd.getResourceDescription(), beanName, + "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); + } + + if (mbd.getFactoryMethodName() != null) { + return instantiateUsingFactoryMethod(beanName, mbd, args); + } + + // Shortcut when re-creating the same bean... + boolean resolved = false; + boolean autowireNecessary = false; + if (args == null) { + synchronized (mbd.constructorArgumentLock) { + if (mbd.resolvedConstructorOrFactoryMethod != null) { + resolved = true; + autowireNecessary = mbd.constructorArgumentsResolved; + } + } + } + if (resolved) { + // 构造器注入 + if (autowireNecessary) { + return autowireConstructor(beanName, mbd, null, null); + } + else { + // 构造函数依赖注入 + return instantiateBean(beanName, mbd); + } + } + + // Need to determine the constructor... + Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); + if (ctors != null || + mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || + mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { + return autowireConstructor(beanName, mbd, ctors, args); + } + + // No special handling: simply use no-arg constructor. + // 无参构造函数注入 + return instantiateBean(beanName, mbd); +} +``` + +```java +/** + * Instantiate the given bean using its default constructor. + * @param beanName the name of the bean + * @param mbd the bean definition for the bean + * @return BeanWrapper for the new instance + */ + protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { + try { + Object beanInstance; + final BeanFactory parent = this; + if (System.getSecurityManager() != null) { + beanInstance = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Object run() { + return getInstantiationStrategy().instantiate(mbd, beanName, parent); + } + }, getAccessControlContext()); + } + else { + beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); + } + BeanWrapper bw = new BeanWrapperImpl(beanInstance); + initBeanWrapper(bw); + return bw; + } + catch (Throwable ex) { + throw new BeanCreationException( + mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); + } + } +``` + +```java +@Override +public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) { + // Don't override the class with CGLIB if no overrides. + // 如果没有 重写 不要使用 CGLib + if (bd.getMethodOverrides().isEmpty()) { + Constructor constructorToUse; + synchronized (bd.constructorArgumentLock) { + constructorToUse = (Constructor) bd.resolvedConstructorOrFactoryMethod; + if (constructorToUse == null) { + final Class clazz = bd.getBeanClass(); + if (clazz.isInterface()) { + throw new BeanInstantiationException(clazz, "Specified class is an interface"); + } + try { + if (System.getSecurityManager() != null) { + constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction>() { + @Override + public Constructor run() throws Exception { + return clazz.getDeclaredConstructor((Class[]) null); + } + }); + } + else { + constructorToUse = clazz.getDeclaredConstructor((Class[]) null); + } + bd.resolvedConstructorOrFactoryMethod = constructorToUse; + } + catch (Throwable ex) { + throw new BeanInstantiationException(clazz, "No default constructor found", ex); + } + } + } + // 使用构造函数实例化 + return BeanUtils.instantiateClass(constructorToUse); + } + else { + // Must generate CGLIB subclass. + return instantiateWithMethodInjection(bd, beanName, owner); + } +} +``` + +### 设值 + +```java +/** + * Populate the bean instance in the given BeanWrapper with the property values + * from the bean definition. + * @param beanName the name of the bean + * @param mbd the bean definition for the bean + * @param bw BeanWrapper with bean instance + */ +// 给实例 设值 +protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) { + PropertyValues pvs = mbd.getPropertyValues(); + + if (bw == null) { + if (!pvs.isEmpty()) { + throw new BeanCreationException( + mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); + } + else { + // Skip property population phase for null instance. + return; + } + } + + // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the + // state of the bean before properties are set. This can be used, for example, + // to support styles of field injection. + // 到这步的时候,bean 实例化完成(通过工厂方法或构造方法),但是还没开始属性设值, + // InstantiationAwareBeanPostProcessor 的实现类可以在这里对 bean 进行状态修改, + boolean continueWithPropertyPopulation = true; + + if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { + for (BeanPostProcessor bp : getBeanPostProcessors()) { + if (bp instanceof InstantiationAwareBeanPostProcessor) { + InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; + if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { + continueWithPropertyPopulation = false; + break; + } + } + } + } + + if (!continueWithPropertyPopulation) { + return; + } + + if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || + mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { + MutablePropertyValues newPvs = new MutablePropertyValues(pvs); + + // Add property values based on autowire by name if applicable. + if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { + autowireByName(beanName, mbd, bw, newPvs); + } + + // Add property values based on autowire by type if applicable. + if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { + autowireByType(beanName, mbd, bw, newPvs); + } + + pvs = newPvs; + } + + boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); + boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); + + if (hasInstAwareBpps || needsDepCheck) { + PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); + if (hasInstAwareBpps) { + for (BeanPostProcessor bp : getBeanPostProcessors()) { + if (bp instanceof InstantiationAwareBeanPostProcessor) { + InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; + pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); + if (pvs == null) { + return; + } + } + } + } + if (needsDepCheck) { + checkDependencies(beanName, mbd, filteredPds, pvs); + } + } + + applyPropertyValues(beanName, mbd, bw, pvs); +} +``` + +### initializeBean + +```java +I/** + * Initialize the given bean instance, applying factory callbacks + * as well as init methods and bean post processors. + *

Called from {@link #createBean} for traditionally defined beans, + * and from {@link #initializeBean} for existing bean instances. + * @param beanName the bean name in the factory (for debugging purposes) + * @param bean the new bean instance we may need to initialize + * @param mbd the bean definition that the bean was created with + * (can also be {@code null}, if given an existing bean instance) + * @return the initialized bean instance (potentially wrapped) + * @see BeanNameAware + * @see BeanClassLoaderAware + * @see BeanFactoryAware + * @see #applyBeanPostProcessorsBeforeInitialization + * @see #invokeInitMethods + * @see #applyBeanPostProcessorsAfterInitialization + */ +protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { + if (System.getSecurityManager() != null) { + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Object run() { + invokeAwareMethods(beanName, bean); + return null; + } + }, getAccessControlContext()); + } + else { + // 如果 bean 实现了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,回调 + invokeAwareMethods(beanName, bean); + } + + Object wrappedBean = bean; + if (mbd == null || !mbd.isSynthetic()) { + wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); + } + + try { + // 处理 bean 中定义的 init-method, + // 或者如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet() 方法 + invokeInitMethods(beanName, wrappedBean, mbd); + } + catch (Throwable ex) { + throw new BeanCreationException( + (mbd != null ? mbd.getResourceDescription() : null), + beanName, "Invocation of init method failed", ex); + } + + if (mbd == null || !mbd.isSynthetic()) { + wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); + } + return wrappedBean; +} +``` \ No newline at end of file