From bc796b788564b34cb37e838e32f29dcffe0e49ce Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Wed, 31 Aug 2022 17:08:21 +0800 Subject: [PATCH 01/38] =?UTF-8?q?=E6=9A=91=E5=81=87=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../atguigu/hive/udf/CalStringLengthUDF.java | 31 ++++++++++-------- .../Spark010_RDD_Operator_Transform.scala | 3 ++ .../Spark01_RDD_Operator_Transform_Par.scala | 21 ++++++++++++ .../core/rdd/serial/Spark01_RDD_Serial.scala | 2 +- .../SparkStreaming11_Req1_blackList1.scala | 4 +-- .../chapter05/Scala04_Function_Normal_1.scala | 9 ++++++ .../chapter06/Scala05_Object_Field.scala | 1 + .../chapter06/Scala12_Object_Trait_4.scala | 3 +- .../chapter07/Scala01_Collection_1.scala | 12 +++++-- .../chapter07/Scala06_Collection_Seq.scala | 32 +++++++++---------- .../chapter07/Scala06_Collection_Seq_2.scala | 3 +- .../scala/chapter10/Scala01_Transform.scala | 2 +- .../java/com/atguigu/scala/test/TestAdd.java | 10 +++--- .../com/atguigu/scala/test/TestException.java | 4 ++- .../atguigu/userfile/app/ToBitmapApp.scala | 8 ++--- .../java/com/atguigu/zk/ZooKeeperTest.java | 1 + Spring/spring_aop/pom.xml | 1 + 17 files changed, 97 insertions(+), 50 deletions(-) diff --git a/Big_data_example/Hive/src/main/java/com/atguigu/hive/udf/CalStringLengthUDF.java b/Big_data_example/Hive/src/main/java/com/atguigu/hive/udf/CalStringLengthUDF.java index f4b8b36..67de391 100644 --- a/Big_data_example/Hive/src/main/java/com/atguigu/hive/udf/CalStringLengthUDF.java +++ b/Big_data_example/Hive/src/main/java/com/atguigu/hive/udf/CalStringLengthUDF.java @@ -10,31 +10,32 @@ import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectIn /** * 插件性质的开发: - * 1.实现接口或者继承类 - * 2.重写相应的方法 - * 3.打包 - * - * + * 1.实现接口或者继承类 + * 2.重写相应的方法 + * 3.打包 + *

+ *

* 自定义UDF函数类 - * 继承Hive提供的GenericUDF类 + * 继承Hive提供的GenericUDF类 */ public class CalStringLengthUDF extends GenericUDF { /** * 初始化方法 - * @param objectInspectors 传入到函数中的参数对应的类型的鉴别器对象 - * @return 指定函数的返回值类型对象的鉴别器对象 + * + * @param objectInspectors 传入到函数中的参数对应的类型的鉴别器对象 + * @return 指定函数的返回值类型对象的鉴别器对象 * @throws UDFArgumentException */ @Override public ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException { //1.校验函数的参数个数 - if(objectInspectors==null||objectInspectors.length!=1){ + if (objectInspectors == null || objectInspectors.length != 1) { throw new UDFArgumentLengthException("函数的参数个数不正确"); } //2.校验函数的参数类型,getCategory()返回的是传入的类型,PRIMITIVE表示基本类型 - if(!objectInspectors[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE)){ - throw new UDFArgumentTypeException(0,"磺酸钠会参数类型不正确"); + if (!objectInspectors[0].getCategory().equals(ObjectInspector.Category.PRIMITIVE)) { + throw new UDFArgumentTypeException(0, "函数的参数类型不正确"); } //3.返回函数的返回值类型对应的鉴别器类型 return PrimitiveObjectInspectorFactory.javaIntObjectInspector; @@ -42,15 +43,16 @@ public class CalStringLengthUDF extends GenericUDF { /** * 函数核心处理方法 - * @param deferredObjects 传入到函数的参数 - * @return 函数的返回值 + * + * @param deferredObjects 传入到函数的参数 + * @return 函数的返回值 * @throws HiveException */ public Object evaluate(DeferredObject[] deferredObjects) throws HiveException { //1.获取参数 Object argument = deferredObjects[0].get(); - if(argument==null){ + if (argument == null) { return 0; } return argument.toString().length(); @@ -58,6 +60,7 @@ public class CalStringLengthUDF extends GenericUDF { /** * 用于以后sql函数需要显示哪些内容 + * * @param strings * @return */ diff --git a/Big_data_example/Spark/src/main/java/com/atguigu/spark/core/rdd/operator/transform/Spark010_RDD_Operator_Transform.scala b/Big_data_example/Spark/src/main/java/com/atguigu/spark/core/rdd/operator/transform/Spark010_RDD_Operator_Transform.scala index 822e602..824c44a 100644 --- a/Big_data_example/Spark/src/main/java/com/atguigu/spark/core/rdd/operator/transform/Spark010_RDD_Operator_Transform.scala +++ b/Big_data_example/Spark/src/main/java/com/atguigu/spark/core/rdd/operator/transform/Spark010_RDD_Operator_Transform.scala @@ -25,7 +25,10 @@ object Spark010_RDD_Operator_Transform { //(null.null) =>null null //(1,null) =>1 val rdd1: RDD[Int] = rdd.distinct() + val rdd2=rdd.map(x=>(x,null)).reduceByKey((x, _) => x, 7) rdd1.collect().foreach(println(_)) + println("==========================") + rdd2.collect().foreach(println(_)) sc.stop() } diff --git a/Big_data_example/Spark/src/main/java/com/atguigu/spark/core/rdd/operator/transform/Spark01_RDD_Operator_Transform_Par.scala b/Big_data_example/Spark/src/main/java/com/atguigu/spark/core/rdd/operator/transform/Spark01_RDD_Operator_Transform_Par.scala index ceae497..736a09c 100644 --- a/Big_data_example/Spark/src/main/java/com/atguigu/spark/core/rdd/operator/transform/Spark01_RDD_Operator_Transform_Par.scala +++ b/Big_data_example/Spark/src/main/java/com/atguigu/spark/core/rdd/operator/transform/Spark01_RDD_Operator_Transform_Par.scala @@ -39,6 +39,27 @@ object Spark01_RDD_Operator_Transform_Par { } ) mapRDD1.collect() + /* + 结果: + >>>>>>1 + >>>>>>3 + ######1 + ######3 + >>>>>>2 + ######2 + >>>>>>4 + ######4 + 第二次: + >>>>>>3 + >>>>>>1 + ######1 + ######3 + >>>>>>2 + >>>>>>4 + ######4 + ######2 + TODO 即分区内的1和2一定是先1后2,分区内的3和4一定是先3后4,但是1和3谁先不一定 + */ sc.stop() } diff --git a/Big_data_example/Spark/src/main/java/com/atguigu/spark/core/rdd/serial/Spark01_RDD_Serial.scala b/Big_data_example/Spark/src/main/java/com/atguigu/spark/core/rdd/serial/Spark01_RDD_Serial.scala index 796d38f..d2e3bbd 100644 --- a/Big_data_example/Spark/src/main/java/com/atguigu/spark/core/rdd/serial/Spark01_RDD_Serial.scala +++ b/Big_data_example/Spark/src/main/java/com/atguigu/spark/core/rdd/serial/Spark01_RDD_Serial.scala @@ -17,7 +17,7 @@ object Spark01_RDD_Serial { //不加Serializable特质之前 // NotSerializableException: com.atguigu.spark.core.rdd.serial.Spark01_RDD_Serial$Search - //search.getMatch1(rdd).collect().foreach(println(_)) +// search.getMatch1(rdd).collect().foreach(println(_)) search.getMatch2(rdd).collect().foreach(println(_)) sc.stop() diff --git a/Big_data_example/Spark/src/main/java/com/atguigu/spark/streaming/SparkStreaming11_Req1_blackList1.scala b/Big_data_example/Spark/src/main/java/com/atguigu/spark/streaming/SparkStreaming11_Req1_blackList1.scala index 2253d7e..65cf3bf 100644 --- a/Big_data_example/Spark/src/main/java/com/atguigu/spark/streaming/SparkStreaming11_Req1_blackList1.scala +++ b/Big_data_example/Spark/src/main/java/com/atguigu/spark/streaming/SparkStreaming11_Req1_blackList1.scala @@ -113,7 +113,7 @@ object SparkStreaming11_Req1_blackList1 { println(s"${day} ${user} ${ad} ${sum}") if(sum >= 30){ //拉入黑名单 - val conn = JDBCUtil.getConnection +// val conn = JDBCUtil.getConnection val sql = """ |insert into black_list (userid) values (?) @@ -126,7 +126,7 @@ object SparkStreaming11_Req1_blackList1 { //将当天的广告点击数量进行更新 //查询统计表数据 - val conn = JDBCUtil.getConnection +// val conn = JDBCUtil.getConnection val sql = """ |select * diff --git a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter05/Scala04_Function_Normal_1.scala b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter05/Scala04_Function_Normal_1.scala index 4e8ce20..954c167 100644 --- a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter05/Scala04_Function_Normal_1.scala +++ b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter05/Scala04_Function_Normal_1.scala @@ -17,6 +17,15 @@ object Scala04_Function_Normal_1 { //调用时,如果不想使用默认值,直接传值即可 fun3("111111") //111111 + def fun4(username:String="dingjiawen",password:String="123456")={ + println(s"username:$username,password:$password") + } + + fun4() + fun4(password = "qazwsx") + fun4(password = "qazwsx",username = "123") + + } } diff --git a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter06/Scala05_Object_Field.scala b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter06/Scala05_Object_Field.scala index e68604c..d9df855 100644 --- a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter06/Scala05_Object_Field.scala +++ b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter06/Scala05_Object_Field.scala @@ -28,6 +28,7 @@ object Scala05_Object_Field { //而在scala中给属性提供的set,set方法不遵循bean规范,为了统一用于则有了下述写法 test.setEmail("xxx") test.getEmail() + println(test.email) } diff --git a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter06/Scala12_Object_Trait_4.scala b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter06/Scala12_Object_Trait_4.scala index a26d67c..2f09013 100644 --- a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter06/Scala12_Object_Trait_4.scala +++ b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter06/Scala12_Object_Trait_4.scala @@ -29,7 +29,8 @@ object Scala12_Object_Trait_4 { trait Log extends Operator{ override def operDate(): Unit ={ print("向文件中") - super.operDate() //如果想跳过DB直接访问Operator则使用super[Operator].operDate() +// super[Operator].operDate() //如果想跳过DB直接访问Operator则使用super[Operator].operDate() //向文件中操作数据... + super.operDate() //如果想跳过DB直接访问Operator则使用super[Operator].operDate() //向文件中向数据库中操作数据 } } class MySQL extends DB with Log { diff --git a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter07/Scala01_Collection_1.scala b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter07/Scala01_Collection_1.scala index efb38c8..cec56f7 100644 --- a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter07/Scala01_Collection_1.scala +++ b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter07/Scala01_Collection_1.scala @@ -1,5 +1,7 @@ package com.atguigu.scala.chapter07 +import scala.+: + object Scala01_Collection_1 { def main(args: Array[String]): Unit = { @@ -27,9 +29,13 @@ object Scala01_Collection_1 { //val ints1: Array[Int] = array1.:+(5) val ints1 = array1 :+ 5 + val ints3 =5 +: array1 val ints2 = array1 ++ array3 //val ints3 = array1 ++: array3 +// println(ints) +// println(ints1) +// println(ints2) println(array1 eq ints) //false println(array1 eq ints1) //false @@ -38,9 +44,9 @@ object Scala01_Collection_1 { // 遍历 //把集合中的元素用逗号分割形成一个字符串 -// println(ints.mkString(",")) //5,1,2,3,4 -// println(ints1.mkString(",")) //1,2,3,4,5 -// println(ints2.mkString(",")) //1,2,3,4,5,6,7,8 + println(ints.mkString(",")) //5,1,2,3,4 + println(ints1.mkString(",")) //1,2,3,4,5 + println(ints2.mkString(",")) //1,2,3,4,5,6,7,8 //foreach方法是一个循环的方法,需要穿第一个函数,这个传参数的类型是函数类型 // 函数类型 : Int => U diff --git a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter07/Scala06_Collection_Seq.scala b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter07/Scala06_Collection_Seq.scala index ff16686..2534fe7 100644 --- a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter07/Scala06_Collection_Seq.scala +++ b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter07/Scala06_Collection_Seq.scala @@ -9,33 +9,33 @@ object Scala06_Collection_Seq { //TODO - 集合 - Seq //一般会采用List - val seq = Seq(1,2,3,4) - val list = List(1,2,3,4) - val list1 = List(5,6,7,8) + val seq = Seq(1, 2, 3, 4) + val list = List(1, 2, 3, 4) + val list1 = List(5, 6, 7, 8) - println(seq) //List(1, 2, 3, 4) - println(list) //List(1, 2, 3, 4) + println(seq) //List(1, 2, 3, 4) + println(list) //List(1, 2, 3, 4) //TODO 常见数据操作 val ints: List[Int] = list :+ 5 val ints1: List[Int] = 5 +: list //Nil 在集合中表示空集合,增加集合的方式 - val ints2 = 1 :: 2 ::3 :: Nil + val ints2 = 1 :: 2 :: 3 :: Nil //准确写法是: //Nil.::(3).::(2).::(1) - val ints3 = 1 :: 2 ::3 ::list1 :: Nil - val ints4 = 1 :: 2 ::3 ::list1 ::: Nil + val ints3 = 1 :: 2 :: 3 :: list1 :: Nil + val ints4 = 1 :: 2 :: 3 :: list1 ::: Nil - println(list eq ints) //false - println(list) //List(1, 2, 3, 4) - println(ints) //List(1, 2, 3, 4, 5) - println(ints1) //List(5, 1, 2, 3, 4) - println(Nil) //List() - println(ints2) //List(1, 2, 3) - println(ints3) //List(1, 2, 3, List(5, 6, 7, 8)) - println(ints4) //List(1, 2, 3, 5, 6, 7, 8) + println(list eq ints) //false + println(list) //List(1, 2, 3, 4) + println(ints) //List(1, 2, 3, 4, 5) + println(ints1) //List(5, 1, 2, 3, 4) + println(Nil) //List() + println(ints2) //List(1, 2, 3) + println(ints3) //List(1, 2, 3, List(5, 6, 7, 8)) + println(ints4) //List(1, 2, 3, 5, 6, 7, 8) } } diff --git a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter07/Scala06_Collection_Seq_2.scala b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter07/Scala06_Collection_Seq_2.scala index 4debc4a..b7fa584 100644 --- a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter07/Scala06_Collection_Seq_2.scala +++ b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter07/Scala06_Collection_Seq_2.scala @@ -21,7 +21,8 @@ object Scala06_Collection_Seq_2 { // println(list) //ListBuffer(5, 3, 4, 2, 1) // // list.remove(1) -// list.remove(1,2) + println(list) + println(list.remove(1,2)) // // list.mkString() // list.iterator diff --git a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter10/Scala01_Transform.scala b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter10/Scala01_Transform.scala index b61e860..603a823 100644 --- a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter10/Scala01_Transform.scala +++ b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/chapter10/Scala01_Transform.scala @@ -18,7 +18,7 @@ object Scala01_Transform { } val age :Int = thirdPart() //Double ? Int? - println(age) + println(age.isInstanceOf[Double]) } def thirdPart(): Double ={ diff --git a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/test/TestAdd.java b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/test/TestAdd.java index e9c5c73..d7d0227 100644 --- a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/test/TestAdd.java +++ b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/test/TestAdd.java @@ -3,14 +3,14 @@ package com.atguigu.scala.test; public class TestAdd { public static void main(String[] args) { - //int i=0; - //int j=i++; + int i=0; +// int j=i++; //赋值是 等号右边的计算结果给左边 //i++不是原子性操作,中间会有临时的结果 - //i=i++; //print之后是1 _tmp=0; i=1; i=_tmp=0 + i=i++; //print之后是1 _tmp=0; i=1; i=_tmp=0 - //System.out.println("i="+i); // 1 - //System.out.println("j="+j); // 0 + System.out.println("i="+i); // 1 +// System.out.println("j="+j); // 0 //TODO 阶乘:一个大于1的数的阶乘等于这个数乘以他减一的数的阶乘 //5!=5*4!=5*4*3!=....=5*4*3*2*1 diff --git a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/test/TestException.java b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/test/TestException.java index 85c39a3..674459c 100644 --- a/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/test/TestException.java +++ b/Big_data_example/scala/scala0224/src/main/java/com/atguigu/scala/test/TestException.java @@ -2,6 +2,8 @@ package com.atguigu.scala.test; //import com.atguigu.scala.chapter09.Scala02_Exception; +import com.atguigu.scala.chapter09.Scala02_Exception; + import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -38,7 +40,7 @@ public class TestException { // } // System.out.println("xxxxxx"); -// Scala02_Exception.test(); + Scala02_Exception.test(); } diff --git a/Big_data_example/user_profile/toBitmap/src/main/scala/com/atguigu/userfile/app/ToBitmapApp.scala b/Big_data_example/user_profile/toBitmap/src/main/scala/com/atguigu/userfile/app/ToBitmapApp.scala index cce74b0..ac17414 100644 --- a/Big_data_example/user_profile/toBitmap/src/main/scala/com/atguigu/userfile/app/ToBitmapApp.scala +++ b/Big_data_example/user_profile/toBitmap/src/main/scala/com/atguigu/userfile/app/ToBitmapApp.scala @@ -22,7 +22,7 @@ object ToBitmapApp { def main(args: Array[String]): Unit = { //声明环境 - val sparkConf: SparkConf = new SparkConf().setAppName("bitmap_app")//.setMaster("local[*]") + val sparkConf: SparkConf = new SparkConf().setAppName("bitmap_app") //.setMaster("local[*]") val sparkSession: SparkSession = SparkSession.builder().config(sparkConf).enableHiveSupport().getOrCreate() val taskId: String = args(0); @@ -83,13 +83,12 @@ object ToBitmapApp { //TODO 需要做幂等性处理,每次插入数据前,需要做分区清理 //alter table ${bitmapTableName} delete where dt='$taskDate' - val clearSQL=s"alter table ${bitmapTableName} delete where dt='$taskDate'" + val clearSQL = s"alter table ${bitmapTableName} delete where dt='$taskDate'" println(clearSQL) ClickhouseUtils.executeSql(clearSQL) - - if(tagList.size >0){ + if (tagList.size > 0) { //('gender',gender),('agegroup',agegroup),('favor',favor) val tagCodeSQL: String = tagList.map( tagInfo => s"('${tagInfo.tagCode}',${tagInfo.tagCode.toLowerCase()})" @@ -113,7 +112,6 @@ object ToBitmapApp { } - } } diff --git a/Big_data_example/zookeeper/src/main/java/com/atguigu/zk/ZooKeeperTest.java b/Big_data_example/zookeeper/src/main/java/com/atguigu/zk/ZooKeeperTest.java index 50913eb..b511e5c 100644 --- a/Big_data_example/zookeeper/src/main/java/com/atguigu/zk/ZooKeeperTest.java +++ b/Big_data_example/zookeeper/src/main/java/com/atguigu/zk/ZooKeeperTest.java @@ -34,6 +34,7 @@ public class ZooKeeperTest { * @throws KeeperException * @throws InterruptedException */ + @Test public void deleteAll(String path,ZooKeeper zk) throws KeeperException, InterruptedException { //判断当前节点是否存在,获取stat diff --git a/Spring/spring_aop/pom.xml b/Spring/spring_aop/pom.xml index d2f568f..559c733 100644 --- a/Spring/spring_aop/pom.xml +++ b/Spring/spring_aop/pom.xml @@ -12,6 +12,7 @@ spring_aop war + org.springframework From 107c69cdf7217d187a00bfe0178a374f0a838cb7 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Thu, 1 Sep 2022 18:44:02 +0800 Subject: [PATCH 02/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Leecode/pom.xml | 28 ++++++ .../markilue/leecode/array/BinarySearch.java | 98 +++++++++++++++++++ .../markilue/leecode/array/RemoveElement.java | 4 + .../leecode}/listnode/addTwoNumbers.java | 4 +- .../leecode}/listnode/mergeKLists.java | 2 +- .../leecode}/listnode/mergeTwoLists.java | 2 +- .../leecode}/listnode/removeNthFromEnd.java | 2 +- .../listnode/selftry/mergeKLists.java | 4 +- .../listnode/selftry/mergeTwoLists.java | 5 +- .../listnode/selftry/removeNthFromEnd.java | 2 +- .../listnode/selftry/reverseKGroup.java | 4 +- .../leecode}/listnode/selftry/swapPairs.java | 2 +- .../markilue/leecode}/listnode/swapPairs.java | 2 +- .../markilue/leecode}/sort/ThreeSum.java | 10 +- .../com/markilue/leecode/test/Fibonaqi.java | 36 +++++++ .../markilue/leecode}/tree/DeleteNode.java | 7 +- .../leecode}/tree/InorderTraversal.java | 4 +- .../markilue/leecode}/tree/TreeNode.java | 2 +- 18 files changed, 187 insertions(+), 31 deletions(-) create mode 100644 Leecode/src/main/java/com/markilue/leecode/array/BinarySearch.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/array/RemoveElement.java rename Leecode/src/main/java/{ => com/markilue/leecode}/listnode/addTwoNumbers.java (96%) rename Leecode/src/main/java/{ => com/markilue/leecode}/listnode/mergeKLists.java (98%) rename Leecode/src/main/java/{ => com/markilue/leecode}/listnode/mergeTwoLists.java (97%) rename Leecode/src/main/java/{ => com/markilue/leecode}/listnode/removeNthFromEnd.java (98%) rename Leecode/src/main/java/{ => com/markilue/leecode}/listnode/selftry/mergeKLists.java (97%) rename Leecode/src/main/java/{ => com/markilue/leecode}/listnode/selftry/mergeTwoLists.java (94%) rename Leecode/src/main/java/{ => com/markilue/leecode}/listnode/selftry/removeNthFromEnd.java (97%) rename Leecode/src/main/java/{ => com/markilue/leecode}/listnode/selftry/reverseKGroup.java (83%) rename Leecode/src/main/java/{ => com/markilue/leecode}/listnode/selftry/swapPairs.java (96%) rename Leecode/src/main/java/{ => com/markilue/leecode}/listnode/swapPairs.java (97%) rename Leecode/src/main/java/{ => com/markilue/leecode}/sort/ThreeSum.java (94%) create mode 100644 Leecode/src/main/java/com/markilue/leecode/test/Fibonaqi.java rename Leecode/src/main/java/{ => com/markilue/leecode}/tree/DeleteNode.java (95%) rename Leecode/src/main/java/{ => com/markilue/leecode}/tree/InorderTraversal.java (99%) rename Leecode/src/main/java/{ => com/markilue/leecode}/tree/TreeNode.java (93%) diff --git a/Leecode/pom.xml b/Leecode/pom.xml index b4c264f..5813608 100644 --- a/Leecode/pom.xml +++ b/Leecode/pom.xml @@ -8,6 +8,34 @@ Leecode 1.0-SNAPSHOT + + + + + + + + + + org.projectlombok + lombok + 1.18.12 + provided + + + + + junit + junit + 4.13.2 + test + + + junit + junit + 4.13.2 + compile + org.projectlombok lombok diff --git a/Leecode/src/main/java/com/markilue/leecode/array/BinarySearch.java b/Leecode/src/main/java/com/markilue/leecode/array/BinarySearch.java new file mode 100644 index 0000000..277a04c --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/array/BinarySearch.java @@ -0,0 +1,98 @@ +package com.markilue.leecode.array; + +/** + * 力扣题号704:二分查找 + * 描述:给定一个n个元素有序的(升序)整型数组nums 和一个目标值target ,写一个函数搜索nums中的 target,如果目标值存在返回下标,否则返回 -1。 + * + */ +public class BinarySearch { + + public static void main(String[] args) { + int[] nums = {-1,0,3,5,9,12}; + int target = 9; + + System.out.println(search(nums,target)); + + + + } + + + /** + * 非递归法 + * @param nums + * @param target + * @return + */ + public static int search(int[] nums, int target) { + + int left=0; + int right = nums.length; + + + while (left>1避免right+left超过了int最大值 + //由于舍入问题,mid永远小于right,因此 可以写right = nums.length + int mid=left+((right-left)>>1); + if(nums[mid]target){ + right=mid; + }else { + return mid; + } + } + + return -1; + + } + + + /** + * 递归法 + * @param nums + * @param target + * @return + */ + public static int search1(int[] nums, int target) { + + //记录数组长度 + return find(nums,0,nums.length-1,target); + } + + public static int find(int[] nums,int start,int stop, int target){ + + + /** + * 解决N.5只能舍不能入,最后可能无限循环的问题 + */ + if(nums[start]==target){ + return start; + } + if(nums[stop]==target){ + return stop; + } + + if(start==stop-1&&nums[stop]!=target){ + return -1; + } + + + + if(start==stop){ + if(nums[start]==target){ + return start; + }else { + return -1; + } + } + int mid = start+(stop-start)/2; + if(nums[mid]target){ + return find(nums,start,mid,target); + }else { + return mid; + } + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/array/RemoveElement.java b/Leecode/src/main/java/com/markilue/leecode/array/RemoveElement.java new file mode 100644 index 0000000..28ad860 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/array/RemoveElement.java @@ -0,0 +1,4 @@ +package com.markilue.leecode.array; + +public class RemoveElement { +} diff --git a/Leecode/src/main/java/listnode/addTwoNumbers.java b/Leecode/src/main/java/com/markilue/leecode/listnode/addTwoNumbers.java similarity index 96% rename from Leecode/src/main/java/listnode/addTwoNumbers.java rename to Leecode/src/main/java/com/markilue/leecode/listnode/addTwoNumbers.java index 4e71e10..06c0b08 100644 --- a/Leecode/src/main/java/listnode/addTwoNumbers.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/addTwoNumbers.java @@ -1,4 +1,4 @@ -package listnode; +package com.markilue.leecode.listnode; /** * Definition for singly-linked list. * public class ListNode { @@ -10,8 +10,6 @@ package listnode; * } */ -import com.sun.corba.se.impl.resolver.SplitLocalResolverImpl; - /** * 2.两数相加 */ diff --git a/Leecode/src/main/java/listnode/mergeKLists.java b/Leecode/src/main/java/com/markilue/leecode/listnode/mergeKLists.java similarity index 98% rename from Leecode/src/main/java/listnode/mergeKLists.java rename to Leecode/src/main/java/com/markilue/leecode/listnode/mergeKLists.java index 03b0938..9470024 100644 --- a/Leecode/src/main/java/listnode/mergeKLists.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/mergeKLists.java @@ -1,4 +1,4 @@ -package listnode; +package com.markilue.leecode.listnode; public class mergeKLists { diff --git a/Leecode/src/main/java/listnode/mergeTwoLists.java b/Leecode/src/main/java/com/markilue/leecode/listnode/mergeTwoLists.java similarity index 97% rename from Leecode/src/main/java/listnode/mergeTwoLists.java rename to Leecode/src/main/java/com/markilue/leecode/listnode/mergeTwoLists.java index 2adebcc..580a8c8 100644 --- a/Leecode/src/main/java/listnode/mergeTwoLists.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/mergeTwoLists.java @@ -1,4 +1,4 @@ -package listnode; +package com.markilue.leecode.listnode; public class mergeTwoLists { diff --git a/Leecode/src/main/java/listnode/removeNthFromEnd.java b/Leecode/src/main/java/com/markilue/leecode/listnode/removeNthFromEnd.java similarity index 98% rename from Leecode/src/main/java/listnode/removeNthFromEnd.java rename to Leecode/src/main/java/com/markilue/leecode/listnode/removeNthFromEnd.java index 10e91e7..1bb03ea 100644 --- a/Leecode/src/main/java/listnode/removeNthFromEnd.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/removeNthFromEnd.java @@ -1,4 +1,4 @@ -package listnode; +package com.markilue.leecode.listnode; /** * 删除链表的倒数第N个节点 diff --git a/Leecode/src/main/java/listnode/selftry/mergeKLists.java b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/mergeKLists.java similarity index 97% rename from Leecode/src/main/java/listnode/selftry/mergeKLists.java rename to Leecode/src/main/java/com/markilue/leecode/listnode/selftry/mergeKLists.java index 76035c2..cee0228 100644 --- a/Leecode/src/main/java/listnode/selftry/mergeKLists.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/mergeKLists.java @@ -1,6 +1,4 @@ -package listnode.selftry; - -import listnode.mergeTwoLists; +package com.markilue.leecode.listnode.selftry; public class mergeKLists { diff --git a/Leecode/src/main/java/listnode/selftry/mergeTwoLists.java b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/mergeTwoLists.java similarity index 94% rename from Leecode/src/main/java/listnode/selftry/mergeTwoLists.java rename to Leecode/src/main/java/com/markilue/leecode/listnode/selftry/mergeTwoLists.java index f8fcfaa..669d4b9 100644 --- a/Leecode/src/main/java/listnode/selftry/mergeTwoLists.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/mergeTwoLists.java @@ -1,7 +1,4 @@ -package listnode.selftry; - -import listnode.addTwoNumbers; -import listnode.removeNthFromEnd; +package com.markilue.leecode.listnode.selftry; public class mergeTwoLists { diff --git a/Leecode/src/main/java/listnode/selftry/removeNthFromEnd.java b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/removeNthFromEnd.java similarity index 97% rename from Leecode/src/main/java/listnode/selftry/removeNthFromEnd.java rename to Leecode/src/main/java/com/markilue/leecode/listnode/selftry/removeNthFromEnd.java index 9585039..61450fd 100644 --- a/Leecode/src/main/java/listnode/selftry/removeNthFromEnd.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/removeNthFromEnd.java @@ -1,4 +1,4 @@ -package listnode.selftry; +package com.markilue.leecode.listnode.selftry; /** * 删除链表的倒数第N个节点 diff --git a/Leecode/src/main/java/listnode/selftry/reverseKGroup.java b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/reverseKGroup.java similarity index 83% rename from Leecode/src/main/java/listnode/selftry/reverseKGroup.java rename to Leecode/src/main/java/com/markilue/leecode/listnode/selftry/reverseKGroup.java index 6d2403f..c05f7d3 100644 --- a/Leecode/src/main/java/listnode/selftry/reverseKGroup.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/reverseKGroup.java @@ -1,6 +1,6 @@ -package listnode.selftry; +package com.markilue.leecode.listnode.selftry; -import listnode.swapPairs; +import com.markilue.leecode.listnode.swapPairs; public class reverseKGroup { diff --git a/Leecode/src/main/java/listnode/selftry/swapPairs.java b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/swapPairs.java similarity index 96% rename from Leecode/src/main/java/listnode/selftry/swapPairs.java rename to Leecode/src/main/java/com/markilue/leecode/listnode/selftry/swapPairs.java index fe7061e..8b81157 100644 --- a/Leecode/src/main/java/listnode/selftry/swapPairs.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/swapPairs.java @@ -1,4 +1,4 @@ -package listnode.selftry; +package com.markilue.leecode.listnode.selftry; diff --git a/Leecode/src/main/java/listnode/swapPairs.java b/Leecode/src/main/java/com/markilue/leecode/listnode/swapPairs.java similarity index 97% rename from Leecode/src/main/java/listnode/swapPairs.java rename to Leecode/src/main/java/com/markilue/leecode/listnode/swapPairs.java index 202be74..8515530 100644 --- a/Leecode/src/main/java/listnode/swapPairs.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/swapPairs.java @@ -1,4 +1,4 @@ -package listnode; +package com.markilue.leecode.listnode; diff --git a/Leecode/src/main/java/sort/ThreeSum.java b/Leecode/src/main/java/com/markilue/leecode/sort/ThreeSum.java similarity index 94% rename from Leecode/src/main/java/sort/ThreeSum.java rename to Leecode/src/main/java/com/markilue/leecode/sort/ThreeSum.java index 79675a9..ead26e1 100644 --- a/Leecode/src/main/java/sort/ThreeSum.java +++ b/Leecode/src/main/java/com/markilue/leecode/sort/ThreeSum.java @@ -1,6 +1,4 @@ -package sort; - -import com.sun.corba.se.impl.ior.FreezableList; +package com.markilue.leecode.sort; import java.util.*; @@ -34,7 +32,7 @@ public class ThreeSum { public static List> threeSum(int[] nums) { - List> parentList = new ArrayList<>(); + List> parentList = new ArrayList>(); if (nums.length < 3) { return parentList; @@ -78,7 +76,7 @@ public class ThreeSum { } //如果是第二个条件跳出的循环 if (nums[j] + nums[k] == need) { - List list = new ArrayList<>(); + List list = new ArrayList(); list.add(nums[i]); list.add(nums[j]); list.add(nums[k]); @@ -99,7 +97,7 @@ public class ThreeSum { //更简洁一点的思路 public static List> threeSum1(int[] nums) { - List> parentList = new ArrayList<>(); + List> parentList = new ArrayList>(); if (nums.length < 3) { return parentList; diff --git a/Leecode/src/main/java/com/markilue/leecode/test/Fibonaqi.java b/Leecode/src/main/java/com/markilue/leecode/test/Fibonaqi.java new file mode 100644 index 0000000..4cf42d6 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/test/Fibonaqi.java @@ -0,0 +1,36 @@ +package com.markilue.leecode.test; + +public class Fibonaqi { + + + /** + * 测试使用时间复杂度为n的斐波那契数列递归法 + * + */ +// @Test +// public static void testFibonaqi(){ +// +// } + + public static void main(String[] args) { + int n=5; + System.out.println(fibonacci(1,1,10)); + } + + public static int fibonacci(int first,int second,int n){ + if(n<=0){ + return 0; + } + if(n <3){ + return 1; + }else if(n==3){ + return first+second; + } + else { + return fibonacci(second,first+second,n-1); + } + } + + + +} diff --git a/Leecode/src/main/java/tree/DeleteNode.java b/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNode.java similarity index 95% rename from Leecode/src/main/java/tree/DeleteNode.java rename to Leecode/src/main/java/com/markilue/leecode/tree/DeleteNode.java index fef6b63..c347f45 100644 --- a/Leecode/src/main/java/tree/DeleteNode.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNode.java @@ -1,11 +1,10 @@ -package tree; +package com.markilue.leecode.tree; + -import lombok.Data; -import lombok.ToString; import java.util.List; -import static tree.InorderTraversal.inorderTraversal1; +import static com.markilue.leecode.tree.InorderTraversal.inorderTraversal1; /** * 删除二叉排序树的某个节点 diff --git a/Leecode/src/main/java/tree/InorderTraversal.java b/Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java similarity index 99% rename from Leecode/src/main/java/tree/InorderTraversal.java rename to Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java index f3e5758..920a458 100644 --- a/Leecode/src/main/java/tree/InorderTraversal.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java @@ -1,6 +1,6 @@ -package tree; +package com.markilue.leecode.tree; + -import lombok.Data; import java.util.ArrayList; import java.util.List; diff --git a/Leecode/src/main/java/tree/TreeNode.java b/Leecode/src/main/java/com/markilue/leecode/tree/TreeNode.java similarity index 93% rename from Leecode/src/main/java/tree/TreeNode.java rename to Leecode/src/main/java/com/markilue/leecode/tree/TreeNode.java index a216ba2..aad506b 100644 --- a/Leecode/src/main/java/tree/TreeNode.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/TreeNode.java @@ -1,4 +1,4 @@ -package tree; +package com.markilue.leecode.tree; import lombok.Data; From 4e78e2be81c1bb1cc3de577b30feb912a84a77d1 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Thu, 1 Sep 2022 20:05:13 +0800 Subject: [PATCH 03/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../markilue/leecode/array/RemoveElement.java | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/Leecode/src/main/java/com/markilue/leecode/array/RemoveElement.java b/Leecode/src/main/java/com/markilue/leecode/array/RemoveElement.java index 28ad860..eb6cdc8 100644 --- a/Leecode/src/main/java/com/markilue/leecode/array/RemoveElement.java +++ b/Leecode/src/main/java/com/markilue/leecode/array/RemoveElement.java @@ -1,4 +1,106 @@ package com.markilue.leecode.array; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * 移除元素: + * 给你一个数组 nums和一个值 val,你需要 原地 移除所有数值等于val的元素,并返回移除后数组的新长度。 + * 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 + * 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 + */ public class RemoveElement { + + + @Test + public void test(){ + int[] nums = {3,2,2,3}; + int val = 3; + int length = removeElement3(nums, val); + System.out.println("数组:"+ Arrays.toString(nums)); + System.out.println("数组长度:"+length); + } + + public int removeElement(int[] nums, int val) { + + int deleteNum = 0; + for (int i = 0; i < nums.length-deleteNum; i++) { + if(nums[i]==val){ + int flag = i; + for (int j = nums.length-1-deleteNum; j > i; j--) { + if(nums[j]!=val){ + flag=j; + break; + } + deleteNum+=1; + } + if(flag==i){ + deleteNum+=1; + break; + } + exchange(nums,i,flag); + deleteNum+=1; + + } + } + return nums.length-deleteNum; + + } + + + /** + * 快慢指针法 + * 由于不考虑后面是什么东西,因此可以直接将其覆盖 + * @param nums + * @param val + * @return + */ + public int removeElement1(int[] nums, int val){ + + int slowIndex=0; + for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) { + if(val!=nums[fastIndex]){ + nums[slowIndex++]=nums[fastIndex]; + } + + } + return slowIndex; + + } + + + /** + * 官方的快慢指针优化,双向奔赴 + * @param nums + * @param val + * @return + */ + public int removeElement3(int[] nums, int val) { + int left = 0; + int right = nums.length; + while (left < right) { + if (nums[left] == val) { + nums[left] = nums[right - 1]; + right--; + } else { + left++; + } + } + return left; + } + + /** + * 交换i,j + * @param nums + * @param i + * @param j + */ + public void exchange(int[] nums,int i,int j){ + int temp = nums[i]; + nums[i]=nums[j]; + nums[j]=temp; + } + } From 79f88b608143c0363f8bcb4ed64f761b9810f9be Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Fri, 2 Sep 2022 14:23:36 +0800 Subject: [PATCH 04/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leecode/array/MinSubArrayLen.java | 139 ++++++++++++++++++ .../leecode/array/generateMatrix.java | 62 ++++++++ 2 files changed, 201 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/array/MinSubArrayLen.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/array/generateMatrix.java diff --git a/Leecode/src/main/java/com/markilue/leecode/array/MinSubArrayLen.java b/Leecode/src/main/java/com/markilue/leecode/array/MinSubArrayLen.java new file mode 100644 index 0000000..65daa65 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/array/MinSubArrayLen.java @@ -0,0 +1,139 @@ +package com.markilue.leecode.array; + +import org.junit.Test; + +import javax.management.remote.rmi._RMIConnection_Stub; + +/** + * 寻找长度最小的子数组 + */ +public class MinSubArrayLen { + + + @Test + public void test() { + + int target = 3; + int[] nums = {1, 1, 1}; + System.out.println(minSubArrayLen2(target, nums)); + + } + + + /** + * 代码随想录中解法:可伸缩的滑动窗口 + * 看了思路之后自己尝试 + * 速度击败20% 内存击败60% + * @param target + * @param nums + * @return + */ + public int minSubArrayLen(int target, int[] nums) { + + int start = 0; + int stop = 0; + //记录窗口总和 + int sum = nums[start]; + //记录窗口长度 + int len = 0; + //记录结果 + int result = nums.length; + boolean flag = false; + while (stop <= nums.length) { + + while (sum >= target) { + flag = true; + len = stop - start + 1; + if (result > len) { + result = len; + } + if (len == 1) { + break; + } + sum -= nums[start++]; + } + if (len == 1 && sum > target) { + return 1; + } + if (stop == nums.length - 1) { + break; + } + + sum += nums[++stop]; + } + if (flag) { + return result; + } else { + return 0; + } + + + } + + /** + * 代码随想录中解法:可伸缩的滑动窗口 + * 官方实现:速度击败99.99%,内存击败58.84% + * + * @param target + * @param nums + * @return + */ + public int minSubArrayLen1(int target, int[] nums) { + + int start = 0; + int sum = 0; + int result = Integer.MAX_VALUE; + int len = 0; + + for (int stop = 0; stop < nums.length; stop++) { + sum += nums[stop]; + while (sum >= target) { + len = stop - start + 1; + result = result > len ? len : result; + sum -= nums[start++]; + } + } + + return result == Integer.MAX_VALUE ? 0 : result; + + + } + + /** + * 评论里给的滑动窗口法优化: + * 目前没看出优化在哪里,感觉没必要 + * @param s + * @param nums + * @return + */ + public int minSubArrayLen2(int s, int[] nums) { + if (nums.length == 0) { + return 0; + } + int count = 0; + int left = 0; + int right = 0; + while (count < s) { + if (right == nums.length) { + return 0; + } + count += nums[right]; + right++; + } + while (right < nums.length) { + if (count < s) { + count += nums[right]; + right++; + } + count -= nums[left]; + left++; + } + while (count >= s) { + count -= nums[left]; + left++; + } + return right - left + 1; + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/array/generateMatrix.java b/Leecode/src/main/java/com/markilue/leecode/array/generateMatrix.java new file mode 100644 index 0000000..ada702b --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/array/generateMatrix.java @@ -0,0 +1,62 @@ +package com.markilue.leecode.array; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * 螺旋矩阵: + * 给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix + */ +public class generateMatrix { + + + @Test + public void test(){ + + int[][] ints = generateMatrix(6); + for (int[] anInt : ints) { + System.out.println(Arrays.toString(anInt)); + } + + + } + + /** + * 看了代码随想录之后的自己编程:寻找循环不变量 + * 速度击败100%,内存击败87% + * 不会就先把第一层循环写出来,在找规律 + * @param n + * @return + */ + public int[][] generateMatrix(int n) { + int[][] result = new int[n][n]; + int count = 1; + int i=0; + int j=0; + for (int k = 0; k < n / 2; k++) { + + for (; i < result[k].length-k-1; i++) { + result[j][i]=count++; + } + for (; j < result[k].length-k-1; j++) { + result[j][i]=count++; + } + for (;i>k;i--){ + result[j][i]=count++; + } + for (;j>k;j--){ + result[j][i]=count++; + } + i+=1; + j+=1; + + } + //如果是奇数,单独填充中间的 + if(n%2==1){ + result[n/2][n/2]=count++; + } + return result; + + } +} From 1e4764c544a750fb5d6728bd4f1b48ed061acf29 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Mon, 5 Sep 2022 09:35:43 +0800 Subject: [PATCH 05/38] =?UTF-8?q?flink=E7=9A=84scala=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=B0=9D=E8=AF=95=EF=BC=8C=E5=B0=9A=E4=B8=94=E6=9C=89=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/day01/scala/Example_scala1.scala | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/Big_data_example/Flink/src/main/java/day01/scala/Example_scala1.scala b/Big_data_example/Flink/src/main/java/day01/scala/Example_scala1.scala index 0012541..d18b520 100644 --- a/Big_data_example/Flink/src/main/java/day01/scala/Example_scala1.scala +++ b/Big_data_example/Flink/src/main/java/day01/scala/Example_scala1.scala @@ -1,6 +1,9 @@ package day01.scala +import org.apache.flink.api.common.functions.FlatMapFunction +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment +import org.apache.flink.util.Collector object Example_scala1 { @@ -11,28 +14,49 @@ object Example_scala1 { env.setParallelism(1) //TODO 读取数据源 - val stream = env.socketTextStream("localhost", 9999) - -// stream.flatMap( -// words =>{ -// val word = words.split(" ") + // val stream = env.socketTextStream("localhost", 9999) + val stream = env.fromElements("hello world", "hello world") // -// word.map( -// word =>{ -// WordWithCount(word,1L) +// val value: SingleOutputStreamOperator[WordWithCount] = stream.flatMap[WordWithCount] { +// +// case (inputData:String, out:Collector[WordWithCount]) => { +// val strings = inputData.split(" ") +// strings.foreach { +// word => { +// out.collect(new WordWithCount(word, 1L)) // } -// ) -// +// } // } -// ) - - +// } + // val value: SingleOutputStreamOperator[WordWithCount] = stream.flatMap(new FlatMapFunction[String, WordWithCount] { + // override def flatMap(t: String, collector: Collector[WordWithCount]): Unit = { + // val strings = t.split(" ") + // strings.foreach { + // word => { + // collector.collect(new WordWithCount(word, 1L)) + // } + // } + // } + // }) +// value.print() + env.execute() + // stream.flatMap { + // words => { + // val word = words.split(" ") + // word.map( + // word => { + // WordWithCount(word, 1L) + // } + // ) + // } + // } } - case class WordWithCount(var word:String,var count:Long) + + case class WordWithCount(var word: String, var count: Long) } From f875a1841e2c5e051b45ce264694f047ac4d713f Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Mon, 5 Sep 2022 15:19:07 +0800 Subject: [PATCH 06/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leecode/listnode/MyLinkedList.java | 301 +++++++++++++++++ .../leecode/listnode/MyLinkedList1.java | 313 ++++++++++++++++++ .../leecode/listnode/RemoveElement.java | 157 +++++++++ 3 files changed, 771 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/listnode/MyLinkedList.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/listnode/MyLinkedList1.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/listnode/RemoveElement.java diff --git a/Leecode/src/main/java/com/markilue/leecode/listnode/MyLinkedList.java b/Leecode/src/main/java/com/markilue/leecode/listnode/MyLinkedList.java new file mode 100644 index 0000000..257ae3c --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/MyLinkedList.java @@ -0,0 +1,301 @@ +package com.markilue.leecode.listnode; + +import org.junit.Test; + +/** + * 设计链表: + * 设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val和next。val是当前节点的值,next是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性prev以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。 + * + * 在链表类中实现这些功能: + * + * get(index):获取链表中第index个节点的值。如果索引无效,则返回-1。 + * addAtHead(val):在链表的第一个元素之前添加一个值为val的节点。插入后,新节点将成为链表的第一个节点。 + * addAtTail(val):将值为val 的节点追加到链表的最后一个元素。 + * addAtIndex(index,val):在链表中的第index个节点之前添加值为val 的节点。如果index等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。 + * deleteAtIndex(index):如果索引index 有效,则删除链表中的第index 个节点。 + * + * Your MyLinkedList object will be instantiated and called as such: + * MyLinkedList obj = new MyLinkedList(); + * int param_1 = obj.get(index); + * obj.addAtHead(val); + * obj.addAtTail(val); + * obj.addAtIndex(index,val); + * obj.deleteAtIndex(index); + */ +public class MyLinkedList { + + public ListNode head; + + public MyLinkedList() { + + } + + public int get(int index) { + + int count = 0; + //避免head发生变化 + ListNode temp=head; + while (count!=index&&temp!=null){ + temp = temp.next; + count++; + } + //找到了对应的index + if(count==index){ + if(temp!=null){ + return temp.val; + } + } + + return -1; + + } + + public void addAtHead(int val) { + if(head==null){ + head=new ListNode(val); + return; + } + ListNode neededAddNode = new ListNode(val); + ListNode tempHead=new ListNode(0); + tempHead.next=neededAddNode; + neededAddNode.next=head; + head=tempHead.next; + + } + + public void addAtTail(int val) { + if(head==null){ + head=new ListNode(val); + return; + } + ListNode temp=head; + while (temp.next!=null){ + temp=temp.next; + } + temp.next=new ListNode(val); + + } + + public void addAtIndex(int index, int val) { + if(index>getSize()){ + return; + } + + if(index<=0){ + addAtHead(val); + } + + int count = 0; + //避免head发生变化 + ListNode temp=head; + while (count!=index-1&&temp.next!=null){ + temp = temp.next; + count++; + } + //找到了对应的index + if(count==index-1){ + ListNode need = new ListNode(val); + need.next=temp.next; + temp.next=need; + }else { + System.out.println("index超过限制"); + } + + } + + public void deleteAtIndex(int index) { + + if(head==null){ + return; + } + + if(index==0){ + head=head.next; + return; + } + + int count = 0; + //避免head发生变化 + ListNode temp=head; + while (count!=index-1&&temp.next!=null){ + temp = temp.next; + count++; + } + //找到了对应的index + if(count==index-1){ + if(temp.next!=null){ + temp.next=temp.next.next; + } + }else { + System.out.println("index超过限制"); + } + + } + + public void printList(ListNode head) { + + if(head==null){ + System.out.println("链表为空"); + return; + } + + while (head!=null){ + System.out.printf(head.val+"->"); + head=head.next; + } + + System.out.println(); + + + } + + public int getSize(){ + int size=0; + ListNode temp=head; + while (temp!=null){ + size+=1; + temp=temp.next; + } + + return size; + } + + + @Test + public void test(){ + MyLinkedList linkedList = new MyLinkedList(); + linkedList.addAtHead(1); + printList(linkedList.head); + System.out.println(); + linkedList.addAtTail(3); + printList(linkedList.head); + System.out.println(); + linkedList.addAtIndex(1,2); //链表变为1-> 2-> 3 + printList(linkedList.head); + System.out.println(); + System.out.println(linkedList.get(1)); +// printList(linkedList.head); + System.out.println(); + linkedList.deleteAtIndex(1); //现在链表是1-> 3 + printList(linkedList.head); + System.out.println(); + System.out.println(linkedList.get(1)); + + + } + @Test + public void test1(){ + MyLinkedList linkedList = new MyLinkedList(); + linkedList.addAtHead(7); + printList(linkedList.head); + + linkedList.addAtHead(2); + printList(linkedList.head); + + linkedList.addAtHead(1); + printList(linkedList.head); + + linkedList.addAtIndex(3,0); + printList(linkedList.head); + + linkedList.deleteAtIndex(2); + printList(linkedList.head); + + linkedList.addAtHead(6); + printList(linkedList.head); + + linkedList.addAtTail(4); + printList(linkedList.head); + + System.out.println(linkedList.get(4)); + + linkedList.addAtHead(4); + printList(linkedList.head); + + linkedList.addAtIndex(5,0); + printList(linkedList.head); + + linkedList.addAtHead(6); + printList(linkedList.head); + + +// System.out.println(linkedList.get(1)); +//// printList(linkedList.head); +// System.out.println(); +// linkedList.deleteAtIndex(1); //现在链表是1-> 3 +// printList(linkedList.head); +// System.out.println(); +// System.out.println(linkedList.get(1)); + + + } + @Test + public void test2(){ + MyLinkedList linkedList = new MyLinkedList(); + linkedList.addAtHead(2); + printList(linkedList.head); + + linkedList.deleteAtIndex(1); + printList(linkedList.head); + + linkedList.addAtHead(2); + printList(linkedList.head); + + linkedList.addAtHead(7); + printList(linkedList.head); + + linkedList.addAtHead(3); + printList(linkedList.head); + + linkedList.addAtHead(2); + printList(linkedList.head); + + linkedList.addAtHead(5); + printList(linkedList.head); + + linkedList.addAtTail(5); + printList(linkedList.head); + + System.out.println(linkedList.get(5)); + + linkedList.deleteAtIndex(6); + printList(linkedList.head); + + linkedList.deleteAtIndex(4); + printList(linkedList.head); + + + } + + @Test + public void test3(){ + MyLinkedList linkedList = new MyLinkedList(); + linkedList.addAtHead(1); + printList(linkedList.head); + + + linkedList.addAtTail(3); + printList(linkedList.head); + + linkedList.addAtIndex(1,2); + printList(linkedList.head); + + + System.out.println(linkedList.get(1)); + + linkedList.deleteAtIndex(1); + printList(linkedList.head); + + System.out.println(linkedList.get(1)); + + + } + + /* + 错了四五次之后通过 + 内存超过79.95%,速度超过9.96%,慢的原因:每次都要算一遍getSize + 改进:维护一个变量size,每次容量变化都让size也跟着变化一次;此外,还可以维护一个虚拟的头结点,不存放任何数据; + 具体操作参考MyLinkedList1 + */ +} + diff --git a/Leecode/src/main/java/com/markilue/leecode/listnode/MyLinkedList1.java b/Leecode/src/main/java/com/markilue/leecode/listnode/MyLinkedList1.java new file mode 100644 index 0000000..e022842 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/MyLinkedList1.java @@ -0,0 +1,313 @@ +package com.markilue.leecode.listnode; + +import org.junit.Test; + +/** + * 设计链表: + * 设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val和next。val是当前节点的值,next是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性prev以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。 + *

+ * 在链表类中实现这些功能: + *

+ * get(index):获取链表中第index个节点的值。如果索引无效,则返回-1。 + * addAtHead(val):在链表的第一个元素之前添加一个值为val的节点。插入后,新节点将成为链表的第一个节点。 + * addAtTail(val):将值为val 的节点追加到链表的最后一个元素。 + * addAtIndex(index,val):在链表中的第index个节点之前添加值为val 的节点。如果index等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。 + * deleteAtIndex(index):如果索引index 有效,则删除链表中的第index 个节点。 + *

+ * Your MyLinkedList object will be instantiated and called as such: + * MyLinkedList obj = new MyLinkedList(); + * int param_1 = obj.get(index); + * obj.addAtHead(val); + * obj.addAtTail(val); + * obj.addAtIndex(index,val); + * obj.deleteAtIndex(index); + */ +public class MyLinkedList1 { + + //该head为虚拟节点,不存放任何数据 + public ListNode head; + public int size; + + public MyLinkedList1() { + head = new ListNode(0); + size = 0; + } + + public int get(int index) { + + if (size < index+1 || index < 0) { + return -1; + } + + //避免head发生变化 + ListNode temp = head.next; + while (index-- > 0) { + temp = temp.next; + } + return temp.val; + + } + + public void addAtHead(int val) { + + ListNode need = new ListNode(val); + need.next = head.next; + head.next = need; + size++; + } + + public void addAtTail(int val) { + + ListNode need = new ListNode(val); + ListNode temp = head; + + while (temp.next != null) { + temp = temp.next; + } + + temp.next = need; + size++; + } + + public void addAtIndex(int index, int val) { + + if (index > size || index < 0) { + return; + } + ListNode temp = head; + while (index-- > 0) { + temp = temp.next; + } + + ListNode need = new ListNode(val); + need.next = temp.next; + temp.next = need; + size++; + } + + public void deleteAtIndex(int index) { + + if (index > size-1 || index < 0) { + return; + } + ListNode temp = head; + while (index-- > 0) { + temp = temp.next; + } + + temp.next = temp.next.next; + size--; + } + + public void printList(ListNode head) { + + ListNode temp=head.next; + + while (temp!=null){ + System.out.printf(temp.val+"->"); + temp=temp.next; + } + + System.out.println(); + + + } + + public int getSize() { + + return size; + + } + + + @Test + public void test() { + MyLinkedList1 linkedList = new MyLinkedList1(); + linkedList.addAtHead(1); + printList(linkedList.head); + System.out.println(); + linkedList.addAtTail(3); + printList(linkedList.head); + System.out.println(); + linkedList.addAtIndex(1, 2); //链表变为1-> 2-> 3 + printList(linkedList.head); + System.out.println(); + System.out.println(linkedList.get(1)); +// printList(linkedList.head); + System.out.println(); + linkedList.deleteAtIndex(1); //现在链表是1-> 3 + printList(linkedList.head); + System.out.println(); + System.out.println(linkedList.get(1)); + + + } + + @Test + public void test1() { + MyLinkedList1 linkedList = new MyLinkedList1(); + linkedList.addAtHead(7); + printList(linkedList.head); + + linkedList.addAtHead(2); + printList(linkedList.head); + + linkedList.addAtHead(1); + printList(linkedList.head); + + linkedList.addAtIndex(3, 0); + printList(linkedList.head); + + linkedList.deleteAtIndex(2); + printList(linkedList.head); + + linkedList.addAtHead(6); + printList(linkedList.head); + + linkedList.addAtTail(4); + printList(linkedList.head); + + System.out.println(linkedList.get(4)); + + linkedList.addAtHead(4); + printList(linkedList.head); + + linkedList.addAtIndex(5, 0); + printList(linkedList.head); + + linkedList.addAtHead(6); + printList(linkedList.head); + + +// System.out.println(linkedList.get(1)); +//// printList(linkedList.head); +// System.out.println(); +// linkedList.deleteAtIndex(1); //现在链表是1-> 3 +// printList(linkedList.head); +// System.out.println(); +// System.out.println(linkedList.get(1)); + + + } + + @Test + public void test2() { + MyLinkedList1 linkedList = new MyLinkedList1(); + linkedList.addAtHead(2); + printList(linkedList.head); + + linkedList.deleteAtIndex(1); + printList(linkedList.head); + + linkedList.addAtHead(2); + printList(linkedList.head); + + linkedList.addAtHead(7); + printList(linkedList.head); + + linkedList.addAtHead(3); + printList(linkedList.head); + + linkedList.addAtHead(2); + printList(linkedList.head); + + linkedList.addAtHead(5); + printList(linkedList.head); + + linkedList.addAtTail(5); + printList(linkedList.head); + + System.out.println(linkedList.get(5)); + + linkedList.deleteAtIndex(6); + printList(linkedList.head); + + linkedList.deleteAtIndex(4); + printList(linkedList.head); + + + } + + @Test + public void test3() { + MyLinkedList1 linkedList = new MyLinkedList1(); + linkedList.addAtHead(1); + printList(linkedList.head); + + + linkedList.addAtTail(3); + printList(linkedList.head); + + linkedList.addAtIndex(1, 2); + printList(linkedList.head); + + + System.out.println(linkedList.get(1)); + + linkedList.deleteAtIndex(1); + printList(linkedList.head); + + System.out.println(linkedList.get(1)); + + + } + + @Test + public void test4() { + MyLinkedList1 linkedList = new MyLinkedList1(); + linkedList.addAtHead(4); + printList(linkedList.head); + + System.out.println(linkedList.get(1)); + + linkedList.addAtHead(1); + printList(linkedList.head); + + linkedList.addAtHead(5); + printList(linkedList.head); + + linkedList.deleteAtIndex(3); + printList(linkedList.head); + + linkedList.addAtHead(7); + printList(linkedList.head); + + System.out.println(linkedList.get(3)); + + System.out.println(linkedList.get(3)); + + System.out.println(linkedList.get(3)); + + linkedList.addAtHead(1); + printList(linkedList.head); + + + linkedList.deleteAtIndex(4); + printList(linkedList.head); + + + + + } + + /* + 内存超过99.29%,速度超过30.86% + */ +} + +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; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/listnode/RemoveElement.java b/Leecode/src/main/java/com/markilue/leecode/listnode/RemoveElement.java new file mode 100644 index 0000000..0f95961 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/RemoveElement.java @@ -0,0 +1,157 @@ +package com.markilue.leecode.listnode; + +import org.junit.Test; + +/** + * 移除链表元素: + * 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。 + */ +public class RemoveElement { + + + @Test + public void test1() { + ListNode listNode = new ListNode(1); + ListNode listNode2 = new ListNode(2); + ListNode listNode3 = new ListNode(6); + ListNode listNode4 = new ListNode(3); + ListNode listNode5 = new ListNode(4); + ListNode listNode6 = new ListNode(5); + ListNode listNode7 = new ListNode(6); + listNode.next = listNode2; + listNode2.next = listNode3; + listNode3.next = listNode4; + listNode4.next = listNode5; + listNode5.next = listNode6; + listNode6.next = listNode7; + ListNode result = removeElements(listNode, 6); + print(result); + + } + + @Test + public void test2() { + + ListNode listNode = removeElements(null, 1); + print(listNode); + + } + + @Test + public void test3() { + + ListNode listNode = new ListNode(7); + ListNode listNode2 = new ListNode(7); + ListNode listNode3 = new ListNode(7); + ListNode listNode4 = new ListNode(7); + listNode.next = listNode2; + listNode2.next = listNode3; + listNode3.next = listNode4; + + ListNode result = removeElements1(listNode, 7); + print(result); + + } + + + /** + * 内存击败45%,速度击败50% + * @param head + * @param val + * @return + */ + public ListNode removeElements(ListNode head, int val) { + + if (head == null) { + return head; + } + + //创建一个虚拟头节点用于返回 + ListNode listNode = new ListNode(); + listNode.next = head; + ListNode recu = listNode; + + + while (recu.next != null) { + print(listNode); + System.out.println(); + + if (recu.next.val == val) { + recu.next = recu.next.next; + } else { + recu = recu.next; + } + } + + return listNode.next; + + } + + /** + * 改进版,不一定要直接找下一个,可以找下一个不是val的元素 + * 速度还是击败50%,内存击败84% + * @param head + * @param val + * @return + */ + public ListNode removeElements1(ListNode head, int val) { + + if (head == null) { + return head; + } + + //创建一个虚拟头节点用于返回 + ListNode listNode = new ListNode(); + listNode.next = head; + ListNode recu = listNode; + + + while (recu.next != null) { + print(listNode); + System.out.println(); + + if (recu.next.val == val) { + while (recu.next.next!=null&&recu.next.next.val==val){ + recu.next.next=recu.next.next.next; + } + recu.next = recu.next.next; + } else { + recu = recu.next; + } + } + + return listNode.next; + + } + + + 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; + } + } + + public void print(ListNode listNode) { + if (listNode == null) { + System.out.println("链表为空"); + return; + } + while (listNode != null) { + System.out.printf(listNode.val + "->"); + listNode = listNode.next; + } + } + + +} From f196a9939371c20cf37729285b6dafcb2c21fd58 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Tue, 6 Sep 2022 09:14:19 +0800 Subject: [PATCH 07/38] =?UTF-8?q?flink=E6=9B=B4=E6=96=B0=E5=92=8C=E5=A4=8D?= =?UTF-8?q?=E4=B9=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Flink/src/main/java/day03/Example5.java | 2 +- .../java/day03/selftry/Example5_retry.java | 125 ++++++++++++++++++ .../Flink/src/main/java/day04/Example2.java | 2 +- .../Flink/src/main/java/day04/Example7.java | 2 +- .../Flink/src/main/java/day06/Example4.java | 4 +- 5 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 Big_data_example/Flink/src/main/java/day03/selftry/Example5_retry.java diff --git a/Big_data_example/Flink/src/main/java/day03/Example5.java b/Big_data_example/Flink/src/main/java/day03/Example5.java index 23f84ba..1c55a5c 100644 --- a/Big_data_example/Flink/src/main/java/day03/Example5.java +++ b/Big_data_example/Flink/src/main/java/day03/Example5.java @@ -48,7 +48,7 @@ public class Example5 { //声明一个状态变量作为累加器 //状态变量的可见范围(作用域)的当前key - //状态变量是单例,只能被实例化一次 + //状态变量是单例,只能被实例化一次, private ValueState> valueState; //保存定时器的时间戳 private ValueState timerTs; diff --git a/Big_data_example/Flink/src/main/java/day03/selftry/Example5_retry.java b/Big_data_example/Flink/src/main/java/day03/selftry/Example5_retry.java new file mode 100644 index 0000000..6ebd254 --- /dev/null +++ b/Big_data_example/Flink/src/main/java/day03/selftry/Example5_retry.java @@ -0,0 +1,125 @@ +package day03.selftry; + +import org.apache.flink.api.common.state.ValueState; +import org.apache.flink.api.common.state.ValueStateDescriptor; +import org.apache.flink.api.common.typeinfo.Types; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.configuration.Configuration; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.functions.KeyedProcessFunction; +import org.apache.flink.streaming.api.functions.source.SourceFunction; +import org.apache.flink.util.Collector; + +import java.util.Random; + +/** + * @BelongsProject: Flink + * @BelongsPackage: day03.selftry + * @Author: dingjiawen + * @CreateTime: 2022-09-05 16:06 + * @Description: TODO example5_retry,尝试计算十秒内的平均值 + * @Version: 1.0 + */ +public class Example5_retry { + + + public static void main(String[] args) throws Exception { + + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + env.setParallelism(1); + + env + .addSource( + new SourceFunction() { + + private Random random = new Random(); + private boolean running = true; + + @Override + public void run(SourceContext sourceContext) throws Exception { + + while (running) { + int i = random.nextInt(10); + sourceContext.collect(i); + Thread.sleep(1000); + } + + } + + @Override + public void cancel() { + running = false; + } + } + ) + .keyBy(r -> true) + .process(new KeyedProcessFunction() { + + //设置两个状态后端 + //用于存储<值之和,数量> + private ValueState> valueState; + //存储一个定时器,多久做一次定时任务 + private ValueState timeTs; + + + //在任务开始时注册并实例化两个状态后端 + @Override + public void open(Configuration parameters) throws Exception { + super.open(parameters); + valueState = getRuntimeContext().getState( + //第一个值是名字,第二个值是类型 + new ValueStateDescriptor>("sum-count", Types.TUPLE(Types.INT, Types.INT)) + ); + timeTs = getRuntimeContext().getState( + new ValueStateDescriptor("timer", Types.LONG) + ); + } + + //对每一个值进行处理,并且设置定时器 + @Override + public void processElement(Integer integer, Context context, Collector collector) throws Exception { + //如果该状态后端的值是null就证明是第一次调用 + if (valueState.value() == null) { + valueState.update(Tuple2.of(integer, 1)); + } else { + //之后的调用了 + Tuple2 temp = valueState.value(); + valueState.update(Tuple2.of(temp.f0 + integer, temp.f1 + 1)); + } + + //第一次进来时设置定时器 + if (timeTs.value() == null) { + //先根据context获取到当前的处理时间 + long currentTime = context.timerService().currentProcessingTime(); + //在上下文中注册对应的定时器 + context.timerService().registerProcessingTimeTimer(currentTime + 10 * 1000L); + //更新定时器,避免下次再进入这个if + timeTs.update(1111L); + } + + } + + //定时器函数,当定时器触发时会进行调用 + @Override + public void onTimer(long timestamp, OnTimerContext ctx, Collector out) throws Exception { +// super.onTimer(timestamp, ctx, out); + if (valueState.value() != null) { + //定时器触发,开始计算平均值,并将其放入收集器collect中 + out.collect((double) valueState.value().f0 / valueState.value().f1); + //将定时器清空 + timeTs.clear(); + } + + + } + }) + .print(); + + + env.execute(); + + + } + + +} diff --git a/Big_data_example/Flink/src/main/java/day04/Example2.java b/Big_data_example/Flink/src/main/java/day04/Example2.java index 28e5e91..d59c462 100644 --- a/Big_data_example/Flink/src/main/java/day04/Example2.java +++ b/Big_data_example/Flink/src/main/java/day04/Example2.java @@ -48,7 +48,7 @@ public class Example2 { //迭代器参数中只包含了一个元素,就是增量聚合函数发送过来的聚合结果 long windowStart =context.window().getStart(); long windowEnd = context.window().getEnd(); - long count = iterable.iterator().next(); //取出增量聚合函数的哪一个元素 + long count = iterable.iterator().next(); //取出增量聚合函数的那一个元素 collector.collect("用户:"+key+"在窗口" +""+new Timestamp(windowStart)+"~"+new Timestamp(windowEnd) +""+"中的pv次数是:"+count); diff --git a/Big_data_example/Flink/src/main/java/day04/Example7.java b/Big_data_example/Flink/src/main/java/day04/Example7.java index 3c91791..3c70385 100644 --- a/Big_data_example/Flink/src/main/java/day04/Example7.java +++ b/Big_data_example/Flink/src/main/java/day04/Example7.java @@ -33,7 +33,7 @@ public class Example7 { env.setParallelism(1); env - .readTextFile("E:\\Big_data_example\\Flink\\src\\main\\resources\\UserBehavior.csv") + .readTextFile("D:\\example\\self_example\\Big_data_example\\Flink\\src\\main\\resources\\UserBehavior.csv") .map(new MapFunction() { @Override public UserBehavior map(String value) throws Exception { diff --git a/Big_data_example/Flink/src/main/java/day06/Example4.java b/Big_data_example/Flink/src/main/java/day06/Example4.java index 80aba21..fcb5946 100644 --- a/Big_data_example/Flink/src/main/java/day06/Example4.java +++ b/Big_data_example/Flink/src/main/java/day06/Example4.java @@ -54,7 +54,7 @@ public class Example4 { orderStream.keyBy(r ->r.userId) .intervalJoin(pvStream.keyBy(r -> r.userId)) //第一条流和第二条流的哪一段join - //最近10min和未来10min以内的 + //最近10min和未来5min以内的 .between(Time.minutes(-10),Time.minutes(5)) .process(new ProcessJoinFunction() { @Override @@ -67,7 +67,7 @@ public class Example4 { pvStream.keyBy(r ->r.userId) .intervalJoin(orderStream.keyBy(r -> r.userId)) //第一条流和第二条流的哪一段join - //最近10min和未来10min以内的 + //最近5min和未来10min以内的 .between(Time.minutes(-5),Time.minutes(10)) .process(new ProcessJoinFunction() { @Override From 7e0a828387968a1359156fd11e44440ea0bd8ede Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Wed, 7 Sep 2022 09:16:19 +0800 Subject: [PATCH 08/38] =?UTF-8?q?flink=E5=AF=B9=E6=8E=A5redis=E5=92=8C?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89sink=E8=BF=9E=E6=8E=A5mysql?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Big_data_example/Flink/pom.xml | 9 ++ .../Flink/src/main/java/day07/Example3.java | 64 +++++++++++ .../Flink/src/main/java/day07/Example4.java | 93 ++++++++++++++++ .../leecode/listnode/DetectCycle.java | 90 +++++++++++++++ .../leecode/listnode/ReverseList.java | 104 ++++++++++++++++++ .../leecode/listnode/removeNthFromEnd.java | 58 +++++++++- 6 files changed, 412 insertions(+), 6 deletions(-) create mode 100644 Big_data_example/Flink/src/main/java/day07/Example3.java create mode 100644 Big_data_example/Flink/src/main/java/day07/Example4.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/listnode/DetectCycle.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/listnode/ReverseList.java diff --git a/Big_data_example/Flink/pom.xml b/Big_data_example/Flink/pom.xml index 42391f1..6cd64ca 100644 --- a/Big_data_example/Flink/pom.xml +++ b/Big_data_example/Flink/pom.xml @@ -91,6 +91,9 @@ ${flink.verison} + + + org.slf4j slf4j-log4j12 @@ -124,6 +127,12 @@ ${flink.verison} + + org.apache.bahir + flink-connector-redis_2.11 + 1.0 + + diff --git a/Big_data_example/Flink/src/main/java/day07/Example3.java b/Big_data_example/Flink/src/main/java/day07/Example3.java new file mode 100644 index 0000000..ba0e459 --- /dev/null +++ b/Big_data_example/Flink/src/main/java/day07/Example3.java @@ -0,0 +1,64 @@ +package day07; + +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.connectors.redis.RedisSink; +import org.apache.flink.streaming.connectors.redis.common.config.FlinkJedisPoolConfig; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommand; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisCommandDescription; +import org.apache.flink.streaming.connectors.redis.common.mapper.RedisMapper; + +/** + * @BelongsProject: Flink + * @BelongsPackage: day07 + * @Author: dingjiawen + * @CreateTime: 2022-09-06 18:42 + * @Description: TODO flink连接redis写入redis + * @Version: 1.0 + */ +public class Example3 { + + public static void main(String[] args) throws Exception { + + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + env.setParallelism(1); + + DataStreamSource> stream = env.fromElements( + Tuple2.of("key", 1), + Tuple2.of("key", 2) + ); + + FlinkJedisPoolConfig conf = new FlinkJedisPoolConfig.Builder().setHost("localhost").build(); + + stream.addSink(new RedisSink>(conf,new MyRedisMapper())); + + + env.execute(); + + + } + + + public static class MyRedisMapper implements RedisMapper> { + + @Override + public RedisCommandDescription getCommandDescription() { + //一个参数是操作符,第二个值是表名 + return new RedisCommandDescription(RedisCommand.HSET,"tuple"); + } + + @Override + public String getKeyFromData(Tuple2 in) { + return in.f0; + } + + @Override + public String getValueFromData(Tuple2 in) { + return in.f1.toString(); + } + } + + + +} diff --git a/Big_data_example/Flink/src/main/java/day07/Example4.java b/Big_data_example/Flink/src/main/java/day07/Example4.java new file mode 100644 index 0000000..2830077 --- /dev/null +++ b/Big_data_example/Flink/src/main/java/day07/Example4.java @@ -0,0 +1,93 @@ +package day07; + +import org.apache.flink.api.common.functions.RuntimeContext; +import org.apache.flink.api.java.tuple.Tuple2; +import org.apache.flink.configuration.Configuration; +import org.apache.flink.streaming.api.datastream.DataStreamSource; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.streaming.api.functions.sink.RichSinkFunction; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; + +/** + * @BelongsProject: Flink + * @BelongsPackage: day07 + * @Author: dingjiawen + * @CreateTime: 2022-09-06 19:04 + * @Description: TODO 实现一个mysql的幂等写入 + * @Version: 1.0 + */ +//create table kv(k varchar(10),v int) +public class Example4 { + + + public static void main(String[] args) throws Exception { + + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + + env.setParallelism(1); + + DataStreamSource> stream = env.fromElements( + Tuple2.of("key", 1), + Tuple2.of("key", 2) + ); + + stream.addSink(new RichSinkFunction>() { + + private Connection conn; + private PreparedStatement insertStmt; + private PreparedStatement updateStmt; + + //生命周期开始创建mysql的连接 + @Override + public void open(Configuration parameters) throws Exception { + super.open(parameters); + + conn = DriverManager.getConnection( + "jdbc:mysql://localhost:3306/temp", + "root2", + "root2" + ); + insertStmt = conn.prepareStatement("INSERT INTO kv (k, v) value(?,?)" ); + updateStmt = conn.prepareStatement("UPDATE kv SET v = ? WHERE k=?"); + } + + //每来一次数据就会执行一次 + @Override + public void invoke(Tuple2 value, Context context) throws Exception { + super.invoke(value, context); + + //保证幂等性的操作:存在key就修改,不存在才插入 + updateStmt.setInt(1, value.f1); + updateStmt.setString(2, value.f0); + updateStmt.execute(); + if (updateStmt.getUpdateCount() == 0) { + insertStmt.setString(1, value.f0); + insertStmt.setInt(2, value.f1); + insertStmt.execute(); + } + } + + //生命周期结束,关闭mysql的连接 + @Override + public void close() throws Exception { + super.close(); + + insertStmt.close(); + updateStmt.close(); + conn.close(); + } + }); + + + + env.execute(); + + + } + + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/listnode/DetectCycle.java b/Leecode/src/main/java/com/markilue/leecode/listnode/DetectCycle.java new file mode 100644 index 0000000..640cba7 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/DetectCycle.java @@ -0,0 +1,90 @@ +package com.markilue.leecode.listnode; + +import org.junit.Test; + +import java.util.HashSet; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.listnode + * @Author: dingjiawen + * @CreateTime: 2022-09-06 11:49 + * @Description: + * TODO 力扣142环形链表II: + * 给定一个链表的头节点 head,返回链表开始入环的第一个节点。如果链表无环,则返回null。 + * 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 + * 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 + * 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。 + * 不允许修改 链表。 + + * @Version: 1.0 + */ +public class DetectCycle { + + + @Test + public void test(){ + + } + + /** + * 代码随想录思路:快慢指针判断相遇 + * 内存击败60%,速度击败100% + * 时间复杂度O(N),空间复杂度O(1) + * @param head + * @return + */ + public ListNode detectCycle(ListNode head) { + + if(head==null||head.next==null){ + return null; + } + + ListNode fast=head; + ListNode slow=head; + + while (fast!=null&&fast.next!=null){ + + fast=fast.next.next; + slow=slow.next; + + //如果快指针和慢指针相等,那么有环,且两者正好相遇了 + if(fast==slow){ + //定义一个从头结点出发的点 + ListNode x=head; + //定义一个从相遇节点出发的点 + ListNode z=fast; + while (x!=z){ + x=x.next; + z=z.next; + } + return x; //返回环的入口 + } + } + return null; + } + + /** + * 哈希表法:维护一个哈希表,当哈希表中出现重复元素时,则是环的入口 + * 时间复杂度O(N),空间复杂度O(N) + * @param head + * @return + */ + public ListNode detectCycle1(ListNode head) { + + if (head == null || head.next == null) { + return null; + } + HashSet nodeHashSet = new HashSet(); + ListNode temp=head; + while (temp!=null){ + if(nodeHashSet.contains(temp)){ + return temp; + }else { + nodeHashSet.add(temp); + } + temp=temp.next; + } + return null; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/listnode/ReverseList.java b/Leecode/src/main/java/com/markilue/leecode/listnode/ReverseList.java new file mode 100644 index 0000000..bb5ace0 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/ReverseList.java @@ -0,0 +1,104 @@ +package com.markilue.leecode.listnode; + +import org.junit.Test; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.listnode + * @Author: dingjiawen + * @CreateTime: 2022-09-06 09:21 + * @Description: TODO leecode第206题,翻转链表:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 + * @Version: 1.0 + */ +public class ReverseList { + + + @Test + public void test() { + ListNode listNode = new ListNode(1); + ListNode listNode2 = new ListNode(2); + ListNode listNode3 = new ListNode(3); + ListNode listNode4 = new ListNode(4); + ListNode listNode5 = new ListNode(5); +// ListNode listNode6 = new ListNode(5); +// ListNode listNode7 = new ListNode(6); + listNode.next = listNode2; + listNode2.next = listNode3; + listNode3.next = listNode4; + listNode4.next = listNode5; +// listNode5.next = listNode6; +// listNode6.next = listNode7; + ListNode result = reverseList1(listNode); + print(result); + } + + public void print(ListNode listNode) { + if (listNode == null) { + System.out.println("链表为空"); + return; + } + while (listNode != null) { + System.out.printf(listNode.val + "->"); + listNode = listNode.next; + } + } + + + /** + * 自己的实现,和代码随想录中的双指针法类似 + * 内存超过85.07%,速度超过100% + * @param head + * @return + */ + public ListNode reverseList(ListNode head) { + + if (head == null || head.next == null) { + return head; + } + + ListNode fakeHead = new ListNode(0); + ListNode temp = head; + ListNode temp1 ; + + while (temp != null) { + temp1=temp.next; + temp.next=fakeHead.next; + fakeHead.next=temp; + temp=temp1; + } + + + return fakeHead.next; + + } + + + + /** + * 递归法: + * 内存超过78%,速度超过100% + */ + public ListNode reverseList1(ListNode head) { + +// ListNode fakeHead = new ListNode(0); + + return reverseList2(null,head); + + } + + public ListNode reverseList2(ListNode fakeHead,ListNode head) { + + if (head==null){ + return fakeHead; + } + ListNode temp=head.next; + //这个head就正是翻转之后的存放的,作为下一次的fakeHead + head.next=fakeHead; + + return reverseList2(head,temp); + } + + + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/listnode/removeNthFromEnd.java b/Leecode/src/main/java/com/markilue/leecode/listnode/removeNthFromEnd.java index 1bb03ea..72f4376 100644 --- a/Leecode/src/main/java/com/markilue/leecode/listnode/removeNthFromEnd.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/removeNthFromEnd.java @@ -8,22 +8,34 @@ public class removeNthFromEnd { public static void main(String[] args) { ListNode l2 = new ListNode(1); -// l2.next = new ListNode(2); -// l2.next.next = new ListNode(3); -// l2.next.next.next =new ListNode(4); -// l2.next.next.next.next =new ListNode(5); + l2.next = new ListNode(2); + l2.next.next = new ListNode(3); + l2.next.next.next =new ListNode(4); + l2.next.next.next.next =new ListNode(5); // l2.next.next.next.next.next = new ListNode(9); // l2.next.next.next.next.next.next =new ListNode(9); // l2.next.next.next.next.next.next.next = new ListNode(9); // l2.next.next.next.next.next.next.next.next =new ListNode(9); // l2.next.next.next.next.next.next.next.next.next =new ListNode(9); - removeNthFromEnd3(l2, 1); + ListNode listNode = removeNthFromEnd(l2, 2); + print(listNode); - getLength(l2); +// getLength(l2); } + public static void print(ListNode listNode) { + if (listNode == null) { + System.out.println("链表为空"); + return; + } + while (listNode != null) { + System.out.printf(listNode.val + "->"); + listNode = listNode.next; + } + } + /** * 获取长度length之后,遍历到第length-n的位置删除 * @@ -122,6 +134,40 @@ public class removeNthFromEnd { } + /** + * 快慢指针再次尝试 + * @param head + * @param n + * @return + */ + public static ListNode removeNthFromEnd(ListNode head, int n) { + + if(head==null){ + return head; + } + + ListNode fakeHead=new ListNode(0); + fakeHead.next=head; + ListNode fast=fakeHead; + ListNode slow=fakeHead; + + //慢指针一直移动,快指针只在满指针移了n次以后再移动,则慢指针到达末尾时,快指针就到了倒数第N的前一个位置,直接删除即可 + while (slow.next!=null){ + slow=slow.next; + n--; + if(n<0){ + fast=fast.next; + } + } + fast.next=fast.next.next; + + + + return fakeHead.next; + + } + + From 5e970a95f00162d97149b0a55f869e039a4aca85 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Wed, 7 Sep 2022 13:41:08 +0800 Subject: [PATCH 09/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Leecode/pom.xml | 12 ++ .../leecode/hashtable/Intersection.java | 92 +++++++++++ .../markilue/leecode/hashtable/IsAnagram.java | 144 ++++++++++++++++++ .../markilue/leecode/hashtable/TwoSum.java | 123 +++++++++++++++ 4 files changed, 371 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/hashtable/Intersection.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hashtable/IsAnagram.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hashtable/TwoSum.java diff --git a/Leecode/pom.xml b/Leecode/pom.xml index 5813608..e45ab83 100644 --- a/Leecode/pom.xml +++ b/Leecode/pom.xml @@ -7,6 +7,18 @@ org.example Leecode 1.0-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + diff --git a/Leecode/src/main/java/com/markilue/leecode/hashtable/Intersection.java b/Leecode/src/main/java/com/markilue/leecode/hashtable/Intersection.java new file mode 100644 index 0000000..f924cd6 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hashtable/Intersection.java @@ -0,0 +1,92 @@ +package com.markilue.leecode.hashtable; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.hashtable + * @Author: dingjiawen + * @CreateTime: 2022-09-07 11:47 + * @Description: + * TODO 力扣349题:求两个数组的交集 + * 给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 + * @Version: 1.0 + */ +public class Intersection { + + @Test + public void test(){ + + int[] nums1 = {1, 2, 2, 1}; + int[] nums2 = {2, 2}; + System.out.println(Arrays.toString(intersection(nums1, nums2))); + + } + + /** + * 维护一个HashSet存储一个nums数组的数据,遍历另一个数组,如果有就保留 + * 速度击败99.13%,内存击败83.58% + * @param nums1 + * @param nums2 + * @return + */ + public int[] intersection(int[] nums1, int[] nums2) { + + + HashSet integers = new HashSet<>(); + + for (int i : nums1) { + integers.add(i); + } + + int[] result=new int[integers.size()]; + int count=0; + for (int i : nums2) { + if(integers.contains(i)){ + integers.remove(i); + result[count++]=i; + } + } + + int[] result1=new int[count]; + + for (int i = 0; i < result1.length; i++) { + result1[i]=result[i]; + } + + return result1; + + } + + /** + * 代码随想录方法.使用两个HashSet + * 速度击败26%,内存击败68.81% + * @param nums1 + * @param nums2 + * @return + */ + public int[] intersection1(int[] nums1, int[] nums2) { + if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) { + return new int[0]; + } + Set set1 = new HashSet(); + Set resSet = new HashSet(); + //遍历数组1 + for (int i : nums1) { + set1.add(i); + } + //遍历数组2的过程中判断哈希表中是否存在该元素 + for (int i : nums2) { + if (set1.contains(i)) { + resSet.add(i); + } + } + //将结果几何转为数组 + return resSet.stream().mapToInt(x -> x).toArray(); + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hashtable/IsAnagram.java b/Leecode/src/main/java/com/markilue/leecode/hashtable/IsAnagram.java new file mode 100644 index 0000000..78aaff6 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hashtable/IsAnagram.java @@ -0,0 +1,144 @@ +package com.markilue.leecode.hashtable; + +import org.junit.Test; + +import java.util.HashMap; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.hashtable + * @Author: dingjiawen + * @CreateTime: 2022-09-07 09:31 + * @Description: TODO leetcode第242题 有效的字母异位词: + * 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 + * 注意:若s 和 t中每个字符出现的次数都相同,则称s 和 t互为字母异位词。 + * @Version: 1.0 + */ +public class IsAnagram { + + + @Test + public void test() { + String s = "anagram"; + String t = "nagaram"; + System.out.println(isAnagram(s, t)); + } + + @Test + public void test1() { + String s = "hhbywxfzydbppjxnbhezsxepfexkzofxyqdvcgdvgnjbvihgufvgtuxtpioxgjuwawkbaerbsirrktcjcesepcocaglbassivfbjhikynfsvlbtkawstrclbkpuldshfgfvwjawownulsggsxhhqglbhjlgltfrqyjntgldlgorgatnjrsywlyngxrcwfojkmydmjbzuquqnzbpwlcbdzgdicctpkgtbdjgywkyrkityvohjbuvmzdfyicyplmrpygdhaeqbuxnehfybsysnnmzbhprsyjmtpcrzeqqbirofzjtlsyofdyeffkvpuhzaflwjfhnsuyryetjuajjnjwvlvrhvpenaarnzoafztixjrisfzdlepcwhxudjpsiirtofymnovacjmpdjtethjqfwduekczlqhsfjgqesyoxcfooagrdhyvsmssbhsclnlblhobvhwtpyftolneozlhbtjagpgqnnapktyevdvjfwdnbwsbelweoflhyhifprieuvfcdkavqxkygjlaegqfmzndgxbsccjgpclxmlpstrqjtqyvlqcopnahqvnpvkjimfdlosvletmamqjvotqwhadutmfvlgldniixvdkmymfadckuaglgbuttymoqmzkaeqxugsrnfyxzcamwxujgzupefretsvbdweuwwcizjvhcowtmwgkdafcpzctpsjwdocgofivyshwdinbdhbxdfhjsrrsfchxkeqndgzauyprwfnrbmunanqnhmjhrufoinakwaciaoerioqffmipfqujfxwofqdyjbhagkyvmnxcwomgnmwlaodxgkgthnuctoozxrebjiynjwohtgukyneyofabpfdrxklopmxxiwjuxqpaazknscagfiaetmmwnwpzceglupqvlctywtpluoqbzdultcsudubqclbwlxyfboimfwriugfulbntvdwnxgiycxvennakpodorvpiknkridcumsovvfzikiydqewgjhacrkxddqpncirzlsynbjwutomcwphgggcsnfqxwxguokjvihoewffngivnkapaqjrsshqfbpfqhzihzndzeyznzyndmhfmypgwsqyernninzijwrirmbebsupvukfjddsjbebfedtdcufnubxqocqeqaincaadorteimkecpkdrjpprqtrllypfiktvcfadfotgjghhtkctgidwreyjulbtmtpwicbqalejtxsgjqepzeduvwvjbbxaapwvmjuweurhdbacxaygzdyitwcwlguknhqxdrfpfhstgnwmwagcblxkqjjwxfhmpunstfhkiffqchcohgcuktfplffqtwlwcsddkaeijajkdpmexteafezquyfonocuwuxrvigpcqbzmxtrvctovnvrobyjmjnqdhxqjxtltichttiuemvxixfeyqzuzxkwmyclbwutbvrgtefcdizjnkmlsvrujtiqhrwpnzkdtkwogypvpittpfhjtlrjtilubngkkjochucmdudfcpudjhiwaflmdfgsjqlwqxlgmdwouofjnytwxumjaailltmzrrfvqcawkzytomjaaafknfnaaylmqkvyeljnznomervgdhnqfhtpalziumhilupdsjpvzwjsgqtnovjneotcsfdtqqtfwjlhsbhumoyjnpuniqeszknvzitifqmiezbzvtzoswezulpfylopuecqcefueesjfhvyddsvozowqtyphlnuridygcmjhjtfoenwbgtramegbnabtooohogyoqfmskrpayzbrsidfbqextanotbkzopgdidswzxveqtojspsbwdqsrrspsyddgwntndfqfqeuvmrnyjvdrpszghetjnbpitorzonhihbzncpwvnwndriupumwihnpxskwsvjqzuetprscqnihpfebqobdezwohlubpyoulnkoicmtjyfsmvjltsxtvydxkajhvkcmhrkeuudrgxjezoeessffmheelwvotkjecsnwybtqutmkubtzbwshbacffkodyhgvdrqxwvtfwzsytriajkjjxcrvypyvmevvqpdknftdieqhsvgedaqlstybriqbeiczokoavsgizdjslkjzfqrtbxwydojvutxensaxrtapxatjrgdvecxocrisfznweidfvxddbmsmcmaostsrlvwvxokcecazxemwqksjnqhkegwcgqltrczpzyjopqmccgjpnfcxatmrsxvozdtcttlxptjhcwmjgcyltnrpicgblfjkljdjqvioxaliduasggcxviifzycctasdhfyetjljfgwjhjssryjaetfbrimuudxwivzpmpbylkikvgebelhouaconsqiyrjqtepusujnlpkkztlbrnnmllrebjamtsszsjyaljvqwklglhpoimqrspabinkpwopignvejbulvugpydnljwccorrvcbncioxtmvjrmvujzrqhfaphfhckmrapmopqaktegfmdnfrvmqzhngbwsijdocmhrgaxspclqxzptviiyhtrniflftpkalplcfoixqcckmvzeqozvbyobxgxehhrvezlkxdvloeqpmgjyqnoroztieaspauxwprtbmlawbxndadnqmknwbmnebiqkpjepdjudweevxtgclllpofytkpvvmlpllxbvkhcftqpzhrlaujzzforiafedqfrsxinxfnbkxjdntfpwquvluuxkukdovviqbtbiunyybkblbifsarcbojrjuityotqpwwoclttqcumithvhgajhlhmcoerwrmyjuunnbvqrghwniqatjnqrjgsnmdlcrwbnfrctsvuambecjkzzkuchvsuwusijrtctrcebafwlkpcoossaagiweaxauwyxhgchfdeqrzbnldmrzwbatqxelzoueeulmgfdxeqxqiaiwajqyihkvivbzhkjfhgutzvxrgmrqsxlctmrvnvybmlbufbmujpezuwjwfpwagltzicimdxyjscoglhbazkcamnchdhuwrqzbfnceikmolfjagmzhlbzyvdffmkeyfcjfovhogdkdszhomhqepyeadooiayofdtnlxwtkprlyozuimeinyiezyirpjfmhubdhmaoraogqytiihxgidzkfxdwqyadvrayajqilwddlyxmhgkwvcwsbqvxbluheovlmugyweciydchhoxlhvodmuvnaodxkelyuprppqvfupddzingyrxtpisrsuuyegruplcogidrrqghimxendmveudzemtwnmdrfxjiqiakglodvzxcdxzbtbobnvvoxufqnmdflgwghbclalddgmevnwzhohbhfhocuabtgvixvfbivligtiyznqmhsdvbfxmylyunerawhdhjlrbgvzljjgwbjhpjhgbmnvwnvjwtdtdrftstvrjjtnorryghqgsfybhncacxoqqhupvtjdnbdranemfywjhtgoxjnoqwsttvsoxymelwnomlmphmrxtnnbsbyelescyspuijmcxsevgorelseeyddymdpjbpehjdwsqrtihzhgwcgstlkallcdssiyzpvephkhsaamntlajcklwtekeupmwlsiojaplbrsnsvzqfuujkllzsiljzqmlvgibxssjjqiocgmvslmqgrsxtazfnbzwdkzninyuvmilmjoexygejggpkbrjeyfnfuctourngguxexoebgdrpbvjuxaqmibmoifsnbnhzlyssonuoqnhhxbkziiudkgtgucbvybmuflvdbdcfrggotqyfishaaqtgwfbdcntpxbtsmokrxnvrzaxfejuwqpgqfirokngeeyejngavztbdkdvtprmywohleaqqfqjnyyycppelbvwlkozdtwuubrjwkkmpavgemwmocvchoquogsjkebulbrgexqjnaiddbdvjlgvfntnkdgkmceomdkvpxtztfbwqqlwutlmvjjzkbulvqjxubuzegteusicmxqpzxlebvkndncxakvnnugqcbdukylzurgtjbcpcpsjbazlignnxemzzpkkhmbdiakeikioibotgyxzovgchtftfhcbznknjilmkudtzifiemrcwbyicspvnhxkzcjaxxcmddlesvixymggysbfnkqcgmsavjqynzehkeckesyddjgqexzmxepknwftptjdtauzohogaptcjdayexbsjxnsgacgztulhucmjqvrqnhuxxcyrawtznhuugkwylkrrvzihwuwhinuffmyyerikwiybcqaeaubmprvzosefwxruzrdqvhkdpifujykelbwumnfpuqksjszmzbuurnswgipwnfzlxplmodczmvxsvzyvdpllrnssiumfbivummsugxvxnfwdvgakstdnkxkjohcinmqbnyqtoahsakqluxrfxlvmhsgdpipgokharbgkrbowropwqaaqkyvhxatqrajmoixrycavnoisarbdqrlggbhliypuiyubulfazulsspfpzzpczxmxtrkjszttlchdpcuoiqnqibnkrereaeexhnqbqwadclbuejxhnmoarhtfrewbwgzzdtwjrkcwpplkezxufpvvdiirpsiulomzsefjnpkodqdyffwlzqvzfabnzwgyjfwyzeknsfyjagyirtlhpplhfcsvttdneoongivvdvxtjedjaakjobmkjnbedinvocafrvkqdrqdoufrcqvjroztpkympqbkuwelwarfjyndkyxkspksyosrqpgafamshptbxzbdfekqhgagkbvkgeinepzkcdnmfxnyqyjhjxntasxgoghmhkkpxvcisjkvgwilgubjxccmffklniynomznltcmfofpehsbfswyginakcvdzhkbrrccnerkzkfxzuvcizvanuxkiotvttqqnngopaewpaqvdhefzrrdymeodzyfufbosecnqkuvhxgprgnfbiyqdkqwwujumesjvxvrfvkknhhfhvegwmwrachpbzwrjsffjbhkkktpnzgtdgzgfbmlmymznnfgnhcftfpdagnbpzftewnzefuqkfyiwlmnyvtahanbigapagjqmrixuyhxhlyrwjoqzdvbhxxfyfbwfsfacwqujjfunypywngdbynsqxplfxtejbzeytcgsabjyhvaxdyxbcyskdfxhjuwmisnldbjliejeonzsurrpqqivhcujjwsfubukdglszfzwkjqxdybsynrkonufpvhlbirqubbgsgbegmpybtmfmjsklfqdzvjbqndqmqwbpczcbksrxyjcrlrlmxkipsffugjmfvmhbhckkmvpzqpgspqkzpnnhcplcmimnmnckuvhuwlkqxhgwqesqjhonuaewywzjgowhuzfujyyflnesowydymqcizllqinuzcxhpycbyskvufloktvnvisxjjimjksxmogvpqdxuzplvjkbplevzcovmlzpltuajpwcdqfwohkhumezhaugjkdhxhwvfwgoxqniwglnwqyhzcjrzholyauavdjqjrwstkwncmmxsngzmykrecmbfabixkwxtqtbjmbnplnalipmefvintguxpsgwvvmvwbpkytxmqejtqmnihfsbqrhzcjshotetczitvdifzlghcxjdswlbcnfdxfxcpmgmmcetagnhrutprhjypoiyolykxgprurkqyplxhgduaffbzhfekawtddjqvuxlalyvvjxzxxgeqrkicyzbdszlbplqujcjvqlbtxlaweqyyidjfytgcgqusgtorexawwebddumpqlhhizrbojmpwaixrsbbocgbjlwjfolifykxnousrhtirctyptvqtlwfuofyezstiwzdaygaucrbbzcluqykwbuduedvvxzgcwehykvggnrasqhlezaihzosgpaygrdecpdqofauicawicbgpjzeqkvytvcbhdyvqmypjkarkcrbciruzifapzkaisuvtlglvfnnwjocduysozqhkuvkppytoedykmbmsxzoqbkqepmivxxadpacmoodqvbmrkicxnllrhrtecsbviqycodvgvkevzudbktybzyffdpqafilhgtccaojtanoknvccpjcgtryxcofprbegxebtlfpgbahpyqbdlkeiqdayxaadxgcicdugnhcbmqebdtyclbmbjalmzbywbtovlclxuwqvrlmyptdtxnkijwxnlnnpsfstdhbqgjjwzrfxykdkunnaqlvyrgbamuvzarrdfdgsrclwwxvuvafnbhwzhlqkykuhhnuetjykmsxzpfnydvtpphalqmaxntnrxvyaswebdimlcckjtnhommgcsocodwaavazrjaiywuqybqwarcatjcypchbnkuwerbobgiirdooqsmqqsergkqmkfxsvufyyhziwmjkamflrsngrrsntfojjjbwyjbpvcrbihdvwhhnccdungtfvnytcnmvasnumxmyrkgyycptvhdwqhtiaehdfeencmxihtbhrzlxstdmwesfcysasacewvvyzkuoxxmyvsyztcvtyqqifdagubpacyiwgkkcinngdibpdywunhvierijzaqyitxsrsadoendrmykzzztfpxgzkcrdqvvskjsqywmumztmibazouprbubsdprsyalrmyizluuxnolvdstornbtvpsgvidptlscjrzylxjjiyefxcdzrmnrsoplqdyfedtvahndirebpqkwqnvzurxmzlfwuzxcdausblgucdxsxljsjwgnrdrbxnmltitjsabfqdbhayodbukydqmrgocprociejzvohnfrzzpjijappmsqoctbfjeiladtutyjxgzukqexeuwgbiqywebezrbzobfdasiwtfkmrqnlkgntrbaeidznyoyiztivqcufqpqfxqfhuikukmsmynglclshyyaloiswxqoyyqinlmkpgutivzhwenuvcepbwkvorqseykydpzrwgvaxhcazghvvsswurwnqmhbzkpumcihnguffddbgvgfeenukhsciynysyaejnvfytxavjozmtmpdgexhylacpgfqdnmmtqwqptjrrwreexcmgglxvkfzklmrfpvoxvhejjvihraszgdtbqcbabuvsbksxkylbisjrqieicqietplhnomeveqvozpniifutgwxnydxtwnrnnzwtunnywsszqgoyrweqsqjtopotozbdtyglfvjfdbrovfbatajrjgttzqqnjxivvywmjaeqxpmnaxnsfcfnbsmxdytbghnlnjfkcazqadakgazvewpqccdaabhpzhervkxathjizeuuhzivpdwulmmfdwbkkgxorddocvvhqygxjzqvsrkjkrwgyahdngcihvkmwhovauybwvapomiwscvjrnnaxpfyrshuupwrfbmugoxyzedxujteludcshfagnikwbztuzmdohxmmcdaduiesmnjvnztrsnbackpvkdfusmixjbdnuenppdpyottqmsfnxtqllnpxdfxjabntmrpwypcgvjtexxhfmbzfoiizjtdtfsodmqaprfudlemamovfdzqbkyhpeopyxbdjloqxmzvqybtfnffaoxdulyxlpehkyzgdhexgdjzxmbczwqsijkecthakunpogszzcutmcintimzmmfaozgdoyjcnwdcsklpawhggsarraefboxocnwlpxdruoyzdtvlagktupkoyswmnczymwhwinwooznlhoajtjuefvxdxbmzfbikuusqrutcfogvagidvuxxtgyshtovetdhzqijctgzenkshqvlibhkhwwnofbtyshrrhfcmsbwqyzagmlpoxubcfplzxdfheziweoghykcmubwgkcochqlkmidmfmzvbdkxoknjrjsyzfiemgtzplatkmhfuvenevobeyneyobkjuidbuvoyaqzrjacecuadmslooxbmzfmuawexswqupvawrqzvihhkfmsotolkdgmarpkkxnfndfkteqewywjzagukjiqhdjdnjxgfnmtrmshswaxizeuexrebctoehacerwfjjgodvicmgugnlngoofgotbztfjcsrwblvrtejthfmmzjjcrvezmczizazzpbdwytxmftfgzdqnslpezrnodslgplqkitigmhhhonadcxhdnexymvlprrshfrecizjnezdlwkupvkplnpvhvcsdilbscxgyxtuwqglkwwxljntjpzsjkrzxmoyswfahhgelyqjhvpmtgpmosmbmsqsfbkeedtdnakyvcumuxqovcnllusoxjufdfgdsjnwxsagtdkjljnfdchnmnlsnqaugqmnzzpzohlatgwhrxsnvvxxvahxwbadqrhraqmstcewlrsuftmrtcxusjkiyemosbebjfxqmvxnyhfdximdbaogpckgvbctkmcusigwbpulpocohlqxtpuqsemnkwcydjnvlrpwjyyligswnphrkbaytllzlmbnultpfcrtyxrvzlucshoxrlzujuwgqwssbgfgpoauqmzzfeppxxqcffangjjrkylvfirlvlhmdypetylrrxmewbuvcylzloskdrhwqaogfephqdyhymqkllwiakogsjvivcwtxcarfzyeuquvlnjwrkptchqjvlbzrilciwuajpmitxiljqeohbkunqyqksadaqkjikuxqznaaihtqeomxkasspyiquazvdqufjysgbqujoyhpnjcgbekgmkztovlkpmqlcdnpmmxyyxmaysxdlzxnpvwoyxnqtstgajdlizxyoiiildnjyafdavyynlozbapbvizlhlpppmiaygngtsevhivkgvmoekoevuswjiefzuwqnpfwwuwcooxudldfjifavbkkidnuqtidunubbabtfsltdwgqfxgoqqylmfyjxvxedoxqpmknbxaqkakvhmtgygniotdikllibsaixidziltnvuyyftypbhaguvizawxijuwiwukkmsaefthkvsdjvvgrbtpwmhwqdlcifjwmmexnajitvzhbhvnhybbmbgexdfdapldjkuwyigtqsgbylookxtwrqbcyzluydbqltcogsyzflztstcxsjipdxsmhoppoexahpaguwdmdtaogwfgkzvollmucphpzkanxazegyjdfkbxwshttzexvdqrymwzjlqphswivippgoasarylakkixysabrvwtaxswkagrlltqknpbhlglbrtycfgelazcoeaglathkfbshvbcxpephcvzfnhpslqhsuldrpnltqcncxdkiawdikeaoweadywevhzfuzxgpwyeqqyfzdmzpfbdenjtcxhbydpwzntbbvpxelxitqjlnvbevgkhdmrumildyuxwmdpyiwfnocgcwlqtnoogrbwpmycyozmccslikmskxdfolnpjrkvkfgbawawnxhtatwhfbenpxlckcbzjknlsfmgypvbrrpjzbwgrcruakqlgtkjjcrhbkdpcqhmpcjdlyoqigfqeimtlwfdsxojscfbdbqevzegkbymedbkfodgomldmhplzaaphenfpgimfsdkzooqvdptddfrneapnsqychajjnctzqsjwhmwanrboxnizydzklprckkgnrxydmjbzjswlyvvbsyzfsamrhzyfzaafdvmvglfhnhqxjfnomrvhikavprpvjdmsfxzbacydtjqcwfrrwfinucsyvhmwrbabfgqcvlbvixbpgumiukortiklgcysdnspslwicnpkcildcarfbxajpojcdwotuoivfdcebajgtvxqsmvvgxlkojfxkovxllvdcfwsssmgcrwuxopsnvrvfyneamxjtqegddlxdgmgrvhaijmsuqufnpuidlxlqmkajvdbdgamtutvkvjcijpmsvoqkhtxamzkzvfnuyjtzzkcfebpxsxktphsupzlxvrhuldzefpkjjahglzquroaavwwsmyzvocfumnxuemysqtpxxnjqqdarwzupxlldgqxbhrocmaqlfyeghedhrugxewggvpizuiemgnyvnmdymlvgtflbfgcnujpkuejymaheiginsvfxsveqhjhfndxspramoskwschxugkvlvdecunquniiivpqizwnyeipwgfomzctopbcwyhtvwjiretdqvgycxwmvzrftsrbdfbqbyhcqezbqarbwdcijrazroqojwrifpwjrtzyhkuhigouheybmrasdtodhddappfeylgraytlxetjophbqgknbcufttuiramawebesrzsbtfaucyqifacyemkfimdhwpzbwdakwjblsantzlcudyabmrklrrnrahosdxnwgwsygewylfltlxejjgzgeptgaknqxextlfcqvzhpxjvrobzkkqczwitykdmqardgcribfzxpzylfzkitocjhgvtdjxavkwtkuxffslvvfrkyllnnxitnboxkutezrepxkxxamrhjvmvaffctuwvzajhhjegigbbiwsscyqikgkwysnceshzjwpeuyqfrnfvfeetagpebaiybxgutlyrdsccrsguxzqvenakmcdhayzmuulkuiuryppecdxqnisszatfowerauhxcldoszqtduzkpwpbwmaxfbqppdiqtoslkouwvxvbaixhxjpttxwxzkqkjzqhcnvnbdhkcxlxnvjqaxlclurimmnolvixxodfjzbtyeapqqfypqbcbrvwdquttbancdgmuhuqbnyxfckgffzmkwuvfmszjnvnfrxogksluaxffcghqorbgxedbjvojvseoxhbugjdybhmrsiwkdgprfgopgccaqdcpfwiftcyjzljocinfjpkqngmugfjqgtcoagawhfkdkyrltbrwdjfazlvvxbecybyeaikfolankjusfjwsziwumrofycukfdmpaocphfuknwsehhxjhmtafugpwckkazjsytjbeihobkxrcqbznsdboiegdkagrcmrfqvyhhizzpnbtyvrzvosnqguhhghbhldtstvzxrbvufwsvijukhyafqfgmfftyjwmrkxeurjujlamcstwlugskqdnppaovkqzginpluhwxybopsrusapwbwhrgygpsfnghdkouwoiafokmjcnfrqaremqcrfsfzqxwalqfmpshmftihexccdovruodydkgmrjltvagsqswkwvorywcgelkvaikkpjbobyxaqyljtybpcdrnswdheyygismrsgjsirpgdczkegnwdlzibocehsbncivftqfxaroxizmzhyijqdvvyyypmoaiztjiwmhleibomoymhxmobyelnkskyabmqsjulekzwydfekqrpayicbbgzczacnpedksthppyetucsmweobsdcjhgdhgrymherrtijjtgqgsqjxidgxdcctgvzsognvzcntochxunfmeiscdstnbiwqlnsmfkosgnjfpxfffnjbmkffkiniisviynbhwenalbilganfnjycegfzzpoywdxmeyujoaedysdabgnhllfojxbwnxvqtlekxisukjwmelujtcznvonmmhcltsgdedgrmewpkxhfpkqnvjhjajagocvfquycohcufzcitivvqlkdjgvvoldpgirsllgowalrwtxqlhjavrpupdjfxztexjmvloojkpoekjunuyjicceixltgwwgqjmntrggfahtudejqpkvbfezycyacuvtrcfahnscilpxcnakdxmuogzxhvdhepkgwcfqnynjnpwwwwpjprcckzbpekxxwberwygobceyvalblpppuydnoqhloeoubptqtyqobwkimjevmmhhdhutwiarzmypuzunoesxxyuedebbaycbawrsoknugmlpwjjnajuoillolebrxsyhvyoqzxcufyikvfgncukmwcetgnkhsotriumgbmgmphcuqeqkfnrjipguhdrbahlyqwhtnuwnqcchtdgsgxeqevdycgwtiqofsnhvuhejkuipfabzvqjhdbbtuwvzbouancgkemccyyvrmtuubouakeuxydehpabvlbnqudwpylubyxrqgynkirvljpnzwgnuiwhevffztewzsysegndtmmssktdgjahcifcruicxqxpymcdwgipjnobhzrsrcqjggcqlkuycxiuopykunrotgmukqkhpvcjggdddrlduosffrizhglncpjjqsfjebbkzwamwoofajpubrgzqouwhdkdtuxqbhqvqnusbyxxeezyuhpatdsreaiinfkukxryycpghwsrkgsvguilifvtvzghzzmhsvyrgfkhxsirhncjxzkuiuyyaimatfenvjjhsrklfcnyorodbojnunndaqbgxofljrlayczzbnxurqiebpdwvevjndqiaphvxbzlnwzsqvrqlekqzxkliikevjcemhcvpwcrjrcxrhpxvfhelcynmuihcjkybzvktcaetsqqsfkxvwjyvetvbnjslfljvqzkagrkighgqrwaxmmsltgjnrfhfjgowkpztqtwjmewfowztsyvwlcyghyhsgvecyjvzwselwbpezhmmzgizbrqqcohyrzxcltabkddkmamwuckiqbicummmmkhwhzzgytotvlnvlryzoojawgxploclzloznnokmfxfjrgvfpkqfafqixdoxflrrmdddmjxgfgoznikzknmrczeqfwavbpytamblsxmbcjbpscsuraqhttmamxhaxgetiylrbhtbymajkgxckluctfwbwsgomhrdjyyzpechijmbwwdzxpuzmyvcpezynjcpjcpliuoaghpfowjvekehpchzkdncqubbvepovfvhlhvqzfbvqymgrhznpncmmynhhlsljjocdxblxbdhmbehfoyuuylurcocnfoqhynvoolcqikrmwbiocbwvpjskohvrolghchvjlydihynakxbndqgqcqsncgknfifwbhisdvrfvidsagrizmsakkdhngsohwtoloknapxzmyjbuojxniiwtkbfytzxootiqrdqnibapahrisjgmhnfnaqbqkoxsinddtsnfqympwjyrmdngimvzxtzsfeezgifacjsuymbrscwezdnnkuyvudcufthkntniodcsbfdmkigtnihqbagwbjlqpbhqhqgtprtwhunoiaekmtnhshvkizsvideqpqonfjuyqcgmiorbhwijonphxhxbrtydbfvftcxlixqxloarcpnnigrfywmaislxkqbgidkcwsnmouxrrwxabvrixfxtgzzbsrqleigeniulqyhvfleqlbqbicisidfrldrfilxejbpohapcyknbvbhobyonpwgpxaiaipjimuxdjgijoitysjrocgezdpsdqpbhtrycdchjfdbaxbmyyamulwlxkepslibgrotpvvcvlegpgsfucxczenkzljinwdalgzapletxvuynqxehembqcgayynsawsgknzxzucuxsgudbqlixqwinryiexkigsyzsrptysrseqbqdwgvyelybiyzbghubzpwmcqokxyohnkbkrlrpwnwydryyemrguinfsnrjnfhmghgvtblxeyuywvuefhklizztwhbrwresmamttahxoeijhhucpjhntakzexhfyedadebjfovkmaenllmburwjdnygmrqnxuqmaphcvbooopcszsghqgjbtwzslcocyhnetjchuaztyjkkxlvftkuazrvpuotfgbutzkscrclhicdeokgiijxdxhyxeiyvekbzwqprmwbgcvtsnsksgxxxtjawklhyjxsuihjbxgivqpzexqefgvydfcdrnhpitogxsyvmkefghvrbwqhguooaioyhxohmodlxyfqchzdyiftgplglkewwntxhlrncdblscuwvhtcffmfahmhcixmcmcbzxlujdaxoxwnqbcktqkqxhexcykctqytkjafrmmrtkizmewalyqlckwqdsarnzbphlwtemvfgtjrlrwwlyrkmbvxxhivgcwhzvkgxygkqhcdjudxeoxkajewjmztwfqetwfcbbmovacqrhyzdzigbzimdkxbrzpbgfugszzppryeisavsnjwevxiyrshggmdsscxzkwnazleulliadqomcwikdlezwdscaqhmeevobccyizsjzjfscabkzijxqutjifoeohnypzfnmmveilajppgzeuzkrpzajiisypojdzpftkxblgwzifkfzybhbqtiquwxbochrkdzlmlnouddlhjhzhlyuasycnelvydaklpwrirdrlzqolbdtnlfvigujpdcczucrripgmmmyeniybukcyrwldyfklhrnqxukfpspylvnujwarnomegpsaaorpacusmlebzkjxizddvmeqwsfwzzsfsszemdefcijlfhkfosxfrffgnddemlvqhbzqnkahoqwwwttymqynwpkxjmdreyzqefvcanexiutrtrdhkhigohjcrxaliltrfdbjbddjuhzhdhulwttpnysnqdpfwewldxkctixuxovetcwpufyjixxvqkmbqwtndwyyglmxalkajmvfyqrjqkzbcnjulmbszgvpcuazcsrsatpcxsoxdddkoxjkkytfarxxxjmdzogzsvekvtrneucakghbcazbpnitkvdaijhbnojbfwqdvjcipuwzbesrupebsnsyuauljiuiggttkuipuxfaadxobwspbfqzyvwfbpsnuwkapfmcibcbocqcgfnjfvkgazzgnfkxkefcubbrhmjhcqvknhvanfrbmvwgilgxjlolekvumikavnpfpxwdqumimcrmcoptcenmzmjpdtahotzflyqmogodjqvtfasenahuvotprpbwbpyqeksmysieqvppzumtfhnxgmuqvdpowrpyukfqpnprdfrywykmujrtzexzldifyclixfcxnrkduylkxsdjhkbvpuqoocurmdhttxtoaifdqbavrvfkllbngbnfzvxpwwtlgfvjspniltwecclncwewmggbpfjvivycwpclscujdelwxsjvcdfohnkznwzaavdzzhncrayokxbdxubdhggawezypqssdkxxmaymqoxrzwpqdwijksbkeoszovpkaxodnnmhoalznibyvocfdlqtsriipclhyuvqupczcxliuzrlfooivxxfhbwexysukyuzruvpkrlgaxckkgtcxirgxyooanpsbkceuvxxgusedngbalamcdohtxevmrlhsdnhgsxjksojwqajhjiknbuzbujhvrqnchjkloxwrxcikefvrawjxcsavtmyglxtkmejdbrphqzwjctormbpmpwfbjiaskyrzybmzzmpwtuzfqasaprslqhahvgejftyyrnimtvseqtrawgdhcfezeqrchoqpvwvidqqoaslfqpggmqqyykujaeeaqapeimuyvyzmarlldkorwdmjgcorqiesgoaqddnnseogedeoqcxovchxorccnlefrlvflvdtigxsmhtfjvcodxswfyjqusrajymvagfuickutoodzcvqjohwyqhslupgzwpintsndbwtfdnyklyahhhaqzhtyzttghzmldfysyruimflquixotblajaoderdpceuccurzfxkeutmfpqffzxnivvwpfclujcebywqcspiagfrkozuindzcnxefuknzmeafmqpsylkgoewhdgelxthgeshejtollmmtsedponkpijgonfmkccivugssewfhvwyqzycixxcpecunhurybmmtdduqnxacbsbmtytbebdovfmocnjqqxdqfxzuyiqsdqetpufldzskwgvodghfemakjedsfmasutbcyxsuntvpodacoyvbpbqbedwannppxtyptztjwdcchsitgqluneylwyaszipekkhbkcnefnzwawgfudeawkayrlaqrdswwevlrbjrqigfgjrlbfayelmiwsmbvdwbvkwuesujoycogvvwpipivovwudibwjanajowonreajokwfvcwsnsectaryshcrnlcdngqupksdhpulnvdicmniteeimortiokofhpfatuemgtuhgvifvyujqzzbojyagamjbfdazzvdloaqofgkmtxkcgtlxpvjcwdvehmcmhfrxkvatcvxkdlrikxyohzaxfamwsfkcrhmeypftzpeplkrtolgkowludrbzarxwuqjtpboqltvvcnftwooztbjijfkwrvtljeklapluojkgycmlrdqgmejzrihmghtmhymzjyqxwwgcnuaaxgpsgnbojcvrcmhevywxkbujhxlacnhulhkwaronipzpwotaohlfauopxyqksuaijejninpkqegbirhxgamxpnhevztjnwboftlvzkjepxyogqfahfbyxdnisympjgfqdwgvxgzcujcwnzaowescttkjxjmeqocjmczarjpoggmclyygefxakmgjgutdosqolpmlgxdepawapgrbsjizwepagtxbimwewcyprbfcczmednblmkevipjequjtwjifnvnwubptljnibdrzxogtrzbdnufzpkbqjjyzdxclofbpmdambenpwgngrenhrngescksznfxscjbikgdtloaqvrjaemipoanblulfiwtzxmhjvtteohxwegzozpqptqchehiwjaiibnslshnadwcwmbcqvusrpbcdbgdizrzrdqpqyiwgmrbtqvfqnghfmzalhpztzzijldncwsdshydkpipktxqgcyxpmqmfttlloxqunahvyygsucisycpefqifflaxshlqkpjxiaagjymviwqxggnjglbiqbmhbcardnhmrwyyabgbsekmeygniooqpdcwpomzuhyibigdgftdrwkouqfsugbxbbqhewwjwgixwpqmkisaqeztyuzsftgjzctbzbrtlxfwxscktafqxaqrnkeudbncahmythkroeotizqrqlnzenbceejohddmspxrlstkdvqoulxiscbbswcqyskoihxytmkincnphrmxzjypriaoxntttpxjwuzvrxumxcqfuuicxbdwqbxwvcpcrznctyhtyhmhuztldztqbimgdizuwhcxyvjqrzbmchsldvrzeftlhfuzxxkmxmpeljvlfcnfgkcxnfqfzemjidlzdrzugrscfrsfhgvscnualiotbvcquophhvldipnpwnaxasjdgrlctrvulvaarhwvuqbnzlsneiqwwhuvzjxeqqydosvgmqfnoeyhgfbwvqhgyodadzypvxcvvugnbcpokssausdntvuamaocbehzxykblqaefmzrsplwaijpanlfydpwwowpnvminkhxqfdxpfjuhlwmfloukjffcixmiojiisgwpowzctkmquemmamrjtezrgbgtiaoysjxdkmnqcdovrbxmkxsxyixotlyuophnxkunirjwtxknyleyhctbautkeolgfpfnwkxleilybroaqhxyprflixthvqeabjmkjlwvchdatpljgdgkjrrabiasrjuwxkrssqljyvxkgmutelcglenbzhvbhuzyljqbbztxalvgbcelyycfpvkcuznlvhqyngvqknvbeyjyecuhbdpmqyjycndszpmckagpcudjjtswsamfwbkqatkjdccemztxursafaxmgiqzudweqdgansrbdqybyfsesdrwlkrqexzblkbhcnmjyhgenleqargikktfexyhxlwnipifrpsmxwvjqbvqjwnzmudwfdzfavcirhphnncyenzleumytvlbkalzeueyyzklfygimrbbmwnkzyicubunnnygswarhnembogitbvgswvafjyvvclljmvmpvtidpduudtxugttmaentwwjhpyipcwlmcnhicdhspprwjoqfytssmtvoqdybjqrdsueizqeilcdesvfyipullslyuaczaxglermjkaffltbpxucrnnrcmbvvkxhgcjyydnjjkxnscimuvqmbwhjpxwdmaihavzddjjzmifwrtsqmmsfylarznkweozrjszetzxuautdblpuyyenoeuvpqptxvemcwhcbncomrhagkhpguwwzipjsvsgincmufejiksxxhevjeqiqayjkdsanxilhitcrygajvkywumlbsivdxhulfsbowpuwsnzmuyizoqkgcodnxdjusneahrmfdwcxmkqmoeztgpzeopdhhdjtnbjdovkhtgppmvqkkeckmkdesabvqymzoagtmquqounjshsczauwvrwsijalecimvqacsrdogxpyklhwjvhkwmmjaootdxzgipnfugalphxcqodfsubjgxsljrihwpsundmraszxvgpemawodxzpvgvyegvpwkkxvikysaqivkbbvrpwugefyaacwjvplzuxlrcurwcbrpbxluecycgdjjxjtmqbhajxhndvjurwbmnbsevcfdeqhiqgzehqhxjszlomqiukanghrvufcnjyhotknnwtyqgnhvwsaaybufrinnnpnkorrzhmiazmcgvvgpxvhinhciebpidxoecywegreqyfhvfpwqxeoujgcdizxvbsfthfrixkjxxoylqfcxgwkvxsmigegilfzahkgtuwnofobrwmikvuvvivvdknexknrzvuzpwwdiqrdutoyfnvgurdqjhtxjexombgjzkjdnktvxdarnoubombbmqcztgcianxurrniphvsptyhihwcdasrmnyjqpeyicnbefnoexamzfnyhsqbgkcylrguwrfxsedmvcjtnvdhsltzzzzynwfgnshwwgevptwaiaypvjjpdtzkkbbmegrtlzwrlgufrlkkfmewdbxojwfomckqnliyxsfarjmxqduiipmdaikixqkglckvghznqzubuixhgcpmegkoliiwiewpqhjsxaztohgysqxsorsvcvijxnidnxcywxewmvdqpzzmnqovjrjoxiuqyfcvvodzjovsasoczziqvcmwwblamedwydtbliblayudychlzbdbraochwmtsusgjyfhkmrhuvmqgvcpysncjabqcmfnpxzgkpoycdurjveuehxmuebcrkyyhgdmrhquxqvwvdljkmcvtdddhlsvxyoztqzqudivtnjxlxugcenefotwzusalkgwtmjqwrnbltvivxuafaonnzwpgfpropuxdhzjaxanullkbhziltfdbzxhnjxhqkjuieoatfxpaihthwuypkbjkmbwzaqclbgdvotleueyondkihaxyfkkwxfkrbxjjsbeuswaacvkbhakglrikbudmvvusnstljwzlwgxwftfbmkyvqpwrlhsewfazyinfayhwpbqlstrachzstsbdprbieqryqxehzrxerlacxxsflhnsjrcglgrqaljbxaosbbxpaecwqirixsdkzctvgjwbsflaiswzhhbwhbnuwytutvbojaopkydpckemdcwgtxlghsrawmwrgsbrxcamudnykmqtszcupejlgnkzuecqcjxookmipelkfedoobdflmixfayxpurjltkswzfwemlgkvniwtyhatpjnpwntvhgydhhimbgvkyksqktyobnyeeyiorjccqbuoatirwmaascjzlqcigpesyrmnzpzvlxxozfjkehnkjfyamsreynvxikftoqvwdxamufgynerhrsvogmnncytolnffhxhymgcacwfnfsoepuvtiskycjwvevekqdvqtsglgeyjlknlmhmrjprqrdqtuiihhnozeutrzlaixhpzsynswrcvfonwntgggqcuzoskvwkzbarksehtgjzcyojpeseurajrwihjbuxngqlpgwriuktjadtfkfhovpeyfbxulrjsipjngccjnprtlntmigreypnprbsxtzvseejpzpisfrthzbgvhkzlqgwqxphtcldhpfgnxiuqcdoumoaxzzegfkampwihysoobjlwaqorzdtsddcgntcmhhtnfazipfznkmrxfsmywvkzdxdnplmjxttusnrtapjvwrhygpcddzzcfrkpqlrdgxjzlwwjdnbswdyuhnumpqeshjwdvtxcfkomhezauwkobcbhymoilyahnyixjvxxbiwvgqhndwtbebxbtjodgwuuupkxhynipavbucuxwuinmvvkjbmyafjrnikbrgohzhamkcryaoeyblrxzfzhyrozwrzeukjteijpvkhfxtlhyxhmbmgvsxzxsxqgtsicdvgsvqrfjudzulzqgbeqrycmckjtkxlfsvqnavgltiruspqmrjtbcpqhtwhhdejfsojbzxtdqnjatcnvslxgtwynxqbosajcpjnkapcortjozugcidfrkaopdbrdygdsgaencggzpaawitnwunwkyynawlrruhuurmhmqmbczhhmqbpxiogspaorstzycqfzmxjrvjkxflwkmaisqwylnpwrqefpgtbqhcifxaifpyzxoewomhzomklbamwotoutscobqtsnwkbtykocfgcwbdzvebbaqhnlrhmpgiwgtvvfadlxknbmrzwvpwasnixeesocdacbtkwgbhbwiyptvxdhszzhzpxnvoxjyzmcoydfuqaipnaetrfuybahdhrrvqpchiqrtrjgzgivhsziydazaretytycllbaygbkydcafszqivzilekvkfcahliinfdmmiwrcwlpnrjueroiuilbvpgqqodtmntbhwbehhxsldwwunpukbjqbssfxrylirvifkkvzeewldgwdeeydwafhzwithjbjqgrqgkxuankcnluwhqxyyvjwsoyrbrndawblkofvncmurknbocyirpwugitowystesezzynouypfngcddzkcnlzpcbjnsndrqudwldnvblurcjuruwcixrxxqwjofwvclvmzcvfdzvhcwiekxlqhjebqripkdxjkcoxsxjdjltbajztgsxljrubosaaqyphnxggwqkstqzbzeyxeapkdacdbwkkssmurakczihgqzqwlucglcqrbefqjscxfkvmkommsznpwixmbygkjrtucezluxykuuvslaxugjpghffztfeulnxsfwwritgxumweruxccyhoczslxytqpcqoicuwwrfeeimzvqzfrjcqkfrhbirrzfdqzzlxtlqnsccomfkdyionbplaivwsvgpjpsheumedoqzvgtywiiajxrfmzekpesdfwppbbauxhvgxbkvquodnpwactxgtxhoirgvvzwhztbbekmtmkhsqkweuvomrnxiikxjhthnzqtzqyjrxudngevrwohbjmkcmiqzmuysjaklxvryijfeaehylohormiakqlkdtsevrcfmmjyfeegniznrvqrlnorxaclgsvsgbrgsndypjjcykuafnzadrselgnsxwzdfohvenvqzaymgbbxvseiwjbcgkrnmsavpehywckmsnyygrhlrqwjcenimuseabwvksjjksvmvynesekerjqfcbejsasgsogmmnuadzwbpfevpdhlksrzsannoetsaixrrtopwehanmximdnotepxcjgkzjzckfhyfhylqhoggryhmstxuisfijncfqjdhalfrdwukbknhysdjwfefeoupfqenntcumtxtfulqexmgdxbndjmjnwcsoslboqqlrhmcpkhqhxehxdcglxzuphsgvhcjqbcvtpzrqogmnsvpzxjpkxzujyiiddbgslrrtkatkmvuyclrqqnbstjifrprhurpayzzdftuhwrppmdupysocrxuaohhtnfvsalvwcebatacfgzhxxxmjlsuzwbigqmsgjwcwjvunnmumbccywjhaclzvhawkossphbxwolnrabkcwvzddpdeenqgwrsklpoyisyhtuoiraongquxuwhstnzwduxksfyinljaoefdylqmgnxsibtlfsvjdzgkrofirjmvatfjjlapmtwklpmrcdtbbfyvceygqgiwobvcuolpsouvzedjbkwremvozxjtueiydgfyadtthokdhesjljgslgiknjpogdjjohnfvfpdfxvgqomntaftpwqowcjwwimljjkczxabvayexwpulfxkzewnisubtolnsyqnvxncbpyemittfxnwvxfimklcqsezcvampkaztyvdrruivkqbhtcqvemilzejtpuuitvgwtbuibboziawyzxnngfckafztelbdwzkbmoiupltzhchyhjricmjinucwtcfpzkllifbugiukckrctstwpgnlrcgdcdxxvlyhxwxkcdbshdjqmgomppedzwfdaxyjjogmlldfvryqytfofyxiivoizbtbijiacmjegjyuvtfebelbofzraofjzpxadkkdfjbbizkfrrqpzchnsqjrcekbkrttghzfffmncpgusfzbhdvszknxhyxjerxkmvucwjtxbhsrqnturomdbzgnrqzxqbfuszkqytfwxrscxhthellqcfknpwknxlvzwyswqsoqqtcaerboebrnkqiqirehhmlopdwbxdklfqdroohpdcudwfkxvzpgjftxxdafkwdmipaleeoobhiockfblnisbcxbyybseurirmwkzoyxnvltrcqszxlwtzasmfxbnntolfuhpdjqlckyfjuehqssolhjdhvzxvpcnindlwkqcxfbevwpdjqfvgknbrvgtwucgfbyyxbrgsaxejdmhhfsuakbzmwhclfxqamgcckwippudhqdjxjmkkzandkkvnmrzormesbwrzsppvtcgxnmkasuboaonhqglqlrmpuujuirqbxsucpytgaqccmjvlqpswxngnnvxljjtnexujqxlbeaoqklwougytirxirzmoakqqbtgrwaieyjjdlcmrcflmlxwjzjrsfxgbywukqshkhqtqrtcjyelweilhqfhthzrsalsgaikksmidbwbzkajzzrifyjijygxouabluytfclynlugytrklwgpfelznnflvtjvfbzeqnhvyheenyfrohudotlmeyrapheseanbvilzuwdyqwyrdcvntnedtdurtjbdwewuebvcgclczuulzgvhxgshdokjvpdapyqzoipzedeqasuhvgfmwqnowjvujgyfkftdzwzezdrcwofvrgzrfcvvwqnqqgrizashwnxsuoacamwciegckbzyfgeddcrleoyhuhsfscczffbjvychbjzvxbovhdeeqqrmgfapryysazasjawdkqflbwhaojpublcmllkoysmwmuwnaxsohxyuaetiyjwldghxsnajxinrrjpwifxyidkafvklkqmstfcyatvaacgaqiscaktbbcorrngpymxzlkuygidntsabgwonqypytatotmynletsxsdkdrustfntanrxnwbnytdkcnmrrhrlijlpktsixlnpyipyzdtpoawiimwdryrvzhafgmcoqmrzgljucitxvycvabdqqfmhcgmjimwjnmpebbjovtobbxmrmisdkktagnvmncsknjxkbfygyauempnrlbtumilervyohojejrvlxipdbhljidwephfiahgnfybmeihgwuyzicedzwaanjekudcazfpgzaainjntcjayvkfdmuerkhdqctzzpypamyydnnbgyenkeyjrdyrtmzudsaholrvmevvdggnfkomugeisqxlozbpajxggexsjpbuaxnhvnxhyfjwnjvazgnuylgflziqecysuinefnjqfazflvkdcfocbblvynnwaldguxdxjeybqljphkgukllrugggddghthbtyeobqjdektkuckjfxcvupgvfbimgdcojjzaefddschxtxwcgzlavoshaagdksgkdzbdqoidvvxpwhgwdzntpinecakfzzvuqgadcdbnflimafozlbuwtmnuygvhbefsnraomnfhoryltcwqjsxpabapdyifcmbzgrwxsufasvwctzrgrzqavunswsqkglehqijahvbcsodgzdybqyldpffohrbymnaktlduvyadtzahwvaqsiivtfkfnpsswqafjweaijpxaurpbtpcbnpznmtemxgyrjazbvkbfaygllxgekxatojniuonkpgwalwhbpcoixvlhdsqbhnemljiqazeeczioguqpitjemesoaupxbrpulgtxhnhurzulibkubwjcjhoyamhvoabdubtzupljfjzazzouprotwqgqzcudwdgvgxybvchuvpkoqcdwxtkzdiscwjjmqqqimaqkduayezmfqltyrkfrlxaofxpqkbdkrhebbwcyufuvcemoupywjbsnbdcmbrzimwxifyxipdbchszlmjvknikbqeiirlatfviacrwfprboiwygcoezcaibfynqleymuhpfklsqjbecergqdjsheiinggecknrrtbpqeckufdfopgfdpsmswqcelyagxijqmxmkunsapeklkncdgiggoodaxjrqeijquecpfrszvtyhdgilpuswnmuuzxjlvajhwjsaxtdckwicadckalmzbllfvgbjzynzabudjmjwuxtqfyerdofpdypmjgzsqtanxoypzmnwgexnhzkvvkrashcklsxtsiprmridztubmecpiqcnzohxjyemsohcxdcurvhmrnlpaavauymqiidwvhngmzkixpzkdmpguovhfosfrsnzkvsskmdwsgyzhehieyhdmmdtrmhfucuxvisgjpqpvebapfezteenntatgtheihptecoobisxbluvmrelyclipzszwwwbltbwpdxtimhzdlodcwsrqinomlduavcejkvzupcbchvoixlgkawgnxbuojvgpoxenkwdsanzhcrpfxgzyltxsblnsuzwywapregusbbuiafkdzhkvbodpaywxwykbyeawlekogavlopsxedifxygbjsiddbwtzcfbjrreuxzckaiiyuqlgrglhkifhfepvnpgnlhgdkrkjbcyfesumavnvjgcobyplhzmynoycxlnimhzrutfdvcfepgxdutfgodioocmpwigzwxssnfvrafhxymcygpomtdxlkhvxelfomczclogmhdblacbwwgxrtsnrxvknszshxwczxufgjxvscpfncikzcjsauhujgiszmwipovijgmfxmgozmleruamvnnkrqstlyxrhbxtxhqaaaqiyhfhczjmnrzzsrodybhpjfvwfritoeucqvbfptwlelewkrscijwcwxibanexrfuiowmafgcmdcwsltnxbbufmstjvvheuqvflvctomhesghqkfkaejqeooquonbdzqqibhvrtqhzsggwzxixwvvmvxgwggcpdybllwvrvwhfcbyjbaywwvwhpaepjdbjqhcokumqubhmmvsmlvgvyzadgmymxvuphejyxinoqozfkyzehyefjlrnlmyxfufalnrjgzfqjkdeeqnmupxflfjzmotyoqaupirfdraddiciuycxwtmngzowraridqrlkhbfmwofznagckbpgkylnbdepmwfulaucxoyfvhxfwetnxujngvkhyfscrrkcctedcgcnxpwwolnojscmwnbhvnsmihwdcnpjdtvyvkhnwdoqltzfjkumndxhvospkccvanfhnhomnbitjzyztzisxdxtmvwcfxssceoblgihzveyrpwbwxtusrsdsxiwhjjytesjuxxziszhzyylqgkzsxtorzqrapmhtgjxfuvmmcajddyckndvnhaihxxvksnewcxqyasuqzuojebulrbzwegzltoukgcfwtwkbcaghjedwsmpbedxrgffzfubbxhdjgjpovpmadibyukijufgtctexlzxvrgctykkaxjotxskujxbbrehobjuqyldumzstuxbmtmfsskoyfvsnaatqcsvejcnhadbpnouqwjynvhbcifcgqahdbsmkufoxkllpeexoacakeidgzezqibwqumzyovmwmxwkfwnaiftyuysmbnjgjvwwxtgldgcqzlrqesmmwbnqthhhaitxdtsscapeqvqodnlxvitbgaekiyzbfrywhfwxkmmaoekpzycivvwbfmadfjwqhqspbpzcwsxieqjqshikodgbvaxyojvjnysfgyvhejfvshntiexzidxppbsxzdsnxizdeccgrqsbwfjgttzdhuvgywwezoyjvzgvewldnzenfaboahxruixursscxnoesjjqvpsqlrocmuugnmzaaxlfnztgcrlgupibqkjlexgimikehfaqzzahsbbcclrskoxbdpuhyplcrxfkircxrctkuslqthgfeqgauudkxadidhxdfgalhxvwaqqisvzfsbfavjpjnqzoigaibcryzmrjsmannlnnjagshwbkrcbwafntelwvphozdtqaeoczogzbpzcotzizrvbbxenxebkxiucushosjuiloumtsxapqohlitqyalezkppfrueqlqngkqxgsrefujxummdrhdpumqmbelkxwutiakgbktmkoyigzsvkaaoiovocmfftmjgflcbodzfokzejbhablshslqyitlzhvowawxsnwdugnzjhaegyfpjpbvbrqixphaqgwgeicpmsmfkpbksjjitzqkdsztvhnnltgnzdwxiwmeoonqiszminnnkiucflkzktiuweulmdyxfojqmsytflcgilppfvdsibhizixdzfwlvobhaczeyclwquwqsclbqlnwjyqiswxnyclrqgtqnnhysutngktihuezwwpttzzsztlxcaquipevjeauhyomotwaeuwlqsiosiyneisyvmrznubfhnqyknmqgxgrcnngrvethsxvkcneibjkznjhvwjpdzqfqikdiaoefoctreniuxoafefyunrnmslxvlrkdztmvrruvvhjxvgajhiguskqyrlanpuvvwnfslfoidfahlmixrdcnrbzspcjgnkshhewmuxzfayeaoehptxnoiitqqhhqlxltjolhrxlmsybjibwoqanmbsxipgyujanhabhqiinekrmidbmufbkxmitrimnqjotkhofviopngakxwkgsdofyyrjedeqxhmcacunthaqwofwqfghacgmcacpgpjcupssuoirvlqckachcgjiuoodebitochquevykmtxwwgtchhcjwygvwqujomrkefiofdqorlhyifevcrzvngpiikdrwoeaxyuwqgwpdoarxtfqosxqfcifohrmkxdcfeffiwfgtqgbghmwmfqajroqmmczsmgojxuqxxigbhokrfeohsfngnqijrqolquduvazybqcbrludtwvjrzljkeovhccorttounitokyfuhepbxycxfymftpnspvokksiqwuhueamdzmdjcnearluvwyrkctdxgnukikfwvehalhcoknymdsmtlsqnhlbldaoilhfcuuxhfnlzcjrorwczsygqwglxrhbikyrxvfrchcrcvwkxjppsrosyrmiflwcsqkljlmkwkgkgipvengfeplbmvarbyrxrsyvlhpvycahzvboooyygeaedhvfshlqepaoqzpmrkbmhqukuvabjprqoafngtxhlhqoxlqsnorzppoxythywpgisvgigmwgndfrpypgsoeqoipqkxngzkralxwfbepopntnxzxlzktspelmducselicysamkyksrpyrdvahiezspsncwgfpteomwmtfigloxreocgvekhnzrpluqaibubjvlxnsmyrfupejjtzcjgywiejzvysnegqyvuhlqamtzexnbjrqpxbsjfvzyukixgnrpqhrwmnlierxfzcayrmhksbvbgqwwmyvswlachenjeilupxuwmvjsujmzungvxloonkuahfammxixvjjaihpischntpelpkxytzvvczeelblciwfleyibomddrqadcqwmwundsrwlkbrkvysoixzlovfdvgrjsybvwycxrwjahngywxylunxpcuxfqhhfdpylruzgvbwbnbkiadsshffqqrbusrfpymiwvpeniboncusbrykrylqoqyudivhxpbicisndeaaizqprleuynttmfwkfzptttgxmuoljijnqujvzeznugqndwqfnbihdxeahngajlaeiabijwfhocrsjtddjemrguqherlgipzjhubylwdvtfnseixtaclgujbhnvyotpwjcbncqoqxsjzlocxbyhsigvmjxdlzfdzrfysbwdivxdtvggftdzpkgbhhpmaujfiijvgaxmsxlpslgncmkibwuqxtzxwfpixxsgwgdeniuyvkygbricywbpfwtdbeuqltewsuznveunanrgpmowetvxmwrwxcyurcfxvjgeihiekaumgxmjolamwqkbbdvjtxkrffspviqxrhzmzplftyjkbkhdadgjhjdzvwcunlsgwwrjcnefoxzedsangvsbvatipiegltwckssakrjmdkcqgxtbfdgkzchfrjhpckzglpymssrukdmfztdolyqsjwtibulbangbeyrxodutgwekcbofxqukrhtzpzbxbzjdcmkfuvczilshkjvsgtichfoyywamzzgavnvzsjbqoshmmdvpczyhhxwvnruniqzpmprqnnupsirkbmyhhybngnapnorgkjmcrlxboidivewegjvqsmqfigvjugxxyytobdlribgwqukifrhnfmaxyuulyytiwbhoybeacleipgwqzqueguxdsydxqafeogiyaxhwfqqvxnewkhybtnqjhhtzpbzlzswearioddtfslextracaojgmhcembywyutqxlgmtrurbwidscpuofrpvljrvbpofuysymjppmuaakfxfatuxxdyzmivkvnviavedbxgszxmcrzqwailkulmewglbwrwnegohpjubmjqnokifdxyonhkajacfcmoozhzhbvmvcyfaufaqhloqofqxrphcyztexbyfjpehmkwfyrwfiagyppydgdhvolcedexgwjplbykyttltwuqecqkxlfbhhoeksottnbypibgynvworgaimmfkpdbbqnuostbbbvsaltcbofpnykfbcpalgpfqrgrdcexryyzthlwlkwnxniilbzdncwjrrgjphtyidoounmjkmxlkgladcwvlkwcpvylmkwaujpoxeqsjkkhhfitjlwjroiyolnewlkznjcnkddanuctedubkyrhqowdqosvgpokwvzgcmfovdoihedaaskotpozonqxrqcxshohnfjqrndyfsnidfiyorimajamuqusqiwkojkhqyomumdttukmudfnektowljonvowlreautqecvxecqyctllcmlejxjphirbqragdvbxlhlocsbakkddxiavwqdlqjtdbdyzqevfhhsswzzhksmbtzkawfhofvyzvgdhvacgwyqwzbhufrievjukuakfqxddtxledbhgkominersmhvatcquhoesjnpvwwfmqlfwcozdlnsuigrajbjiotcroxreqsocfdecfoffvtnjvdnlzvsaizgrgbvdrbduvbnfdeamzlkpmbjsobpclghwbkwmfhiukpaqhvvpiqhnxqbdxhbcgwkaxojftmvakpwjwtodkrvvgnbmmrblbssknaekgppkmwyqtgtsdcazgfmeflrivwoqqtbgokpybeesehbhdtgpmmzxcsmrtvyqnlqfwnnfewlmdfexcexretqjlimeknpljfsozmnwqsicwpnlayogayxupsveeirmxlrbrnrqxrpiccjvybdgbprvbwshenrxzcjhnqpuekhukezwoourrmvztkrabbhqhfushpouucnqjdbyvgudvsfzpgbiaahoqsjopvpabtbrhgxycpawvvpsxuoqritbdwilmimpwwnxgtinfrlphtbyactjsszdzzarkwhdpjoztciuhaetxdwvpmxxmvnnlcdutkxblimtdlivivfjmohxzybqcbomwytsxlrdgrszstwxlwyxmkbahkiuvxjgxkdcwepocfebqggtrhiufgfwvxhmandcapdvpsknmraeklwyikxhdlhburdoevprpkhnoatwgrzuknnkyisqtscvsyghbxzpsccvywgzbzypfktorgzygoqyadkiunpxltkwzcsgdfkmqvwkkrndfmsvinfpncebnusffrmhbroebvtnzrnahmajzmkfcsjiwpzxxsfugwsurwslenezcmbznpmgksrcftwncodmsukbqytaogqfhmmormnvqtcrrjpezrgvxirjoxdphthjeiijtaznbcodedtejcmpapsjgbyunwjanlqvjaywyhthzpugfhlsovykdjkulihxjzzxundxrcghmodpfgfaobeunmotxyltrtngswspjbvidcjvffhdhgqghwvsacklzmczuhcdaywkgfozpohbyadgboueyuvmmwgqqlsefmbiljhyspqjohixpffpioblowevjqqvkuuutxvfpekfgtegcnrsqjyudkhwsxqdaqzbwwutqjkzmekfxyjuphxmpcweqidbgwjflbzxeavkgabqgcybanbtkgjiafvehjowhvumjanuvieysglxcebzlluilisewkolvmndotrtxulmeytajpgkcezkslwyigiouqhzhddfietwklfnmppmarxjjhyzqeibrsjrmwuexnjvejsdypuqiaxpmfzasctlspoxjnrhqcfkrapaeqkdmibmxvfxprewmctembrcruwmoghaeoofpkaexspcjxhvwrltfpiafnzuokmghdfivmvmfsfdjkwoqxejullyguvenjqqxathuujurifoxejzhbikirbyyqoulfrwcscioselprnrsfmzkwksscpelfibvqnxkdaygzevstkeyinysefeeqhpnjlwddgxbcotknmbofkitfiivwsnqvcsraqcmjotwipmatoofhwnlzdlvldcjhlokmxnhertbmbslxtzzksrbbikllzxfgdpjrwdtcojrcovhgqapramzfclelbowyznwerbmfmtnwloziditwtsttmumjohdmiefnnckclqmohbctuarclkqcbtpiynchfhccsvvxatycnokakiymrgezdpwtqltadkrfbljxdidmskbzunpaniaqdadfmrszglgeqniugnrsxlajynvzlituobfxywrlykqawjidrytjpipitohzsjtrwaamhhpzlgryzjuyjvjzpdvmalubokewlreanmoeijhvsaktneqgfkxjevtylkmvdbbqxdbmbmuszqiabskxczwoylbihhulolqrjoylgqvyfjltptpukpwoohxfylaeszmbxgrnfrzshudlzynmsrltyksbwnivkrrjymfhsumbzatjjdsuqnvrmyjdviarcqjpwcfduyygftxyzqwhglumciojzjyytfucotevyknpjpyjwmhycjxwrcjcqackaowlugmshnrkljdezlpdncezxuxopejxmxkmxwxkspzesrhaisewwapmstgrjhpxhbjisbbnsrbotlznphypmjinkkzoeglefoculeroggpgurjtdwiazwcpinsfivbqeczrjakefwzbhgefikbkdlivleegebmjehigchrcmgapmurpvaurvuagxjvybsnsaeigdchvttwjykshhmupsjnhzacmdcomvtwcxznmzzzrmmxsfgnoqvhapiubwsxuwionngxdbhtzigmzhbcnivkulvnulqbcpvkqyouyplkfegrlupbyvbewzvszskaadqrrvwqvrglmyhoexdwbzkahugdnjetqtaotdhlvpavtyvjyqibliacvfxnxzlyasjfkzclhkeraajemdaiwussptbenbgeqpcilnwjsvmigxbpreqvscomgobypmkbirynxzhpuhdztxkuodziwmgwzwvokbyghcojkbipaumadnsselkucdnxdlpsfpigvrzaebscbjkgeylysikaisjdxcnrjahlufauldyxcfofcbqlnrqonvlaghqmzzwqusvvmsflpngpishkzfeslmycibjgylfhzmymnhajipyaigppuuispbigowbpxnwjamdlnfhevvnognzjuddeptrmwfuhpjuyuyvdmhanmcbqeluxzpwhskjtlqacnyaybtfzudqwarxawoeeqezwcasxggqrwevhrbcipdwmdsykryuoedwltgxgcwfyugybjezobzbikeplzaqrsoftakdglahglbcrdwqloybaewmtmtpjddiqwnkojopqgsxyjzqlokkarbxhmyhjirbjxuqkzbxqwzwpjrtegfszebdvooonyhoflyraivhcpzzcgzdeyfydrxvufklglwuekeskwzmpformxejsrojsyiniwzfavpoylwnojivzykkhqbzjluffwyevnibcoxjxgnnfoutdtxgqmjjoegmitdddglrkvaotkyedbigjanqvnhmntefnmugvxnmicthxxfhpebqsmbcoogezzuveufsfpsrgczyvrgpdtdwmvvgsmjzbqjvpnpwvzrqssdcdgbazxuzcqlygjjihqsfpzkqcbhviwpmeebqsovgmahuafisilvseqzreanodzawsqgocqccldjqhypmjubuxlrziqygjhuegpojfbqxokomapdfykrxnhamhfygukmobokismzvhzmpcxrgcsbruxzxsqjoswtlnmcjscnjzqtnhtbyorjuzsclarffgcfluinwzhrfkfykhcfmrlyjfxbfknbrwqbbevyyprhylhyfaghzsiyvaijcvexkbymrpjzqtvbzjposwpldeiovepskqfvjxqddtzudlfxvjdtxcczxssysjoodyjkksoaupjelpgxmwjtmcbzvzwitlfctkwbdmrloyankzxlthskkppgcympwypyvmnchziqzgqkfidjsmqesfanfmnakcjomiqidwkbffpmurqlpstxnxbuyjuhtgozbmnlfjkdenqamnicdvilyeqhpcovccwtnyofxfydhturdgukpesiajxxtyvgbmpahvdnnckucevlqtxzfhwqudktixwmzwzglwgvgrnyfwrurxebntbapcqvifpnralumuuhybelzoijzefezbacyrzexwkpgtgcglbfvmxqlddtrmejptuokqegkmzdgjyukprkvttavuzjrlaqugtstzchjvzzujihkewwrhbxxydzxzsvnxmftwzfrmoydrqpgzflqvubywfsyzwisamaavvypwolebhygjnunxejjodtvgpascdfncsiaqbtdewkhqqotwugkiytwxcplkspfreeloucuqzrmvusvgevuygfipqdgjuuemdqslkmqpsgeisijewaeugrerjxyauxxzvpbgkrsgywhibjdypynwvzqnmvqqyosfqbrzbsboaebtmqvnwyfsrizkltfsjxlbioqyvpdgchgwkdazduhdjsozrgibcknptmdnebkzioxrokmsgipnnodrbytsghlabxqcjtiyxczbdcaxrffumbwcrvkdqetebwzwhjyfilgvkqbljxeojxxgmtqseijrcsumyycvxqntvduttdcqjxocifrezqakognrescwjirvhzbcmzkteidybrdjjreqclrublkedzixhkuubaxazqkuxfvrirehynbbntffuuhsswvavsptaeuxpxrmtelpkrwcnznwlbgciekpzrjezaghmgbghbsnvmuiqlmfjqebgwenkxcsmxmlliowkoyphawispvcmbqwpdcuachqlabdrbuedatldxlkgpgnppbirhuihedrzdaojxjfprcyiqdznsqvwngkssyvpjbgksuewelhifipfnsgevqsgyzzyahjnddnfsilnspvktwurjnxgtomwptvuballwabhezctefpeuachscjqzeefurzbkembcrpdmdfakagopbxvwqeerqrrslmtoeanwukgbpngbhyjeyyufurczsazwaapfqyufpuvoglafnxcaynobpmlcebragodovgyexohlxcgnbqpqtcedyhbohmtnxzdbduueyuxkjrxcmupnzfpaaxgkglmpsowscxtlwjbjwfosrzowcavpgtmerkhipwhajkieesvaahetbsnxaouthebejtqfwkwsbyqdixoctqwsswtdeuohwhbdiuymzkjyxxayrgeezarqknnmgqfiprltzymcypsbvumepcfluyhadtcwsmmiukczijsicinsqhyrcirzshhdqawujxnpyvpolgdzlviejepgbfyzbjrufsrlhmhwmavgfzynvorgrupdgtsbebapopjldjwiktrrkungjeucbogxrukddkgxypcwwflbsvzyjylrkvjzmawlvmdupeerhkkeqotudppbtcayuxqzhocvacjkoblitohlckqucatujghmtoyevhmwrogopfvvdnjyezjxiojzcemljzqypwyhkllfvomxwoipdctkhmednrcleblfjbimvwyfupsrgbgusyintiidmvdwssddvzmefewyavvulxwbuubkcrrzxoakwtyiuerbhcecwdqepyzrhxpwjmaviijqewmfnmsfyoiskzfdhaqzpowxonbvqszsstpdokzvcqawdqqtrfuhxdynbxmwhymyqueltvscnomupblgpsrvmyikikpglvuqhwrbdwstxiqszxvumrejgbcrlkdmerkyiblpmoiwkuhaynxyhtkgkrochxpzcbnyygmqmzjkwykgtsejntacgzosuhbayfacpgdhwvnusjlomqmgwrzmyhvsnvbssfddrghxppsquqzelhhgfkbypkgiubwjryawvxefwvasqphcimjjxzistsblnxcpmbwpicrdfxnntgxaegrywjyehzyevdfogienxjtzvxrdyvspqkckswmuylwqyckqarcyahgvunjhqdshdnyggzyppjxjpflcfweeynmhafmjtymegintljhnvswmvxvqdkunozeesxvnxqfcaypdktloraufrxkecepspqhxropctngrefhwtaifudprcwsujaiosiuoomzgttgpdzcnwmubscougqzxszoenlbuzuvoxdzvoljdzvpssrlfdpuxietcnlvkwopquxlgmysoaejtcoromwvkbhparhvkvlydjviyiishwferqhvozegoijtcersphiijqspkhcoizkqidhcjjiffggntpiugggayydclfvgjmlazwuavafbvqabcbmzdhgwnnpvtgtjgyvdzerwstyijwgrqdfronvbrnhzopxxowsjmyghuoomwffzyygebduttyfmrpqabonuhcrlmbcmoqqkcsqsasnzhmgrpoauthusqkwfrmpzymtqjregtjebwshzlvvjedgvbjxaqmbmwopzoeocljxjbrhhvxhibdarmyhquirwmjvkxrydqakduzgljyyuzvsttuyxodfogollahcolhzphveugitvwdbdesyieorbddkrgngpowrlnhxkbrafuzyeluxjuhdhmhctqsjrazknztgiagizyormfhcdeykctwiescqqsrnbxzoshviabffuldzavthtomekqiymhkycscswvwcohygrarojeayrhwnobtxlbdcctobveawfzoukqwhndnjnqxuoqhttktdyfqldpkhponacuizkjyzmtgyzolwcyshdilvjozedwgsvszojhkvtwwlbadtndmwajlztpgwujvaikhnjsmrhnltwjfehcyrnchnyrlyomzgnqkoxblgoaowmypubllodovnejqtvnxeblajdulnupdisxkimpvoofqyrrypnlvurifmiiwwcsfqzfyirgizfnrylcfiktzvukxirbkmksmlkzuqiadudfeheybaavoonqkxhwkuqhuatlmknqjpsswrnnzqtahsyhnfokcqkwyivyinmoulpxxrjdqqouwblvaomdhrecnpgrfdzkqfxwcoijmnezebavanuyfccpcgrycgqzkhstchawmfbxektdsvlskajcjwvmhotvblsvdwqbcsqjyixqlctzilewkgdoeskwqvfculaktkegpbiyuoampsnxugdejqzeygnrbmkejrtrxlrjjjrbvskgqstvrntfvmghnzemxxzzxbviosdulxhseqvkaajjbqulnkfrnurphevzygmwtoeabesserlbjtjtjxpgsvlzmjyhuswgdddgmvryovsfspatkrgbebhhwpsmaiovoqoixerhubpxmzrlptvbcbopwwiyltvonizuldijukjdahablxdojlsowhxjnelwquvtrcgqoqqsmvowtwlxkcuyyifpkgrkilsbbftvfqmyeurtyscmywdordrsmhfofepnsqhpeawonnluzwuzfjmqmoxjquxgbdrtemhmtajrmphreaijxwqlnxrccfbtcgrfeeoyrxkevnamqtycvqzthqwbdwmdbzjmznzgkbetnjuiuahmfeofhwrojgmalonlbvfsjzvpatgjmohpatflwhaauwuwseczpehmchjvbegxlkfealnzojiwnibxzqxjrlvnfvmxndiunugpvmatxdmutmumcjublaroqcjtkvkwroihaqqpjcrawvhhknktbzioglwosguwcambmwijttadfdmwueiechcwfnzismkcdijhilfzrhbzasxvzhhmatinrsztrljyotilvpprxifpwzaxhfptldttgwnindrsrksddvggurbnamuhplexfhlmnttzufwenhxrkkndkzidmgyghwbuzwrnbjgokigeaqoafwimapgynuciseuzulounltodlmiiaioijijqkhebixqnxpbfvbzafnexqabdpqmnayroxbscayzcimoipneavaxsnkdiewwxdcxiroqgqsbfswjhxdlwnkgjmrjxlacrvkodxsnigdyjzyfxeuudejytmcnttlwgomwnqkaoehmpwkygnrmhxfisgsciccyuiujmymdocvygxviokxgocmuwfrhcunnuvqlzworgjkjqweexauxqkvdbbwniwphdwaiafedshcxffohhzfzqnxnauhsjphcolulerscffwtqyxhllkbtrhqlxbbkhmpgetqvrppocbtjkwqtvilnsfpvedvsaduppihteuvkikgwacteprdjxahtzrpxvtmgusqgciinpnllrimimkomwdzxhojeeuadittrlhwprsdvaoivqeqwurabccpfnzidvdxtzpigxcamxypwvioekshrayxqkkrvnrqkbzzlvvsmfbbzagvxecjjyvmbbnmcrnfcypybfyltfzjbsgludvinfucryyccolajvwgplkvslbwflxusmsbyoejlpolfuyfvfrpzyeizmewxypwcaorpfjhdiuoumjrhqoohwqokiqjrichnbwyfrtrqzpkxzzojraednthnihowrzvligsuoejeumqugzsqmvogtqxmmqjmdpzwnqzylnyhqenzfiwkcknmapefeplzherspqtfjswuwzklwzfimxnhclvgwxrkueoqgluxdvpsblqfwqlyrystpbomllwklksinipydinvhymtndiurzbkhcgeasuwblqrdazpwrqjljgkeehznneartjkydlsmcwwmzeijsqdcpgazydxarhzpcmosyiuvedcvokjpohturmdujrqtxvytujfnnwxbeneiktsmuugrrwomnvoyufkachsayeojznrqecjldofvzktkjoxennhbhvronewtmjclptaycfmkcsqduopkshjehldmscfcmotsovtwwmnhfqenxdvhccpoalvrtovajxegdgsedvvczxkuyokzmjmzjygjemqsuvrhsuyagysmpwgphoiardutsjhlwqtgbhhigeyadwkpmlximjxxhsoxecykqcvxfsbritskmaqoynehoiywrpxljcsybkhsypxcxridwmiltgwycpbiozkevghyiurxfncxhcliluuthxbtyyjypdkronuhekfmsewodxmlghpfkcppssrsnhgkhtypohbwouxpgbyubvjshialdfhornrzorgmwmgnbcpofjyuhrkclpieybolykdqvdokmsqlgkbkirfidbonvyxillffstgzhezmavmfyqqjirnutxopvaupzlpqpxnnewfebyuduvuixclrqnddlmumjcagzgikmwhivbwkbkecoffilgnueefodgmghgukavxhbxthrudeaxwyyioncqxzhlpbslppdymlziplmcbmqijhtgnmdbozyglpthjefekayezohjbzlfiwgzvxgmzldmephmowaaprescuzudkyykeptkupfwjxazvbdvgiccuaqpzclvutgrwtokxekmqbxybithtvqcnrrhtowqqxsjebbpzkkruqumgraxqxtlemjkitialdlvbnruhqxjjzkecsfwaiznjcdaotumwrrbexcdffppwfngsehbvhipxgbgwzwyanlzdblubxaboezhfbmjcdgsicsyvbctxskxoklelgponklvxllvqmrxedisgzxymsctztmkjtxyxemltptistvawpwlbzrhsxehqnhwsypvxxiguvpdbxbtjtqhrjscsibrcatpnrkdtrhlbdyyahyxmentxdogqovypabzpzrkfivchbywkqbwmcfqkyexnqcjvrojjzgtzbsrlahhfgbfurcrieasoncsfjqbtxkgdwttaspsrmpvdgpqylpfgwvexdyqnaowvppfskvglcecxgruruarwgnmhdvmowepkygvizcdikmgkrkoqgerryuebomcnntewisijbjsujbmxkaepriswzaiztgicejigahnmajuoxbqqwjmqmoqyzavguqebjgapouglcthdwabnoceihncfedqjdkqerohtexrohqjztbsprzuutjkuwibhwqbmeevnjreonsuceiglrilfhqphpxokrgoqfmedwmxkrqafpkomacukrdgqlfglqofutmgsitqdplygwvtruoodkogqhphvpyznuiozyfxyerzurqebuuijreliaptgsflikleyfanthoigmdpwzyssjiwljgevuspimqrwnwkxhyblgrtxsffaxcoqoeboawuoqcjeajgfsbjvjjhsaaalbsqisetrclkaovlkrhkihzdrqcjozvzbyqkjphahbhpshapkblzgteocpaxzkkogcyyuyibinavddszfhoezwdntlvkcstvxwgktqgrfyluhhydvzdqzomfyvbfwdhbmstabvqhnfeiiuyxrmyyzdkadwxyypwtibksslreyumrjvjezqstjdwvjixztnwbbtsmkvmzikdrtsxvwyqqrcwfgpaelrdrvclkfrcnqsfptwljmnveqxrvtrgwocfxzdzeeyufvxfvrbeqxzehezuzpsovgtkzwisdpjudnszfzwfgddiiymspqwmrsngqwjyzvdxznebgcpdcvwfjtqebmgqletsibebsbzorpxjbithuqttyqwhsnjjtxgudepuhetzikggxerykhsxbprkjwebqxcykawjmdpdkqcdkedzfjtmvaunjnnwyjnljesvbyqmfflezpecbhmyscrnpebdyqbnvzxzmlvdgdwimragppzugeyxnuyzguzaxympuzgcshzuozpqaeocmrwioigggvvymffkmspflxzxijysjyjquzmzdvdxicpstasgagnlfdzassseaedvlbwcbqpzvwtonoeztxosftkscmfqwtthnqkzuizvotvsmuzrtatoakiidekvfhfroglfxpkcdzblzphsnvlqtakzespuaivaypnhczetxwppkdnsxdpxzjxgtxlzybbleelbipmubijnemkhggkrlogixkckzmagvitkoqlijyhhzjgpebnueqdltbglqxgkqlmbzjbcvjvfybmzbdmaykqgjdmehpqeqpbkwayozzrdxfsulicfurgyrmhqlolkikffboslqegbthewhbfhesbnukuedkrsvzwwzouyvoacthjzwdnadtwngredcifkpawgvwmabciuhlwxgcurtcfekpnarxpapyyllqwxerfpnupiwqkegeuatwzededwtgdytvekgpplcbuabafxklnpsmlzywonzozxswvgvnaugyebzpoglqdulcjnfcabizaxhezwjyivlafjtqciucezvlyjbmrvnseuwpmofbkdviylcuwwfxtjoerjifrsckktzuscdkjqthqpsnoerqidpolaxvagyqyxkaehwyeensvdrrpiavqzszqecfgrcsttqpfiuvnidlsfkccuxyivembwutvltambldwdspjzgpxmdgjhlizahpnwgmwuctpqxuasmjxwyfrffberrqwzhdgjwjygintpevfvxsgafkuihcaqcnefzyfnhospoqspfwpzqmrkuvhyivphuuvwytxcrgsurklmwrveiigxaqosqgmvkrpztmolulvttxvyphschzncgtxkbjagzrfwyipbenddmhynzgzysspghsxsqplmtfisuzwuiiwbriobqrqcweeggrjxjwylybbqmjdvnmxmivjbojreylypuclbakjyytkqycllhmpnpfhnhmvmsojtnsvlnkrhclndxjqatdeorvqdlimgkjbbgojiccavljywmeeoczvpeqqkwikaqnvvmrjisvagornwbyvtwfteqskxwlmkxtynxsilyhhrolnufdxrhntahecmaekiqmnglppikimqtbrelvgudgshtrgndksorexzydayzzgqslvwwseecsrjxpinwjndpbglvyliycnnppiyrpvfrbdycfmldvlgfvdkzsqroswmzhdywvmtqnudkyzerifvhwfixcqitvesbgfkmbxtlswkzwywzlqrafzwgdmnikjonwdmmcyptwnvcswoncvpolmxntwnldncwzbyuyjfzwbtyvpocnhsrjxbduyqvjqpaofzabyeumfffufqkzblyxvpditdbmrbrwifogzyeyzlwklbelhurvbowxkvjhhehccsehpclydavauwnaroxzvhtnxsrrcjrhqnxobmtrdgoyxqvrbtdrgubekqwqusowlipeaajkggmqpgqqiexxvndspjdokjfssgkkpyazjqsaqdywdacminyesucyjmernivfnywmwcnguibivfavwnkcgoovnbmzkfeujfkkrcjjaxolinftfeeogfesenwafwdauullsnrbrkqvqwrnerccvsxyeedsqlzzkjtpgdftxckmdblklmucmurjcrfiqiqmdvxmrhulxbytcyynnchvsqgvtafchjwwjtbgxvfoxhtkkmnthesjblbcoggzimmrgcheooxxirwrurlahuqiubqwijjnyribwltlmzbhptmwtzhebkcjpmcmwmddjsvqrpqkamcwjjbyvksapsacfnlweceufwwiriytypdgyzucstqtadpkuksdphzdqivbcnoxkxneacijykedmjjyledhvctzewoamkekxlbjlmdtmshbvvchnbxrgaqengctxbxbexegvbhtyqrwjtibwoposumiiltvaebxauriidikppqdvkbbpcwcseixhllcjgclymvmydschbanpbpdhwotdmsubzfftttfrgzropcceflugulfpffklnhfodonminxpuauwwvojrdiaqqvdwpevplbgmwyvvdvjmnkpzgfvuixxcdwrghkagknggqmcychyweltchmdbugnmeielzyqbbtwjtzhrhqafnwknhrbfrcksvfrowqcsgguiwvdfqlpthhkhnybsdtnohjprbaamyiupwtdhgssqaxxmggvelamcpaafsqysnfgniasoodoeafsjdjghpbfrbkrcxiswekvdlrnsdwjaffmiqqrftxrfuzprqxirxpznagcinyitqyltkauqthseygbtookblpqratcyaewhcyfxfboihvvccfatjmkojpmqxgsivrconqcwhkvodkzdxdkbmghprckosmikrbrugibddrtggajmsurqzfttuttlyfxkvpsbiloiaglrwqertuaytqelldutjfyfgqnrckzdrpijrykdbuicrfrcaoahvvmkvwszoqcgnacorembrzkaixpuysjkgkvaudjmvmzwrtqelrdenmffceewrhybxhbyavplaxlmnkrpeqvbnprbgyinvqlxmwbakgrsjbspzlakrdkgilsaoqqwcabwotljovaqsqtnzwrbnbonhmzldbnwtiudlhvgangnkdvqhpctvbvlqgavvnniwmahdaofsrlmqrxsiurilaspcrjpqkxhbztyzulmilbfmocgyodjipexiyqusnorqttpthbnovctbormmtnflouwcwldwqhllsegauwrxujnjqpgncsmvkjbcjyjfkbjwolnuvokiobagemannsbnwshmnuggvhqnqwfqnxrnaxuwjnoueikhizzdclvhmronuvqztszbuhzbcbqnoalfffoprcnopuydrxqpeakzgumbijcjyqdkrwqlbeurrhwpkbtdmzgsjnwkvubdvejirnsqywvynlccppndwlrtbtgtsrvcxtimdfrydadzurnwstcwryrwxhhtnwdzegwuqcpmuxwxbcygubywqyggxjcgohnhjmthzunfioetkovgustwluldrcbijibdlpvrttkfhzmefbvopcibwzeefvefmkgwypmvccpfijamrnqnjgraoyszthyzwckbgvlibkmlcjpurivqchhibsmszislylwvlwiixykomtxnbdqxqkbplyrzqmqcwhutwbkzljpufcgumrynhmxsaxvifgayvxjhwcucdbjciodfkxvuhwarvxjjuikuzajitiqxyomsuzjngeghworwolsfrddbyppbkeedkrebjioyvqcjbpfpgojquskkrylkmhwqgytuiyjdujkzanjziwwrlbhnshlqwjjcrwgyhqolcukoxfkkmgicaeglhkmpsuyceybgpcsnbtrvmklizvdcdekrctaepmuwffdxadyqddiwqknvhflvpxzpztvszhqxyzpubiyfabemgsbtbmcjanycijdkwjrkeqzswpoedkxoqdnzxbceqjlnpinaszuiboygntvjtzocxmlgpwvzublzkbohhhwhmnrxvscayiqsowblsccxyxafyhrqpbgggqvqdlzfkvcoqxdbywpxmxugpfgxyzzkgeysvtyyqtroipixgxquztqjekutrirkemltzyzatgwblhmbftuktdgleoiefawjmrswknmmqkrtukmeujkhayhokniknswubtpiqcrytwpzatgmfapnhylteckmcciwtngaihpbhmvbclqduztpcqykqbktugduzckyndupynddtbnottaobzjqokibgzveiymaywshferzuuegkpnoduzcbjhflixzdwcqstnyifztrrhtbmuzqwluficpmwlafbntkdaplsxrsbuovdeubmrjichkpmqmfaionzwnbzobnankjdavbmvvlsnrxxahfjunuoznpsmzlrcpygliczaszjfbntamujjmwbdkffgdtfoxhyamlrnzuclgglavycrpkxbilibkbdoddlxllwirlyvemfpioxzjrvawhazkioflosrtwkwbdjekjvygipladvaoohjbtjvsjmthrlsuudatwccwfnuqfdeurhmauzivtkhtrtbbtrlwrospubrlfuqkrofkeyyxjbnqqbxdyqnpfcszyxjchufchczrxhrjguysiqqqxsnngoxamhwmsxygcznimbeqbzwqpuusprnkklceytgiihccvjrctgejzhdezcotqyrvrfqexsbezwjlygojrrgefnonexayhzusqhqlegguvsmgwukoeepmogshcwzlmtudlxcrwkzvingpkekkgcuwkiskyjjcbyweyvnzkhnjjzuifuhzregfqnhdymahqycpkpgkxhrkhgzuooeayktkkiepfpeonkopghztlzeiqdiximhavpxizdywcpwsmpozfmdyrtkijjiovdqcjtvpysjgbyczqzdywujbdrsotjsmpqqjpalfepnusxlvwlhhqxezbasqafargllwmebgplzfhikxwpbvkpashhqcqfjxbdqbupzthutajkdgspkozgxzrwgesaurgbzmtqrxjtacjbooctsyuhlqmfvemcowrrbjmfplvopxohvkxbldxemaeoxidrpeulomvoncggooeenopgbiunehahmsimxvxytfgysvpylknijfxbwwwkkverzmcdvkcmxtvmdktzpriyffhenonngnlspgubsvvqxtaxlomlmcpfajjfmamrdivpuwlzgnhijccvkchbgcbmcdckvzdnqedpubvqnujvczzwjdlfbswemdhdvhkkqnahanngziguucgzlnqktizagfqzvwbtxkjhgqvssvuhhyrfxbdwzxzewyuxchlrgihuwajcxsiakgsvrsrqiqrlxqsduhrddujtculrdmicjhrnpgjraqgjaoouuoszvaydjkxiufpolxaywdabtnbgpjwjbpgqgbmhuircbxmigatvmewannvqzjdcfrrwwejduwygkmzwepfeqkrjaieehwozbkvrmnawxviktvmrecwyfmggjheehyukjxotpcncfpnlhxflvxadrwgqmqbbiggcxopagefcbmymbbbqhphnpxgkffneqhhsxunydatwamunhpcioixorgvolrsyhxrmbgbttbpkhxqjrvvdmprbwhrezizkzwstrnxscldnqxpoefxxemgqjdhgqtucdsnnzjjyozdjxpuizxouxjxcsrlteofyxciwouynqabmwjhueowmlrizylyjnsifpwctgjiybcrenqltlzjhwbevjxnkwyccplkdxvoyfqvqlncfciklnvpnpmhemcksywqhmufelynfwoztwwwrwmjittjcrtynhoseapcretcolwghsrrgxixgqctoaqmxtxiyithimiigqqgdrhbvzajpotiampfyzqbiddwhupkyylkqrqdvggfdztpdcumsbwrdfxnnqukiooqnooyfxbjegvzpkyyzqfnptdxqlvfxpbrieultmectzehklqpaswzzwaovmesvpniwqpdvheodaxizhkiypflookykizpqorajrfnlbgqfimmamscyucfoxcufpcuaxzheeeikdlewwrpunoarryxxkpmbishqbnhjdkqoewvvwaqcgyhgngjvmcfgrnjedihlpjnqtidhgtklfckcslfavgwhugpgygchqwdcdpjexwxyoyxdowgfozqcecjhnavgwhklgzzvolirqgfargmiksrmsngerazlklnxeojwqjelsqvbljfnkvypppaymmpoaumowtwvohccwbmppjvmtqeuyookepcgnljsnobuuzqmfwivjphmtlurelnobfxopqarfmmmyatufogeainqkngpqzrprxmdfzbytgmibsjzdzbqcpibmkqygopgxzgpmkfypppyjhlnfanvmkftzhksoyuoaybpeiwpeilgxbmeojalbklfobxnxigjuvdpxjwezehvdhenrnainrqjerkwualgtprocogzhixrmylmnzumbejqlrsebxqkzmordvvwtsizuddmvgxmhobdyhyuwablhsxuqgqznaxnrwgdiolndvuoihcublznfwbuvzmphxfhvfuhfngwnyhwyqsefucplrxjcbfbetommxqnuhylijkkjgqjipzurddsohxbrvaoyvxksseitjaodfkkrckyhagyhrliatvhrbruxlgsbcroqjthgickzcibrcstcbnqgdektgirmduqwniygynqofqeklcrtpyjxcaxkymzingvkqqljwthsukbhkttcuqwbfeqreljwedxqbtmkhphrgticrsmqblprvoixubusszumpxhrxpcapwumqbueceuekhyyekpjscibbndilzoabfttrqmvaytogkapysuhozzwcmvgeopuvmkggexflixvoyzpmcocllrhjkivfsbrqtfgjtkeckgiwlwhbpwfldgdbrxrsoxbjuqpfixokpruhdcqrgxtvtquqbrggethvlknkgvnyxrvopurgfzkxahvbaxtqsrbnfcpumeybxhdofomtnbjnpkuosznrixrytkqhawsefibvccwrbzzwcvdteovdvqqiqaglkfjysvfagsccrygehrvjpelluoaeyibpeyydkszpdcamxxeiqrkdlleyebazwrxzdjbsgebtfbjmtwpsrvhmkudsiabnieuimilgfxjvaruybiixkupnrbngkxmcejuoghckmayfkpljzfvgohsjsnztsdouhotugqbaasyczzhjzadpyvzxxrzpzhhdesyanxsrojvkrvemkmueuqkweaakhaxpanbswthmheduigyapnlskgzsgoxmspvzxgjsdyynxvoldaqvftegeqmggxgmrniecslppllxnecwdoqyehsiknwwbmrzaqsixlnsbbueltfapzhjuceurfwufjsqnuyvktldrfifpestrbbsfcrpaqhhbtezevgnexldfnwrlofwbsrmfbdbpgyadmbbfodpuxuzppafvscyyorvrfsebavocoaelwvajesedyawvrldbxlkhhwfeuinotnlwsbxwgghrlguauwqushduvjdaxvmydrpjvqjfzfpbdnuenzjesoqgiwelhjaniwsrmrtrzbxyogmjkktaezkkbwiwvqdczwbaadpjhyihcelpjecasbunrtnehkkulnbzvogjhjysmefidyidfqczobvojzmhjpfsdzxueskcypscalflpwuhjqbvjixcllkushxrwncuprrcqbetyclahesqcnfeumvvgooqxuglsqrxzttvimnxdimgukdzjyppjotriknpszbgnvpjawbqllaitttbewhlyuheajpuordsuyvekatgnghgzsxnjlkfiydpcldjrbipksfowifkojaelugsweazsvceadcllrtllpnmsittxvygylabeoonsdfsxtyrmdfsaqzqoxklfwdjzriqefvcgsbgyqertseqzuihcnykbnsdaupgbexadfcaovexeovkckgwnucdpdnsqwrnofrzbqewkexgtvadqblkfhwplpdyryopdaoqciclmcbzryqjwzuebsbhqfeqdbbkrapeesxdztfvvfkksmwevacmcpfggnhkbzfawjezhbadqfcrenltihqrmvdzjofemesrtorpitdocbsaxpjflflbywpoxghsmkkmxbjluzgramnizpszhpmfdjrjrevxrshewliuwleoelayleiftrcrapzphbggttzsvbsljkaolagjljnpjahbppqkixuvhfytmjdwoymcmyukkvtctyqaklilfjmcwmvfzsloallufwyckkpvsrnrssjsudibigzuhjquilalplzlslxlpatifcmjjxpoukcbkruxzqcybqtjwacermobdxliekxrdgbuuoqadcqfqiaprdejvkjcclinabqecrekbymedbhxylobihqemyawbekbrucjnvaocxlginmidltddgudndxvomsxjeobicvdvsxcvzqqofirtdncjqydulsebtvkkfiiboueddvxidaxzzrupgaegurxiuylhkjsmwwmexloxqhwejojshwfuenqumgotlgruptyfhnsegxyxalmrjenrtwhkcddaoxfcdhlrxehyifvmrrllqmrdbkvcxergawjchglwlzoxisyqsetlykzzsgnxkjfurcnpvgbgzkgvjsvpgmsiomvoypzffcbgkmzijgcavuirfhgfqcmbbnhlkutsgcywetdgmuwjtdcqqnjyxrzrlykopiopejxauimhwaulkxjtjdsedpjdzqcmxmhcvgahyocdzppbyhcsgzztfteaekmzljkypjyeweioumfckvsiuqqefgfvtzythdqzaggsyioibwiutgzsrjxaaocznlewcrfuqzwpqtajezpwbwrezaoyhfphwixjbfkcvnnbzrwtgimxrytsoxnzoxblzyfkhakprmbhioyrprckaemvphxmybdrgtcditwpiphepvvkozrixxbtjsdkgfndfvsqjmqbthzvpyifvewizgavfpauisuuvpvhxziocdxjkdlvawwwfjogzwopqguiyeopyqhzfxokhdmnpjzwmiexquishnryakvcncscvrsadrkhcowqnotuetinigjepnxzqxpnwdaxoplyakpfmianmodugetgwotseltrxmmrakocogpcswvhelaqhylggbslxsqarrlscjuraepwdipjqqjbfkubmdvhkeggktnlavnqcxyxobsrrnpkbvqebdlfacrpihbzloaaqsciuuwarwlqgwokdichlaihapllrfjndameviasttbrmialahtokescfssqmibdczkhlqqnzxyrsennzsdbtpstxaxhvcqwvkjjycfrecptumtuggwskhqmcvbuczveajsodidhsecodazxzzuyrqmvqsfgtlkzjprrmbydkreclkpgtxwmmozezygzbtxczleichzrtaoutrzzvnhweyykqspphdngvxgufoeskmsfteemnceezumbesbmrjmxfuruqbslnxbhclmtfbfuzjiitlaxsaforulocmizqktyflwspvauzosutexikupivurhnaghmvwpnbwmydbuiivkrzsifbhytsabpbaoiwvdonofbslbmsbzmffwkvxmaaviqsipazyxauyqpqibpajdzcxcyzlguvosdwdmxnaehwgyksiyhfmoufrqonwdknafqyjirtfmacdelqpzsulnlfipgtrxxiktkxumosnaucawfocxqhlugrzngjliqctawaankkikfqnwiqjcdmsxaebjgsiaebaikxqvurmifufffpxzgkqoyfnspjjqtfbfkxbzdqbuihepingurwzkejptppvhjdomfvyxrvsyhnuqaejmltsqoilrescxxwdiulynzupxmamngmvcbpksexzcxauyphxiprgfnkzwuwaihxxnwhvnopdxybmbnyicdmczhebreuspyrvdkmdspqbnnbfaivtgdsmjqdiohhcqrudtzrjnxaxvdurwwgquhsfepjkiqtbwcjefvdvditebvgxrxwgafrkiteyfvqxuwmzsojzrooeqtdxqvnqntfcbqjpuowxvodxggakzeilcappblbwjbghqtitydivfindmqlwdgkqawwriyydptrdbhmkpwwcndjduzjduoqnwtjbmsopzheqoilstzwoofmmprnhiusqlogfhwokwvpuegpxiyztjhjgstrsmwvtwjmnjcrejhxuyhbqvikvrbkcyozpjfzfcyjwrzfdmjijzykprmzmjieymhwsclyoeinnzcgtbbqnxwgpwcqojukholmsjniwcmhdcsuh"; + String t = "rmhdxtymfgxjluxmeeerhxrrtjgecmyfdhevakyosvvuwgbwmxiakbmtqjjpgctjojdqatuelqmfeldgoprxbzcylajhhjngqlmporofjpoyhrkptrbpzvvnkrqjovfzmmqybqxzjxarhguqcyvlugwmnzwtffanzuajraqbvjflgalgcwuhmrkblobybwouffzptbvkmwoklczfhvkqsirkqvhkryyxpkyfnwnjudvllmznupldkpoplwdlfzncwxdlgvgkehpcudqybnyhofpjnjmahnsrntxjtgocwsrnukejehwzxdetglgahdvzyypdztqwbnfrnytxprhtqjgobzjyewuasgnryjoyvwhdmemppixqcowgmicbmsukgodwgnsdieuqyzuysedmsphmritlqtnvnvfnmgnghxdsmmnzdhdalhfsfsppupteyrlajxrlbyqteaytgpsckottqnibbxhmkwuqfftwvibzsnaumsbohxeoaulsmwuvjcimscyqhtioekembdwfozglussscbzejqnvmcpfwdmxshhrkquacplctruyklkxcfovcbqllmyghdbkhdmawpmalrsgymgmbleftwtvldxkqprcbcbneyyluoyydtcvkimqjoinwntfxfbwqjbufqansdlgrgauzfwxpzrjxpesmozcsczbfzfeziedqzwywtxhyfnpbxfgbqcsfwdiplegcsrseqsagvkpjrupkaxffrddebpntocmkbarvdrhvujedwnktsdimzcbqlqyizozxcexqpoefjpznegsrtbfanqdyqaaudcklplvxojfuzccmtauaxurbwbexulqbxooadcrlxbtggxcycadratsuqavwwkdqtutptdpbnxeicmackhyvjhkfbayjmymjwejybhoryyqjjmwqzhpgulovxaccychffcplvkqfqghmgmdsigkugsevwkvzgpxiolhtzocdiphokfitggpneuisgnxismbhrturqralohcbzcrrwxwintbenpbmkkzuhacttpgobfpiycfgkrpawsdheixoyazmwcnrvslspeievjzzqjifxkkvqmswtozweouodkvvdijuibcdnwpgfsugufjocuutawdpgxaryazzefbapyzlbjbpltnndtxzmwqfrbjqldaetuqbufutefenwanqvtveoxffhfurgjgreebqudhrqtxjmqsmjrjpcpyuhwwotjjdjldtyluisvzyllfqglhrjmyaiqvbmrswhbjvssqmlgsgnymblqvthtgarrciidbuyfwfejvbsvfvpizxmonqjghpiiysiekykfnucfacmlgfidflwndywfdjaeupaspmnjlobxjutcughhmqeklbzfmzpsfplncuefmdbqttxwfcbglxmcgwwfjfzclhtwdjirwvhnuuvdtcrcwiuxqxwqxwzuvmcqzuehcmevljsedcyssmhipkclkcxnkbiwfghfstsklslgcqwbcklghfywhhwybtasdwivrbskykplcuscytwautoypyuhzdjvgmxazzdqdsudqkkhpbdbsmkdorurhqttaofphrxkxosqyflaztktmflfurcawfgagoazkuiaziflwvjzdmjkglvvloctyqccamerkqiblezlypityarvywunzzbpzyzhitbdlsnntjcuraevcdshfbsdlzkigzxyysppucvpzzjmahzokyidlandntkagdjgvpgtcoftsyilnltiylwpnjhhmppzsqrzkabgnkqaissrnuhjfztvzqklioszdtaeogwbadxqrqhnaxywkamgdsnyipgnfbndxjwninzjqhdhtgrmqtmebrfrhsrvyezvsqdecqgkilwjaaklzgxzkwlwmwailmdbtsavsweehjkelgsnqxbbvehggiceankladdexheozlbmagupxisghwwnngbqpzhwudmogcitlvqfyqvniwsdyodbuuihsfoitkaphcwphkqxtspkjqnobsixcvuzriuxgzmtvaziqvwmbupaiwothuajjbgasdqwjvzelledjffvwpkjtkwhiwfumpxsrdxvjfzcppiddfdvnhunbeucpmpzqqjzdaugzxclvrodndbuuoblavjdncmrfmsdbuuytxsdnuaaiaedutmtjmcbsonqgpiyjmrjvbmhkzigrcpahqefktkyxkirgiytjwagdevjoailxdjnvlhkjapcyydpyynmufkrzkpfykkvunukqrdckuzxjnskhkmbvofszgcpzebnautcydxpbafgtpmnmfpgoyppqybbnfybakojiudsqmoneygrxiwzilatiqimgpuujmmmbelznwwkeywenzgkckqckifvzwfifrsxinwdxlebqnlwtuqmaunfjdqvqcibdogridamuettagqxhyhiqwcwnbvmtqqpebychgdlhyggkrhtjsvtryqxuwmgjaxajfiozhzrmcxyushslxdzlzjoiehascrtxjijslophtjfczqbwpkwbslrqqtnsnjglxspmdltxfhvwxljxemljqhxzkpzjshcqedhoalsuksdhhqzhbnlgxyepkcsrjvxgymwrnwdrvawdorrkimrsgllgxpvuouwvxwdrisecgmprzhdlacndcpfxsfkvzkvfbziwlzkxtbooexhhecszskrsoqvdotizkrjkfcytdpbdegirbsagauwdpsvahyykxgbvbxutuaclwqxrtkfnotzfebagdrkynjxndyntxedirsoespcfusjzjordgpjrbuptkwncxlwrnjxfxgqyxshjzljmfvtgzwhnbhxpewwjkrrmaijvtngstvviaxkunlrbbncqonjjrduhrxenozpfvwjjhzlevbubdhxbqjzzyeryxpwogfcthkikpsrahyzdyjuzajsvzmnffqcsnuqjdhwzvksyzrcbcayztziniebutntekmqpyixujegjrtnywhtmqjjsoipswtzbyponaxkmsttbuvnbkpawhibworxhokkhppooefzuzpuihpaknwwtpkepnzayjhnmdrqxwensgafsxxigegzpyislihybmhbelimrvnxjjqgtxcnhtgwbxswupuhhmqrspimisylzhwqkakzdencxxamajpxhljgdifobhnydycpbasizikawdysxboemhakqusacipbrqzjuhxctkaklogmnwxjmamfzwkczkdugibcegxjkfipfjvrxwlutrjhummrvcgprutsqvyryzswpnwdgcvivbzexwegoyakvcixpgxvcoxskqjcwqdvrivzixxpvaswhgleiomfalaehbxcjzafgikwulmnikpnzxgubtwwwodpsorfypavcufrjdyolwmpexxtmwpdrbfdsowlspuyjcahnvriojstmpmxtcjochosbsczydfdlqeiuvtzmbksyibgfkvogcldlpuznynyerocfjylfyndsycpepfjtfptbunpckdpvctnyuhvofvgqiebiouvhpxnwamtoccpyqxspqlxhxpbwbeiuvhlhdcbfzqifhnboberwevfngquhfgvfdwszetricznkxayhjkznoaaanyqhnnrpcpsmmsvvesqkdoqhdprjhhcduwzlnjznckszkmcwwlpiayptiahsgqahwddlsfcypvbazucknrdbqflmcmgdulaqfyklwmadukhpjlkhivhcpjutvacflpcjtlziwpocgachctkkaaqvxxduytntqceygohpwknstvpkiwggqjmmkofjvucfkaszrtrfqwuwjrzadpmwifpdixrwuaoqjincjumftfnqftthgqtobtgjccrlsauyaviettrmsorlgrdbbtwuohaetqcgmjbjlbmlwejxmfhfhcwhghifrhjphpkechdkjbiulinkcakgqnpdrorjqaubhcmxhwzwmqrpzkvuvowkhxiouypouekykfyskgcawcmalyxguuoavwyzumcnwkwposddunwkpkldkvymtolnfdkzjbuoxezyypuwxuowamrmlzqifxvibtkkjqhfkpyezvogcsznbgtwhzsozymowcthnqniymeulcjfehbxhqweqozylgdzztyinzntkvvfqjaslwvninkoxuczcngichlnfdbgualrjmtdboclnkmxssrdpprmeyoqmfimjgoyjsnmnkweynbzmbzsgmzkflcftqxdiskfdlmfrjcgmatuvdpeawzutdluwbylzepneuauoffakzzkxapugrjawdnzlltnbyikliifbmpwpbvnvyyvroimzarulvbqwxfswhhkbbrvianztvmaiumlpvxkwxoolkflharnogpqclcyjuwwnzfcabeirwvglnhroaltgzfyctaeblyiigouxebnvuswdsgxkamczffnpjwtbrgdobwduqgmkgwynzqxduoatvfmszdrmekijaytineirrguplfeqyxyxwievbekqkysqzqalqwdqncjciuclipbujhrutlhtfdbcsnblzeituszcgvxqdtmetjnhagoasvdcdpiqcianqnrapigkbkjbafhnzsihihtjnexftvrppzpcedakoavzfedrjahaztkgivmyfknyuvrvdqbvcefjkvosiepopxsafnxrtqqfrnliigeqltwnqovhlmekwdavprxevhxyrrxnijrydlhfpmlrkinvxjodckoqorhlddhquxdjelepeuskfbcgtwbneclpwfnvyblavcteremndsejgdakjvypbwrmvcndirgyzncplinjttqdjhrriuxrzmiccjzqzadqaabwhnadrixtqtexvwpygkzqopskjbcfaexegghzwkkbvfpzdjqcyozugebmrvbwvbcqltijctkwyxhpdgibhdwyoesqyepjrjgejwbwrrfhzaglatzucbliymlsoamftvownliceiisachhaqzmhkgisyjmwyqzumvxqpwqkliuubcvjiesevhhzgodfsdxtuggdeowwgvdygwpuomuetreypumbnqwmfaewvegttqraprrcokmtcjkclqafpxtqunvxnbokbsimjwteboryznxmnlitkhzppnsmswzdkgzaoepusloiyqllxckgaxnhpdpkejgcbuckgfhzzeyvtwosnnxsdupcwuzuopuvoslkzutcbseeevdkzltdxhwbvtvykbstnuinpijxjatdrsgbhpitkmdtzoatgmearrmetmjiuklffydaqtubdtbdfgswoqcscbylrsqluxguppkwmzurdjboujljynafrrczeyfnucikzlyrbnboeougivvvriceqdazgimjnduvrtbtbcqbesdpyjerkzkfqwebjcmabkpxlgzkfwnogdpwunlprqwbwswekplgdcqeovezxwkrdsmovdrimcfcfmfbowfnaxchbaponjvfzflshpnghvntazaxgidmdsfjyuaslgnhjsrwuejxqndgtdadhijjkeeleruoqyhbjdajmzozxrysecvttmzsocdtyearsxpusxvdrppbkzrfvxewgwfejuhrnnldaghligaeraaoaqxgswitykslvvcyygpftpzrqkctpwbxeybbbugkguertfioidzjxmktqemcbxotjbpxonblvkrjwvqblrburvzqafrzxhfonlxwjgxrpbqssombbggiqcvxxpqbipyxkscuzgubvqdqndlfauzptnywkqhonmxvmrvkubhxuvcksktvhccrcsirwmpwfbwqcizmviklfmtpyqjqnrfyftpzjbnffbczwiamexobauwqcvgcqpnnvwoxrisnaqqdcoawcgmkdgypipihgaifzkhibxinsiiphpksfogtssbzxchsvghelajgmsquljlsdqlimbfxaznbcoluruqpgemljppozgtgdcynydecclaxnaxgxftbftarkrkmdmuzndfnuwwkppyzekywrecpmlgztfekuypskkmehpgylqmmjroiqhbcbxbiusybwtrllfanyjamlkcpyvdkdxrtwykcqhkfqpziyfgboosmmvmmbbtygikpkfzbvqodhgguqfnmhzjadcjlzxtkzqxjbinznnffmfijkjuxuvcodkxgocjpqfikwpnryanpnqjqcqeuqzlhrahxmvbhdczmicfxbqzyculceyzyqgzejsicueipmyocblyhagmvmhfnjicbdedsuorpifxrivukwatimhcgnbgtgkjnebgcuhuizbxvxsmuwhxhgjdsorltqrphyhyjhpsehkmrehhozuoqdairhaprwgtrtjsmtpzhnbozjjmsuurthjmdbprrjushthmwprrvqowgmloflfkjldsnuzayoegvjrnlrrkcgavwujiujrxnzhacdiuzecsefvuldzvxppnnhtgwupzlbjurijigieonsdvssxehiyobdblawllvuudtckupnljtlnpvnamncbrsdjsdyateelkyqezwxuehusieyecjchhgyniyjsdxdhrtpcaqpqkdcevhwvprekjgzreilzfhwwlzdivwljfbcxatczrprwkgchtacyfdyftamwnyqrsgkijxxuwscaknouokwfydbfoyehpyjbqvupfzlemixqsjcvcwudwkudtqihnpfabenfosxzorbbkedmwmnicrgvlhmtrzkrvtgyqkowqhohssgctwiisndvzuiovgsdizrbroweiycjefhnykanfgdxzgxeydsbmrpxgqfccgzpxhnllszdiuuqfpcfjfbbjhqycpsomusqaeouolqnchxqsibrgezayhumgmwtxwtfmombszhitbdmqlqkgkzgumtmxpsxqopectbtiqxcdqfnwkwgaokycpwlrbicvzofvupbhvwyrgspjvilmfkdpbajljqywsgxexulrnmtvvuvdjqmkgszopdbepwgusltasocutfgxnrzgdgozluayontlmiasixsrivwzafeeobtmnlispmnamfsubdcygoaznetrljdtvjlsjhhbehnkgomfkaibackxcogtswoepbxavdbakkgsiugbgxgcqwfkutsxsjdnineeyzvaxtvkvtoradspefqmccwylvizdaslvqodovuiitbueennkekucajubpyyvlnghwskuvmvgicluiuytlzqtqklzllevtzftsiohvyvjcfbgpwgojwuaexgmppkongbxlytbrojcaltbvwugrbentmybfhhxmqtaqhrqdtwgqxfmqvficcolzsvpxkzvsodtyxdhklckfpdjfihhgvvgaqggwstgyrdlkotlloywrzckqjggkskdkziopvrqxptnwzlflvqdsttvwqexfdmubdzdkdviogqxujhouvofttvtjxclkukrcqkqdqiymmtzswawmavrzmvwrfwjmqzqktazxlcrvsdmesnkjpxuavxxrmelkeymfovtatwwjjvhblflyeurvvexcttewueagqqisoyybtvbpawfzfmvivjxqxahfwwhgbxltofjmqaujkiwdcmgpdjxopnarqazzypfuwifznioquwevuqhsfdysdvcfzitrplrwkitntievjuqscxzqnrfdpuynbslssiqpxytcmyemmrtksusqarunqscretfxglpofwpunoelbhuosmqrabbrinrhborayuarnmeqfemwsyibxhpugpgbrgmumazhwqgilexzyrbphjyayymsknpgylqqiqbxjwecnzyqufzgtkupordaodvyhnvswafrkqzraennpncpmqhgmkqibdeawmqbfyogzznpepdgjwmkrdqowbinhtpdjrzskdfqtbxhdhhiizginwapnxzlbpmgowsllzspkyycgvulouerkurlxjxvvwslokdddbnygrstmeqmkgmshiqcxkrawtrlalzbjfhaerdegowzszasesonibmezsnqabusjvfppbeotrvadlxyxkwzzggyqqzcopsigjyobvfssuqrypaskxaumonsercadglnzrebxlimkxjnmegflynombmnegttnhsanaodfwimsecolkfdjxqhjirornevptuvoywadeufqgibasgwdflobuhvwgfhuiebwtwrkhudzcqukiimgczjkghqjcioixtqmcyiialwzlpafgzcdvtiftpwtzenkrurewgnqidwqlbwcjtdnhwzltevylgewtobvczhmxrsdfqbgitdxrjhxxorqczkijdainknkxqnbtgqdlhkdsrqomxhfzhctjkxiuxtxemvpqrybmljblkvtbzepwztjepeyighypemygpcjjiallyqltbdxgfglaeeimgnvncvjohfchqnawzcwtuvemdqzaesjxgwdrmhjjvxqqpzenybmmattkrvimbiteyosogssogtpvnneqdyoilsysokthmddoqgcaqudccrrrayaowmbzcrgoxskcsnxnzbinuwonimtjvyzytxcozikxcidqgceryipaekgxgfwwcggyujgnbzmesczwnxtechftprfvtvwnkydmmftbrakezucpxmtkvpazxtdwosyfeizefidlusthfbybtjoppurenzakgemuggcazibgnbgnvnmkqcivbvkmhytudiwvsrltbahxdgqonqgyoiiwhfohrsrgkwypdyttrvvlzrmrdridqsfdscfwdiwniuslridoxjrrgcgrvnujhwlrqbamgundxwbubnznwtjqcrfbwpusivthzudqmvpfchuvgmmmnhurkvjkefbapqcrbpsaaubqpeyrgzbrabfedjrwbumwhxjizbsiwthsadpbemtnlzdjfnbcwwkzsxfrvuwdubkkgpdsqpkexuvflmusivpuiyqydudqnhfjslmqpynglthhiytkdscinhaekbmmukbtdcicmsatlftlfhdsmngvhabgzqxvsxinsoupolkmrmyivetmltefxyozdzjwweybqsutayylzqhzqcojnogfwfcfrgnsyjzprtqyqjjhynaivenhygjybjkdyrycqdxbbkkeoqiaoaebsyprzpxobgctqcjomxxmrsmbxzzrjsgpismmajpjggsmhzxjiozemzyqerpywyjbfmxydhnjgmklogksldsbsfrtztybyqrvwnjnovznrzwxufvkiffncrlnmbllmtsxuxknccxidhndhwmbydrsmtolkqtkqesukxtxqvhyqqyyvuhfznfqpuwygsqovxhackffjmjtoapfxpnppanejtugbghtusqhuhekdsyjvcudabcbfuporcyyyarleopljowfxdindbhjhesizxswgehytqvhnafobegwjpesavmyxdsufqyvowdxfohlhgcecowbzywoorkffesutefuslyghlceiejwgcwukuzgrgmydaspzzexsvnuoscbrfugdwtiixpocgkgtogibeangfyiftlgdenzmqxxmpxgdgiugxcemuebjgfftlwxjzdzakivliazhtyjdqrqxylwwtrwpzavqnsfpiilnrugglvrdtyocjmobznpcojwiqjsgvekwnwygcmpngffkrsbvldmpckqxnszowknnddsbjtcahqhnnxqcimpetmhfyfvrxrlmozttybtdrfbsptbfuscdtdlviudojqxxgecbrxzclwzwpcymhhkamvupqxpmaypjffvszuehakduweeuqbepgthsqawxuikullrnbeieummxhwecilovanpebdqzxyvxpwlxaztcbosiqzldkveqyhyhrmizyxdbgshvoglmhjekiuvzxcftgtqhanypdrhjbmcjiybkytzwvvsrhiypjdhgjnxbnarrxunhibnrbzykvbfluyzdwjzphlyhywqrpgblzcircsrsewwsblkwjcfwttsowgayjfxsfbieqibsqgywlynfivnkngapobcdneasxlozniobpsuzrnvzidgnelxtiatntebbwmbbpskbixnujguntppkpgguivitygpbwrdoiuplkfifqudghwnyvsvyufmuklrrxtiyvlwzbgkujcazdnjxxdlazxgkapxzwmlsqtlnfypxqgjldwsnhldwyehlhxccabatmtcxjhnpukwcptewcwbdtptwwmzvzeowrrnvuakvnllyqdpllvojcjcollvpdthhhzfrbtrgdcfxekxgkodacaohhigcbvjoqdxjklbvumxjqkfzvifygbmojmgzxlsrwyucfhscgbbrycixitmrgraaydfajhtixjcuoaxqmzbvceogjvyawzmiighfdqietynzdokyfndnpyjhpjgrnpuycxqietkwgqisskwtgauzgsuffwdbclwrnyiemijtelfldfdzqundjdaqfwfspxxdjhwxxatkdzmcaqbspxmmhqwibsszniiqafcgwgqpcpzvuinbkjewnnfwpjmrxtciztyrtfxmdrsvfhmhwvpapvzbccmzgkfmcjsicrttxagnsatkvuvmkdiytckrquimamjqpabcwslrvzwfjfuanjutivjuztoxbksgwcfznmtohvdsisbwjtsqrjcuzacwzzkpcpojimxzeujpfffxkskdytqwxsfhxrlnljbqrnqltyvyfnrwmjosrprxzoakafrvwoejxpsvvlnmuranugrdxocvgdemrxalkmjcfzxxkljazmlpgfayyqmvdbdzjmdkddtcivfsolmrorslrrrjgjhnqpkzpmuritulinrtefwelzbhjyevzybokvozcyhuategnkhyogxtsevqqadhfafyklpulvvsursdagemjhqfmwpbbyqugfltlztbxggrsmtpuyjuhjgimjqprjvfyvhrqduwacpygprzitwsxbneqecjtzgqvxjfbdwpclzoidpqwpbskquoczvxgcxzkopdazbwbuwnimnvmqtgifpxxmzyalgkjjfkzmpvxmodijsfsrmtrphdoiaqmaozsfshpfvaadlunwmjsgbhqfzbvnonhojuokltmxzfysqdzfinvbtzmkenvdxdxlaldlbvsjnkhtxqygpbsaghlnbwpvvmowebrimqqxywlycuwxsrlhdxsvhkhclzkheqrbpfhgewcedkutywwvpxcppcupzoyaxblrcnkxnpvhbibftszvdxvmwdbvcdchkldjyslzgcgmubocyvmymlpvqkfstejrkbcpdfbuzpewzkshremlhihcxrggaaftrmghlvrselcqhommtmmwyvjzrsniigylfcrxdriselhrbbmulbrioywbiyfsctnxnpwwinwokjgldfihugpnsljaqzegloixsgdhozhvptzkbsdyzrvbwdxlkalxijflnbzwzjvpmnakraryhmikwnewzpuuhewtzxbkhygjidtyaxfrypedgiqhxfqpzbcgzopwkzmxkdcfyribjevbnarkepkbgptvinvfesbxipizzjjwcdfklqijrwtxnqgszshpbmztghuqawoiemzumzhygxfxdahtkcglaemvjezekjguyjijdmolbimwsitookpqdwmpdqljrdgnzbnxyfxeqqmghxpfvgmkbqttwgndazwcmmsekvpzlrtugogyqzlqggcwrfymvakoecdepfidhjyaegpqvpejzjrhgtebycbqhekqxkrjatuenjpabmygxyghmnyhovlkgydatgabysxkqjklpopyfwaiismogacwcfxlevbgoqlertugrckfciyesmdfowhrrorcygptsejbmvbyxwtuknumcoytyxrngrsbynstxrnlxugnxrkbkngwxyvwblouguhghmxavqidzvylduzsipnwzsychyziafcwshgpuijdktnnvbiifskooqwwvpejmrdrhlmrurxhcsdfgpkkiyxdpslpecaktbyfgrhjzspxpgtfoowqavofpdvfxcovxfenecvqvbmazmvzbstjqcjhkysrtehgbvwohpuivercjwaersguqsuwegxacxjxvgnizpthzqzvxjyjtahaugostubcslxdfdrvsyxgenfdlqfpmodhckazrochijnypuucluhvxbvgohljimmnqurmudhpwrybfdhupvcagnbyqerbjmzfwaqmtmxnxuihpvyleyomcljzmwasimotkjtitpyvycpddtkytbxzavslcqdileabbtwjnkcctxssvugjfywxqgcaussqsmftgghrkdrcopforcnaybrrrczymogkklfsdlowpgtlolbinlqpaonlcwngoiucipgcabeixhpcpopxkxbbiuuxwtnfsoizdusbjvcqipnhqefofcgnmjzsxtnwyfivnvebebmzcqhkjqipghfzlbzlcvlpqiawpuzvicsibfidzannpgzxvytvpgewqxafarrjeezcscvbskltogndninthywxescdzfznbgnvwolsvspmudjohifaaatnwgyusuephffzvkwuaxwasgxqrwcsurhubszmxicfeeebvfwikvnstoruodwhhcpsprimurozcnswnzuemjabeafmvbdldsrbunecoaaphwvwlkaghabtioyuqyqtewuasmyphrlgzmuaqyvnrhxjbiealqkfnzuhgrqygnoqivsctrtmafilwnkgcdhxcvglaoscjrendrvnjkoiooingwlfelnqczhffmywmpqmoporltjadptbqzwqkbscvdhlasjnwfpjrlmjbrzegmriaclbwwckkspwzxnznnyfqwgypbrggkgbsjtxhjlilrzpkzkipgmsesgkrykyzpwatwslecveecqbhvzmmkdvwxlywtopjadenbmskoqnvlulwefueojbonjhczbzaveypnidrzqoqecgwbxseakclxlwrgxqxetjeyhgesindjvmkagnjunyugjblmclgtmuubvutbxctpoakthquvcyxahectiiupsgwfvfocflkvwzmbyqezjxfylwxlxjsrwgopqyjsknjugyrpoxnzqpkzkugexlicqksyagrfheinwpugbojioofyefrcbyklgupiejlrrmgglhwrbvilwekppjpabzdefjmmwivxahpfwlnrzvxhnwbwxwmowcocvrygdrxmhcedzkazdtllrllwigjpfxqkgoenfcppsggzcytqonjukvwnxzhykpoflwynqtoswumkiahsivdklcqldajzmkmftvplfsetjonculbvvautjibxgjvdjbnthzbjpfwanyrndplwbzvhaeandnzcthwminzainnzplighapxtayxjnclkjvzuorotdahlgknoukomdwgygzlojyabtfrsngrgttdxhwocpswwwiyamyecxecpyjwajhoxypymycpzgrozjlitromizozwwtmivylowpmewizxrgqhaptvuydkkamodclnupaykigsdfszsuycqtwpghjaozxnodrundzypfkgfgsfrofkcrjralbqooiwmyonkxfwmstdfoohfazccpspjjotvoycdnoahqnmldwlludxzhjwnshzeyyrvuamgrctyheukcejyeuvccvtelhqplbsqyfiovarzaergtrjzbzukjzymbuosparvrihjqlmupsylgxsfukscxkrkudbjjkjckwwkppvkqzdkckgopqjtqxxfkquagxtuuhmmxmbbpvchtutaoflrrtpwfbprmmfatnfmoonoasotajrysyedukuqchqczzzqdphwxlvwqseiauugbqdgaclwbcygwawewuvdibciygdfccjtolbaqamygsqrotexgwdxgsysnzqvysnwixzyqveiriotuycehrhdwdzyrwkxlooceiizeukvmbihnsprurtlvjbouaasxunnufkmttnpdrjgromvtpegihtpveetycimaykmerezuogddrrziqgvxjorcfxuxrqiivedvgmarhtamucshhyxjhrfbtgerqapkfdebgorpgqpfgbkyeorcrhtknsehjngbfntztsjxuiosflkwglubrqezmvpvvkyhjyuwrnzcwdvnqczaeyofyxlqkpfqfskkzemplzslgfonsqcuwmsnjdxxqtzdzmmshytznodgyqfpcnuweejbiugbicivwlzawhuwgckoexoktvzweryjhujhxbrmxlgixvfjncrzybubupjuutqevqvesmbmevrmzmoihxxaqxbcxendilwehveefhqhggxqpnildakrqcomqjadksbbwkijfminrzvjogkowzdipdbumrpfoibhegmvjuvxvtcfvqurupnantubsukotuexidflmzzfwmsdyhzaepnsjjaellxzlposdsvppwswcofjbttepqfafuhnkfrzyitoitsloimdnbnirrgrzkyhwvqqejrdshqojapuixkbregbbjzvzhyjxanxjuemztouplldrvbkqarikjayiinfbtwmnfqiyjhzgolhnfjlrukluobwwbpszlbztbrpcwpmihzapahnchpcfmeqihtncldhtrbhvwlvlqmtjletasjhkuzmmwswuynpstmpfbpvpefdgmyackplzmweswhwzhklkktdyuzfftvphilejnhsfwsnaofhdxruuxoasnqighdowszogeckarkyhtoowphvfthmqjktmylaqnnkxdczzbrlbzujlwcdsxlymxbfpcoemfaenwecmmrmgbcipnkzhodkwjfsamxjzdcbeqosyafpcswmzbdqqgbgqpbwjmxakgkjfyxfvpehjshemyxaaayrmeiydwkjidzehzvaycygntmfyvhrxlvwmzhptiyrpuhtyfvmdlfekvlzoypwfxkjldxjjneoslwaogscgbhhxsywmanpcczfialbjjqtaohmgclkanzwlxzbaqkklrvfcdwmspzbybogogmrxvhqharmpfmhoutakcqurayjtgmbgdhaxkizaqdbltvcrkulngmlebrcsrspbrajhmwfieijpmgiwuhqncekijhdhoqkmnuejizeurkekortxiwcxolthitpbskxshajotjqdyumfhbmxeufbxcvcpfzhumudfaipxvlnimeinutendaqmwwfgkzcsikpicjhbrlpfuezgvtrujjvyeileswyoobmvwrjjzzzygkrqwnsadnjqdsxjbhnwxlvnopnjjsjlqijgottxnvrxakpgktbozsaslcnpsxieqybildajhvkjfghxrgozeftvtdlwfaqsdcyrdaltyejgwevrjzggdncsgcnmfccxwjindrsvtyagwndnuivyyocwgqdonbiepnjabwkdqxtciigvsarlehxqzabbgroneuqecfxlpcksomsjlvjursmhjuhsmviwerinkwdqnbfvvlyhvoprmrwqkmmhaecfrpwikjkyvtbqecmqiqcouxailrwnqixmvzrwnjbrsrrvdbhqkaelyunnxxgsswggybzpiekrdsalgdosabyqnvbpgxkikkfeowctbkrqasuayzjhzuteixemhdtvzufrswiqmgyveannkogzkjnkonuiffzrrufposlvugwbriacpaowgsbpwkooezclihbospnqkjylhxoneinzflmzvdnriotqomadezuymaslufygeqjunwfmkimmsxrsmfouirmwsvorrrjaazthnkpkqbsfgdlbkggpytbmdsvjlobmqgffoyhrjmfjoagszelrdfxuzpexxamwbqukzwlztdmiqtlizrkefmjerwebbosiwghzsxtnwianyvmmbvsgjoyfqffjnzbdargsjytfoqyamalclqzmcbzsqbhdgqixveexmuvvzygkdzatdzmbgqqbjjwabildloeldmyljorzfevadbpexntpaoxdfwbpfjpgndwgecuvhurvemsjlkbhrnabpuotuqmthnhsrlrzvgyohdpytaeyhwhlpshevrrnmrsgfrjxcwwiiqdiqzyxyjnleyubmvfqgfixvdecpmnbbkxanslzxgiyzhtewbibpcaslbcdkflpunhhcksglbllusypiyhpftrymhatmvsritmzdslmpcsdubjvgxbnoymuwtlqglchfrjuxmosjmdriwyoatorpdgdvefbevmejkxolveddzieqmbonxjnlgwnjcobfhficrpbxpixaqwyztydofqylexfovzsycmqhhbpzhwqyjpcjddibfmiimfunxyrdlxwgaomkwmifvurvqkxmickurdzbhmqorzszojlwctslrzwsnpuubhrorbxwylxrebpsvjlfnizbhztofdoojriapbvlsbahkszkmzllyektxledvyltscfuszaaakivuhzuqepjgtteplhnmrtyzlmynqrhddxxnukiunlzgeojmzpenpmhrxfcygznkmnpeaoqonfomsikfleqrzewatdaqnkndrhynuizdkdfopncoqpuauzyaqwkqtvsvxszghofzzexbqmaldlpqsqymqtuwptqcgfrabplhsbxcorhkhabswnqlmsibtnemsfmdqbwrkyszzignswgwpmghmfylkuiqnebbrldpljbihdcwhvokeeotznfckuhocayxkxyyxeinzkelihuaztrseczjqnmvoicoyufrkelyxhurvpwwqluofrstuscirfppnlrodknjmoekgoitawbebrabnlgxyqktbavlbvgeswjgnrctrbzekgibrzejmizoahwzaufsxibaqjhxoynmkbygbeyoeamusxqapjhqlwnwmnoeueroqfigfsgszbbtoaqyrcjkjstzopgvxwpparlebknbewomshojgxxlubmdebsqrsrkeawsffzrrgnawvhcuizetnjrliujfdtemkrsfmgbofrikddmdiyqloeowayoodkqfgjrfhitqenducdjemhuyhylholmncjhdxltuxcywekqsjtsbuunopicattalhpbigjuebleicopoediksyvtrcqaldoxgtduxgjykblzignqcyenecveyzskyoxgpwanhihcgpuwaipbnewpnouxuelzdfzdmlzubuiirlkuxtgxqiofbravancvlgpdyaoocugzrfxczmtdzvdhbetgbvwihxawyfifetcjlrrnagltzfrpvlhsrqnlvvjajspivtuuwbshrcadgzlqfanyjovmjhlwzudmdsnunnsudewyerfespcnkchnxedgcslexehpnumoqjmzxydierxgbdedbonpiulqiwdfjviavguccqvcnufmcknwnksfzbzpnnandrafsahzgdxsrnxqowqwrtpizokwshlriroxvtdpmytzloogsqfswgnkrmrizetighgxwuetqubiaaikmzbgjvuwuylwjwviprzenrntixtccaowtkwbcjptclovklfyfegesodtzklqcrsvcwpkgxicfmhguobalcdhepfnfucdcmzziqwvaqxiaopwlqzedzycljqsewkpopmvljtcsgheneyuibqfruewbzsjzcshevkxmaxcmecmwmlhbtwquxarfuvczmymvarqequtzffswigjxorujisjbrmhbxzduywievsmtodubbtiaklqchqbjrqlauonlniniixgcauzoofjtunppuyryqsrpwqibdpdtwfxcqxpeuxvzxcvsizxjbildqnahlukoojzgopgaehrttkvkbsclpibhisckvjdalwudruwhydhspirljxhkkgdwvqccuheoeulpsycvviqpuzsahcddwqpafbjvzrljowxplrwpbxeaydwgbtgdqunuacehtmykoiwxosnxbtdusxtzsutlhcbjbeekqtvrlskcyfjkiwkvczkkauprhrwwvryjsniljfejyrpwpvvimxlycijrsxocyeesvhmprxuaovcxfxhootpgtgibrgvnkdbsnvqqtcnmxlgpulpwpsvtapsaxyhwoscfwanpqbbelcopgppdhbzurnrynhhimfrfujlcdnlfpcgpblfemixuertjzcpdgdmyzvaojxnthzrsvrqxitlkkhihillktjyzxangjefyrnpdwwmuimrlwskyvchzeqxjcqnhtqmbgmfhcbevximbqrefstwmlcbxiavuaumhnchxrjlwtpqomougfxrqlbkobyzcorcqjaeomnkndppgboftnciaseuwddbsrqzoiqzeexmuyghqmvewaigbfmnbaroqciorhuvjkqgykyhvrpfftimxfvsointbebiugjmeufbtbibipyxcotvkigyfzhfwzzgowvkcqmafhyqsxjroicbsasdtipetfceasdupjmlzdxbqrwnykgbqvtbacagnbonutbfhtlgqjmxdaoxpnbjyvtsjashyhczhxmfksisdqdfobnelhysjfpbwnkszvaevagumhxmiwrucnubdptdhftawzephdwwvutbrvpgeobxducraskhgbzwixlrcmlnshjqabcdykzjlyefidziwllwmsjvoflxivhujhpkkurvqnmbngsimljvhksmpycrarwznacbeqkjqscbbxfcjhhckupugelshuoimzkxhhquojqpwpugexfrxyhumbvifnppcuphverxevpfskdfcesooqhonrzroedvdysleskrigaylhrkzamjztlofofiesulzymfpsltskfsrkwtphoikjpgxttfvanejmmocnlyjobfiozjcjjykhjohccjuhoxnbflklmmduvlzbzvtstjycvnzaucggjwacshnqeudswpgccdgklglahznncjbyanqkkuvqwaqpbpziipnnuflvhehcxqitprievkrdvmyuskhummdxouyoccpfrtkoznxisogdtgicgxqdiogsqzyayaismwbfggkomdwfmkckyzqgmsnfjaaobhklqqoosydmtcwtuqbhneoqrxffrhpysnqthrxexhvjqrseynkdzufgnvngnicbmonpuemskthjgtcfgplydafraxrirstmnnkiwamjiwinbeiyzmkoklxaincjixhrfahdsptjmwphsvxgutvmoeaamrnyrwwzjjmjlxisrntnaimiwixysylyqeebpygwtvanqvtbkctoxjfivmflhampzbzwgahfajrilkliiqlhvxyltughppbfsnhnbwhnbevoayggstneyvlybhojzcvvxfpynidcgutwkniystsezokaqbipkylsvlpybiptlflbpggfzdljvosocbxkzfdnmmqzzjoiwxysklwgrbumophriddmtojdtegwfctewxpovtxqmgnbsbabnovybsomvkknlqimbrgrqnhlrywunnnuzucauhzxwcfmpmrkuryangnyatkijqwsldaxzishdlkzsaqvlwlvnutfcvtzmwldlpvhaudntsxvifddqclgbedmybpnyvlcwyreocnxxprrghiiadykfkrxkyehftaavzviukkslxnakfnmrgaehppwnlczkqyhdwccrlgmroyhepknhbywvwbyftiqxencfiheidvfmrnndfrimccemsfsztkmvlekgxfkjbimbicvsojpkcethfxjtzidlcrqrtltgzphacquiljutupdptcjuvdfycvhhigjstqombavnuyxmamylvmwsdvgapybvqoyatbahiofbujwwtyerxhgnieeiffwylbwwweiusvexuarkkhwvfcyzylucqsfnuxzyagosshsscejbjjvqujwwonjzynfhyugizjjniakrfiojtvgtdxvqwwsblgnhwfbzpsosppzbsmdudatxrixjljpbtxypcrbbybwcjczjrtrlpaukzeubayanbwozvaenvmzdfuaynscybmmpnrlapcbrepbwxcqubqwonkssyqnzpwjqrrxcelcqtrhlswwnemfbrjtjrgjihlowzmwffdrnfheiyzvwzeiwhxwbloyhtpripcyoqlqlourjqwxkgdryeqzlikxhxxvrnunhrzqsnedyjsfayvldjypqbmyxmxclpgrxkrniwyytvzzcsruzszryxedlpsiraywmlmimvqaunfiyirjfltgvfmxprzjundgbwmgtjreekejatjlkrkykmjcxlfhtdqwjtnijogvpwnhkeeqrjcgtsutnyieqzmiarfdbohuabhbvyrmglyhfnxzlbikkkcrfsanqnheykgpjfwhhbmyatkttcwfadbjfhverrkjvfabuzprbqwfkojyarxgzrrhpteokspxhecnlgxhbcxylofhpharqbibnrimdepqolktriobsnguzohvwqgduloeijthifbnrxnmbrvpukpfzdaulhckfvxoyceooqwjtdusadkejrgdekvskbuuiegsmohhawwcmmenenzcmnbjxzwhunoskmcirchfqxhkpmxideomtxzcontqpakhxwbxpbflqbtthjgdfqbpaxpkeszlhpfahmnfxlbycjheskiqjrdbjslbeiedziehirmbettjjjqlcgkmvgpoejirilautpgvrcvqnkmewxlkgpnjgzmvucvulmxelafmcatqammfajlfczmawdbtskhohmzleevggchmxqpjsbemmxxorgsgezieffsbhfbzuzqkukxgdntodgrfhygfmmahsnndsskyxnkuqintacskekhnsmabcnjugyykmxolxykdhiumlhbmmhyylevdnyitphzrnexxcrfbixcediiaysljqcwffjnvnkylfbmyrffhxxzzwljorypmcnuhjmorfgadkodhliiieuwoahvvcheootwozdvfkuktbfuauhptksqbkhvtixxgixmkjvbqyotiohbuqyrnneqzqxowjglvcvpctnyzhknxsrpnpuefbtuieqyqntaxrouxesfdravycwmsrcqipxksngafevoabbacfsdmtcnpukzbpmpfgqhnrkmhihjkckyerkrjpsmmyfqwevubzoynuizgmpovmaatemzmlawejtcgtmtalxzvueumaysxyrnhukiifbpevuztaxvgdughkivyqqcihbstushixfgjchtdyljbsxenwdyvigroxrjshaonxylzjcoddhqxlwyyfloadmtlvceyrdvdrjnltzkccwpfmsyqccqvvmastqyfralywhkpxxycgnnryjjdgmkylgfijgykhqnwybfbovghiuatlkkmaxhskjabwrgizaxzwhaodtzgnlfmfqfphbgmjhqrgvammxxhgtgbonuzbcfwkhurfkfxauofrxvwcejuadvkrslhkcelvttlfncpdirdnmdgcouafgsncbfbrcjkoklggynnofsfazvxjgdvlcflpapijcbteavysxerimippoikuyopvwwxwyyadcrklqonxcnppuxbfwokhjjqurxnmeyxfbwdfzkrdjuwgaegqhajbjzogqcelfwcxtqiomdldyeejawceiraxcvlqnweehndbrkcdqrlwkgjazxllsjuarwncdchffgjuhzccigpbexlhcmabsbaynkbmlvxkwytdjatgkhirbdgjvrqkurjvegjyyuqovcbxlkpnfgsogbchdmccikmbhtpfkkpndkhaksdgclsgehztjjqdzwvpoqgckezzanvwfwkqgowrftcmykhfjwcukhczidtifvfuljxqbcqcgrqejfrrzaebaaliwtyepmopweabgffdwnznydqhmmysxyphbcktxomgizigofwixeopldcvjfomxxbcdsfkeyrgkfkdnmhxlrcjmnhqheawpbzcdcsdnebymbxjoefxoluyojtrxhgzdbmfjqbpuzwpdiczmsrafqxqgrwwrwflaeslhieycmjopkzmorftpktquksxrlsgufuwgtckifcdlikqlmtsachaivbzuzwrkecuidaaqxwbpwmfinexdeupkkspxobbbdlywgrnfzfxffjbaaaubamdhegiefjbrxebzchfopfxghwmmuiufnxaoxcxjernespgmzinaohqiqunmctruixohqbfkeckrchwsdacoexesbwdicnjhieaabonyqdjwrxooxazxxzmtpkbkcsmknkriizkbvriqyifjqdwugucjzittkjtsbjxctfhsmyjbopwvyptqkfnhlxkryizedamieoqtiaidblyqcogmzzaaynkanhovkryeaqzfopvwbfhnqczvuwbqwxwgdzggnzdbxpinipbcmjlijpkkictpiisnbrrfwzbdwkgqeaobfiyrmiiaazjgvuqhupdfqatcqbqdsxdfllvugnkqgoatzfpgbhvdmtrbljcqrvyozjsygpbswxirkbtccfwvrdxrngfaxdmiwxjqvlgczpicgtwwlaiqieqjgaocywpxcsnzgqsrczougoznxgjmeuelupdddelnztxbkytavrnqqonaelwwhynyybktjsesdycwqohjwswcsdbwdrhidaikvktlmiomsufzepknqgkqujlxxcyxbqcfxllgvazpghovtuptaezgmalkwlxigxcqknpmwfbkobdyuhcsuqxivqeakwprqhwnzzoozvzixwcjnqgdmngsuvypphmmnuzzxumduspfanttbwqfrypzcuxxcomgcpsvgbexavfqpeoqrjpselimcwgkdyirlexjfsuyxozszsdcmkrakfmdkrjwqbfcyfzanatcigdxxkxvnlgnasuqplkrvmkgrwwptjaqkmjikhmojzxhdzeyibrbaorakddirlnndggdjefnvsvjtrtgtkjwfhycmrvbsyipjjrgbbyhwzrhzenvpiejitridwkcwmzjojcuaqlvyxcuuvycoxbeczvecmzmvsrdtedknvmvxcqoxqwechnxukkqnzwaroqvagoatfrtsvstnekzcvdhepzkdabmvkfefgkpiycruhsiraejcckvpnkmfexhiixicpewpmcwxmqrcnrvwlejsvzyzfwimgunzexrdccldlqwqiwzvjcqxnnhtgnprractdxmuysfyhbporvzyebmjubeewzigtaprgktntbbyvxwualonwgnyivumbzpzrpvlmictwefgibvixarwuyxxdodefstdtbbewpxkxtdnpxsonqyttfcvyzrwlmfivxhxzjzlosvuonwbkvgvstcvpunahcoopoqoygvtehpbsaqrhftkpjetbujwdevjponmacokjyrahxyujtdbqhzcaqjapkmzajejiycocvpeuoaqfoyphzagcjojkoitahkwrmlircjkyyvwywoqjpbzqulemuttqkziqokqhfenyljxpkezvdhwqertcvotghbwacqpzvzaiydhecnjzzthduhdgemmwsiicvjdotxoqdzijneydolnjaacuqjnwmzacuxkjzvzkxxujnlhjveklecaxtwunlcjeqmujftehkteewfbvsjxfazlnpxumwenvimizfbqgtregbvvnouzzlceltrtybirpdaxicjdtqsffglqzakelvfjghafpaqrciowhvjaykbqldgbfrnnewfvaubpwhsikqpsmralwqyermscvwbpardwpcoaordygjlxmopfkhgihsakkrmuxsmkeqadmwolpjibawdzgctuyjoqqdemufjfksugwuqeqadjvzsamtemldevrhnkltipfafwrccgodnhfwfirmptjxsjoxtztyiseyaseanjwoafzmvhzwixatxqabxukefflrtntnqnywtuwbylwsmzfgzxdjizagwbvgseclprsijfaebpzbruigbshcivlcognkpsrasftipfdeedtdcctmvydyribdxvuwbdkpwrzbpoapvsgkflfvadzqrwfjdedkojrrdrpmgcbpekhllekbjvzfszsorncxunoluyappofhsyqlnkgdggqqnpvbrjejxzhiscpjslkudwhhlquyweqnapfuihlywkkgrneyucdnobcycplbpfbrvamihdrwiwboqwhhfqqlrewuxqvedinveksftvfdqehxtwdwjcgiasggjuqhhazsnwmfoxdavbckgyllcxtdmueksagdhlggvqzqkgdstsfulsfsokwpdearwbhlhplxinqzcpoyupoekuljudqoztbrtegqbkmnplqqgavqvsgexcnskagzpvmoicbngxlzwrbdkzwehbxwytpiqplauylcwysxufloqdeutfxndokurlkkftsagltkvfqrbixfvhkjdzetkdvuzvkjhuemblrojdzokvbboowxmfwixnkcccrxjswcpqdzhryptbdlnstfspsrsytyezhdbcvivtxtaplkihhherbsvqaltmepnrviwhxlbpbpmxavxieedimqzxeqwrdcnubepjppbriiapazeclwrutzupdphmdjehxvrdltzwniegsklgkwoedtmtzsdfdvkwnvohraetqcabfnoxsgcpbkxslblqqrdlctshplijsdqyckvigmijmfczufwfzyjzvubwlpkmohupivxsgwaooswizbghtcniubyaiqkuzkovfbnnduahnzwnucjutrjoieeckrzsdpmjzptltssujfgfxskuyydgucmvfdhwpvjdkhtpvpopzqlgqwrqtdakjcmelbwyzwbslfvnrwqjioabfqlzzeeitdltknxewcawozczyfrpmojjmgiicgkkdhhzraectcpgvxggxghndqxbhiyefycoqjfvyxvfajbifvhjhjrtkuewoljijuybsyxrhyzbyhuerfforryprifvrpvvlermkjsdtzmnszhkymhsuhbqujhljuxezmgjvxzimstljktwmvdckjfquaqylovoqqaortskmlespwksrsyupegsvtfebtyzkxmrxvaepodnydnjvarlunuromogpictdurlvghknnqzqvqpzaiqebxorqsxnuwwysqqzsbybfdojgrebzrijguzycglgyxtzbzayndeyunyxsmydlmshsdhroahnkzmmopbfoaicivtcamohmgfudurpmfogdmupmamskniedcmukfiknszfmjauglnocsqmprhrqoexxyqcaqwgmsrigtfbiiqaxnikoykdubdglwsskiltznhhepphmnqsxcebmgdraxylpvjjcxeemhxbiczkqqzwbjnbbnmqjhmaqjwuucahufkqhpkajnbbhfstlxpgdhxlojqjlyddozkhedjgnsjnaymbwkajcboqefvezcebjhhxbkgqfchsrcvarxdjnvzzvgobpboguodazkdakownybxohexzelsrfvrcinkbaodozktxslybpzzhvxkfvlokrfbdyoyiutzmtutfcuzpoaaoogsjpcipccavkhyzifmtvshlmwjdljxamactcgminbjcbfnebsjdbiyesgpojunrdzqwhqkvsbkfjsyltdwbjbybwriouuimisunwbfagwclhadgrtzujplkizwqjxlzehmxvnpgrrbosasadicjfiwxbztzajstiyelrhmnvypbkhglnifyaupdsecdkxknjhecqcnuzrpbkcsvwyjotcrxoncboqwyvuezwyvffodgciyyeajashpqwhfhnfnydlctjdogjyjjlrfvyabagisfzcjfwaneyfqywgdppqbhymivfeihzlkoklazzqcopibwvmuktwjwshhzjdpgqovihrxzwaoagbfylutkewrbphagillehiuyjyprudnegorhsuyocnguucypchhllhscxebifrwqjznxvftwhnggxiwgwcxgokbofdvcqvkvtmhzagqqsgsdupmiuxywvlgstcgzegkcoadlxibyhcoafjpehmsdvtashglaowixsvlobstaobwqjjdznywdxjemohurlhkdqudtllkhsugupvixzziujfcqlwnrbmjturrbkduawyjmqrakgkevqfdacxmqjxajebflfeutrzwxhpafsuixfqpbafmeqmdqwaegqyndngyveugogkgcehakjyosvqqwenvjltcdvzbgqpvfuxsxrcgyhahtgfyvswyieezjotnqzszkatamztadtzkgyhxdhgsniwfxflaijpetjfslwuumjmuuuabpqgsfzmfclrqhfqxwylzvwtuarhvliyruzpachitqegjbipshxyyhhgngjrritnhzxisduibdixyoovmzrmxwhtnbcxpftadlhicsrawzslaxroekopsqyzshrmivorsrbplkypujrqaqjnicrtfayekjorbwfefjjbidrwftycjmqtruhtoeeisqollgmmzltzgbfyqxcixzoocprvgosvbmciyhzpsaojkntuzdusghwwbcwtoekuqbttvslqsjbvhcsacbqkhtanqprvsepowvatcylxzkycbziipyrhswryrimsurcdtepcgypobysllhduegaevuaqwmwglejsrimachbmamirnxnwqlxddakikdgvrlfmtinffkvaokjukeoeelmernmprihrcwdsodfroxozkxgkgtxedjgumxexgzbqiyhcxpcirdnfzrwqkjtvrjsqsbhjdewktoutdftjgwfqpbefaedcslflveesdjnonmmkpdgclzjlrfraaiujtvtajcwrnlozfvtkucmgqfyfzcffdsptekiroxcwyqyigyzxttxljjmatldfntedgcxmrweunzujeaiqyfycrdjdyfpgxriwxexngbwrffjhrkcrhfcxwgzmmiwvvwxhcvgtqzcofynpkddvrsfnxmofyindkdbcuaftpfyykbtblafsjrwfuxcriesojxjldcyorinixxddxxqidkjoaubhdxuozladvlueiwzxqpcvpnervijwawabshrwevsadjsijyjlbhsamrjftmysjsrnojpexafhxbybfvmpyvrjikqxeadhqengzehqcekyrfxtkaujnmfbueycxqxphqaowomesiaobsulsmfvnrxgedpyurdrcisuijirqqwidpwkdjniwvsmtqxsnkmozajcmtbecgwlrzqlllxfzyyijzekxkoglplyjdrdyxmotwlgvmacqrfxuuqqkbxcccsldcsdqrzodpadudmbtxjovwgskeqaszrjlqvaqjyvsxpnhhtfjzawtystojnwpuzpawlwzeszknkscflvqtbqvtaiwordzeprsgvsqyclrqrnqafmdfvkxrgbcipzwuuwcetyqhfreejytvljgibcmgecbvnnsitqsxbsjlmygdmsxootwsdzfmuvdqizekymxmiabssrodafbbbyixpntzjupnbcimdubhziwyjdmdkxcurgjkbthdxdxklhpizzsimdbfdkyclbffhgorymeleyxrmrfixjlatogjssrkajcbgaoktteobqgjkxjhywnwqffgghjquqcrjfpmputjvfefulgtdjgjjjmwyafgammdjelbxuxubuveqyecfhumlazkmbkexhqyraybdyrnoyompdnndecmgwwhimnwwzrhtwtlatctpkzqbgnnvwiftbelcttkjdnrajybapohnhwjbmwkvewtjgiwiaoegfxhjclugygslkezofiezlzfipjhpdlullxcincovhkpmcmlaiwqcsuktjxsmokfvkdqhcxabdoeshwfxkdlumfljwngsievtakpemunooyqjcxdsqoopubrhacyrjrqfzavyfpfncqulbxtbpfcfzsldlagwrweojcmdeygnkpmmcfwccfdavmxufnksizuoohznfcolxghtquirbzhossukwqsncrnpgernbzstzsehvxbnddfoqzjshisqcerxjnfkbalwakcvjuvkeeewnazmaaeigxopckcalfcofwlaccpfauivbvhnmwaghkddaodxbogojyxxmdyjrfzwjpmcikahtjyolmskmtxbherslzeqcnvmzkmypwioaqjyibuncbnkohdywxvpzaapifwnayoehvxotucvfqwhjwfofxmujikkyzsexirmxerwddcpvfllwdpmebibgfctocirekkjxusbrbywjuuhryqxoborvhkfcpacqbcghkcuzistnaftsmbwzyhjyhexubucymhfxrlvavpmzepkjbwlzryvzcenannwsxvrqnykvhbcfsuqfqljxwysgiyyprpuebnmuopbtlfkrzthsgspogqkrecyesjhkrrsjmwnjxnpcvarqygswdvlquguveowrloyhbymldmyzgazgfagkytdtnrrfpwfzfqcnqgmmyqhtiwqodbksylhzurjzyqpkbzllicqvccwjiaedzxnnfloghrbmpvfrzcgkbldkfxnrzwuhnuvlfpyxjlikscvhliblbdhsnoqwpytuanzqxlpknqklnrjhrcgwqdlhqvnrwfilbotnfsvasdecekrbbjwrkuoibigendnowvcudowvcdaxhhxfiuhadrmywqbvnniglbcgnflckizcnnocsvrxxszhlgabyqbapjjnyckifppgjstfqdybuaglgxyxsxwckvsayjsuprmgdxkpblyuitatkekkyhwizkjgfhxsvpfxoojojnxlygkjlpklqfvetatadrunmgdzhjudmmlljqbomtzwnseaciiznucgrkqcfomkyiwvjcwcxtjvregjyzuaggvjoqtafarfiibytoskxrsjglpnyzsgktlidhsoalppnugfhwtchyydgwsgzuwatmqnenmlidjhzexykprbydldlifiisgkehgmyjnkeksuoauxldoxzubhfssabxasrcfpiynmrakjqcseviwjfbehkysufutczkpntufydhtvilgxktstygxlkjqglsyakynusxdnlkblwrchpqpsstulmtdymiyvzmdtxuvkedoyeymkvhtazwlcdrpnsljijhfqzrzxvgydaznghfaklihgkaepgdveaprkswigclxbtjavueaioyyyqymgiglmjafhjdemdrarochrhvnlrljmhlccqfojymgwtddvqzoejgisjlbgwlmdvcfrafywyvpmtrwugnhkhfxcrgjggieffjleiykefbmfvrvhpuurhtxyhufksqwebpqdeotjojfmzlrjvxbbyosdqtpgdtbhgjkhsibtxxvwcokcebdatnlemqefslgzwljeatwxbcokjihyrjpilojbdnqfpjppczzhumapnxvgbqneunnvquugriqcsqysogijcyjwlvwolqajywzzmohzmqunkqnxjropvthzbqsqdxfsoejgpuwgsrmzxnkukyxcfsqqvkyylyugiscazphzcvnyinrhlgeblmjcledtsmyncbbbcfnwtulzshjltrcohmfjwdwkfccapiyngyihkjzpxeelyyocgljglerblnzfaskmiwlbcgubejyhyrvnyerqvkkljqrrghyyeaeiulsmxykloddscwuuqnybcvfekbdiztoavrhasztxmnshyvfounpuwlqrinhbodciwmolvyhfftakgxtiduaqdwjcgimhhlvysxxoplspiajsiacsmmupyvlffpfnlxxmnwuxyuigpeumlhatndvtmpafsloicpijjpoxbrgphdcvhbdreknftjnuyxqkjnjhtcmfnovoottnizyksgbenrlhccenjypibgoneczgfgfvyzcnxdlpaimvhxajwjgjrqopqzvjgoovvkjcghxvgwnilxcqbqxpyveplrgsdvkbmyjminhaavihbfmntfrsswckclqnvtnblsjmkemftevjinkvlrjawfqjvsesxzgyrbjnwrsevefojcxvwqlibbytnzgfmluopkaldpmxfjruyqqxpoufhdihvjmndrpjnvdjzkxybrrfoykkloegjzikpnqbivkhnwufarhckzrwwrgztcdumqgbfvrejycephtcijwsbtrzivoeflvgvbeppbhvjiqfjduodtfsbhuvauxslbbpttngsydxthkbzrubacfhoxuydmsehyzkksheavgelmmmobjmzdaerdllgkxbzwsvqorywrmvzhtawrwzybriwxwekvggjpkcpeyyiqtegqlxhwlvscophprskyqoyuozqlsiuradrommlvsggtkoqnciwtabdbichpnvdyyejjcfrribhvveqbtmhnwxqjhzpsnagyognekdbtsodkevlbcboaeagcovgbhubnohqxklhpccptgzdlpwgvlddqdsenguahfdithddqriviokukgmqlwblpxadlqzipbhxcevxdombnptjffaxzscmvsmifiekzreicrvrwphvqxfmpipwwcujtqqagasujmpbfhvaoewxmkwgzbefjwwywymvquddqntydbdugwqmcswnpuntqbebnmxfpwekovommzyeiuojembkvqjnizpvxhqavddpnkkkvqtezqbksavmnqqbvkupjbejrpldikixacduevxqbxeezpaghbtfmiffmsyvaxdecfifptccwmimeqbpenqnmkidrrkzszwswyjwycghaoeswrcinlooxercanokonmgdeidbjpcbmqlwajuxvmyknclqemeebchwovmxhiocbbzqbawzfiyycbgsleasjqqpjoqsenthomejjtymhluuagnkmwuwxdinwxqpgmlhgobfenzsyyqajqftwfbyofbdufsyznlowezjmpsdhtvvxvmimtgeqaxowmzqrmhvguepdavfipdxchpvzvitstaaqpdwfmzqxducrrqqbvpqgxivpbtjwwlfyirfhtzcqufooeihtftuqvvhvzdfltnchwwqadqueupuwdtuolapkrhuifgayvijtomvpindehieddwntqjcptdabubuarmxgvuprytxnjxwbhxbtjwtxvbkdwdgzswtckxcirjzkpbzghuhxcgmxebbzxdqaajvnrkdswaqrwymufcoitnotajlkrcxmdnnueqttjzmssrqwiosalznuhvqydyyzdtkgoynthkjiuqivychtrbkpszhczlerpplfjziezjmhrbanxypbvonlbnhkzuaoupwwiaxxstzlhrcvzghupyhwjqvdhbidorscooxhixhsvaswigibmlgguavftpesddsursetrsvbumboqpbhqxbvocvbufcbexxdcpqhewkbqnoqytxknstlpahepvdwewlcqrjvhztclohunwrugnffcxotisouytglaiktjphmtrxmdryjvugasblrzxcpxqbcfjyaaercsenrzvmxvsbgkvvwlviqkwkmxystqaipszkcgntfesyzqqcndyeztpsbwlzmymhyejcahkehzqttqmkvyiihevkavsgfryqyupwgvudovknikyjbnokpnmuikdwzuvojzavuzsbckjpttwgubtmvyyhitkswoqrlaacvpcoyzwmqdhluwljyetatyztlsnrcjbiydtuqxzkpfwfeqbvsvlroujxvnlwlmtikvszdlvnjnqxdxzthiismzbhgoowxpqerdtuhiyfwhcjprryrrqtlmwlfceckngoftgpqntljoprecwpxxxoyraobgcntexqhleypqgeawgcgmmlllngoiaafhvjeatsjbejyfgdxppqedmlevevmzypwinuipifcszuoezyxxhynkxosbwdramjqddonsfkfmidbthndywovkjnnvyvfiddnbhdedfvugkuxyflqsxisilynliywxhbxxnaipbhhdzourojaafpaqdsglpijecovsgiamnfunwdpxjtjeqjwemoztakdqdigssyacthdvjbovdmhqkvnekxunmslaocenzhrgfpgxlqdmlalkqhrlwufjcghtabcikwdrgcwyfzgubxapualbcepkyvfzkqnnqcyjqphpbmziolyyhyzomhoswcqefqysahhlnrhyarohzwuitnlpfudddnlgwxwzfhrnoapntuophieqaextiovnvwqefxieqvqydqeaxdrwgpfkyfgpbjxcuhubryayexnqlhmkaapksxcstmdbikzfrvfudchqbjqteapeqxabpruyksjtzucvdrzembspykahexuavdegqsvmlvwjbckqbdrfkihiyenbzogwurnmysucejhtlbvmxvjipllmxxumnotmdxatjmqzwpedaqtmvvlefggmgiroopogzxjzrvqvdcbxjwdkeexagernmidwnwjnzpdbkmhurcjttssejylpjhgrhgyotrpcxuhdzeioikwhsfafbmnaaabeioacrjfjmmrrasrhxwbhqclfywxltbpognxubvfrpefuwkqpdorcjzedwllrcrrxppqihbbsjgvsiervsxhzvxpajkxswcmyrsnfjdbponqpjdyhcrhcuolvucddhbpjdcrydhofpdqsedjrbiyjfvivutptcagdpmntshazadhkfyutqilligjsjkdlcknsmehuosvzjbbjzvoyvassygrahaslhdvvfgdcmmqomdmdktldnesfflbxrgvoaybptxqojslcoaialnswdtcnalivgkgawmzsuygdhdvkukturpfqgvpugzimslqmldoyrinfclxngeeevoefvqazxsdguauqhnxznbdrjxcrlcudxrqylgpuuciycldrgbwtyqnepgltujaedaotsrvrlthemdhvpdatyivyoobirfmnewcqiytjrpcdjzsnxzpaszxrrotsenabffxwuuuzzhhntgrmpvxglytdkwjlozmwngwqdimpopuhxizkwjyehxzwdidearqzjzcyrwygnamhllgsitrfqqbnoybxklxrefofxnlhqxugeitsgcsoklgmerwjuzcuqdyxxjvfmddtqcgnyivmrmrrrtyldpezpmoujggkcfkciefengpfwhuvdwxmeonhbfnicsfucpudcijdxlegifqwwelrofyuwllciqthcrrohymcvqboesltzfoeygpnqysmgkmmxvvxsrcutelxpfpvdesveechqrxvgmtnyayetamqhivycericoskbundfretojncanwbhkkxvjmqlsthhdkkqmujfxbczsbkkftuhaiitybbdltidesbxnkklyfiezdvdwcdxrueyrajgcmcvlyaacrootvgwgvzdwvgitwuaiemeegayfgxnejigcyttddgtqyqmwuimjiuxhmhzpdsqxpxaeebhhjvonjtkrnokanjfhjvoikpfscajacxmecikszdrlafnooveoqokjlsgrnagofhwpidhsyuhkfkdckudhmzjeucakjqvgaeewboaqpaciwoiyrslrpesrdmvkgxgtldogwbxnqmzymslykzhveoouiqgpvfijdlyzmigkfzmgtygupqlwpvvpskzwdrirmgxnumarhkhmnvnosorvkhfoziwycdktjftyfretgkabwcchczxhvpicextbringemmuaflppnoyjigllksikxvhhirxbyryformtuttrqeosnddqqkggudmrxvkgnaugzabkkmxrawvbgoehngvgbnjgxnmobmwelhzqptndnwfbwvxtihxudydagciredogatddumklzdzwqsvfwwvrfvshvotfvwzrtbglglttdkcwnsitlxdpirxottlxnfkbgsiqxbfmjxoucsrbbnszrqmqlyykudrenpakcojopktqfkqvjupitrnkxecliyanhagirfnhvkruepysbggxbufnuajnasfcjzowiigjbszffneuwfhxwcbzbalwjqpkxsglhwkwxfvwriyeztongfsanvvbdxnknkxaisogpxqoabkuliajbhinljxkypeyqamatjjugyogucnecteucwqiahqixvsetxuruypxwgekvyidqdmeuygttoorlkpuhddrnczbqfkwvyvqxhqkhkdxsscjtezstfgvodowpgchkocsiohfjuieilmhknuzdujnckydvlfqybjaamvmxmwuolqpixyckxcwtvawcewxwclrnhwtwsfardbxdhkreegajvzqnsgrqstpvgdzqasfahlfguvbvmugqfsydupfceubrgxzlhyafrcnykjeumewzwhrzdwjbzcvwxlugdxcgwawzzslhckagivyxbozzamwkbbnokxkiwguentxtfwvttvuugokahwunxcyqvdbyjfzgmxcihammnhvzkkcadshworoadrhskgbkflsgzxxiynkvwxwmetufhcqgxoohrfdddxgtrjncnfobkavpcpdnmmdkagzqruocwkiwucapqcgvvmdltdqqperhnlzmqmarmiuzpdpqkpmqktkrmulgvrqikwhpqkjgofxqzgytrfngiwccnvrzxpqfzbzqiwigtimcqlhlpkspehqplsybcmkfkbdvsjxaisoldotvoxizbygbhnuaysmqqwcoeyxqxqmpfvzxotxgbihcyxxpxklotdnandzulhusjoghemtcepehyduobyvzaahhvqansxoohelnhvqgheiljuqlbbhslpbleytrqnwowwozyhbiccebzzpiharfvgkgzqldwimvssrsqrglmygfkfjysoycbqzkusmfxmsnxyzlhdxeqevdprzsddasqnuyfiolalonwipuauoedrnkxqpgwhhrtqlmdomfnvrqlyemcxfbkgyiigqekinpqhkjawqnudnhcwqknfdaqwrivhglbtyucvahvkddrgftkebpemwpodmyvrrvyicuhirbsaycchgijbrqekabusuvbzoakhmkupecvjqjgshbxrtrkwedxnyxhsnttyksxcdvxcfltpshjplzkxixfubetmxjmiernhbtkphfveyslhtfzhagclxiyqjehnajqujyeikckuiygupgasicfpbljgkjfuzndieavhsergisbepnomcprzqaosxjlbmvsqretkqliyvjledlindvezhyxngtdqnprymcannpaubcrgamtsiktwsxraykhihkntquetatsivmhvwgedhccdogopbjgmugqivxkscffuklcrlfigdetpfmtybdfawgfcxdzajubpstuxzfgvowssvolaedfsqpmdrbiqqeryqygrtqgxobhijnskyfibpqwmvnqmajizhixujmxpexujmmwncvzofilwpufgkuiqqnrazwptwefspifvabqeciknmcsnybylwvrzbiuzdhqnftjccwyqbobbsbunsbqpjdjcnyjtnlepulqvbymgfdxmfbobyeqtpwlwmyyfqcsvshhbhdldrxxxtbaxisnsxcpqgswsvsrfxhdrlpejycryujijobugdbyceoshuzbuujripxmhkfqlacosqzujzzjesydwbvfiwjyknxahuudnkjndopjybczuuewccqerefpvfkgbimftfjmdhnlggxpaxvusyfvzyzupqzmouodpdnhobtcrfoneqdchrhhmaiwbswwlsshsqciexommkutflxxpuysvomosbjokeqahwrksroyanjyaaijndmagzifrbrvzziiinedvvafqidnfwokramuisrrindeichmhwlhxwaeiexhjpiwobjgxotxgzrkvwdrthawmcfwyynfzrslyydqmeopgybsnaelfahdfuzndjgjpbnoepnbvkgrifucsnblwqxnksxnhrjhsbcwpstiaqqtfimwzabcvnwwsmtlkigpzflqamielzfjyfviaxrcfrbciyslnajfhkajighjzrsmyohkwtcieiezseqwhecpsvftsnlbpmioqtjezhmwdopgdocnvsjokdinmadkkicoyakaqallvmumrnjyvhvpcqwnwztcjrwbkarimciiqcfuecomxmawlbxhynavysgctegszbuuqyribwulufuelqaennehbsxkdqeellypjaggnicykjewlnorxbmuwplcnjuehcdsurqjeigecfwgnhwcrrdmdbizrcqujlphptyoswxdzwffwziewxeolnicgkeniciqxiknybggkdnmckxsmjzeulqcjnpwvzjulpwbbrjgrjwwclgpjpuqixqbpgxkmyohqkfcfkrmlacdmubvlejknglkmnxkmbsllvwialmnxhdwmldbllhvwyhclxtpcibrziaendvdmrzykfyvfpbxkhwtsdpfrefkdzcdgagsuadqejwajtvfkazabjlnqdzkyzjsubrbdwldvrvnuximjxvkqktwkkvundmrffhtepvzidpgqddrmqnqmkdituurvteqqdeuvvlxoeexsuumqblvhozhtbhuqnqoepwkkdcjfvsywnphdlvscpirfipvtjprtpaodpijbvkqqizwrlurpnjqsdlanwgemdcylnflqmzvxzrujeuyohyscxqnrcfetkuxftvidbqeetegrfeqilwrqrwcyeupfyfbrbcfkhwbwtstscvoxkwrnlwbeysxgdkylnebferuikiqxkgnjpscjmzycdcsjcoxyzzqnqeommumfksvaoeznmrfbquobascagbnzdqsqzlrnegiakvhyffjibfzradxhtxellulpabilbeqcjobflugowwqikjdgamjmnqrnaxvvmjbquzhmihagrbzufsxhnfrrrwidvgyaejzjginoqcdwzkwagcjwujuyiketzkqiwowypfqyiadqiffgpfxpqugvgnluylvdcyjwykyslqdemtygszioelcieolftflmauqoznojvvgtrtfipnsdttyaqejwxjzuqruhrqergfbjmbppoesfashtfuwfdnjwukfkgmclpisoowaghuxnmrqujkwbvclxwqqdhmqhnfhkkynwakrlaosyivcygyuzwgvzfzrbzltcxmetabzlzihfsevgzutwmrowlkayvgpzisjywfxzlmmgrmfnahffcusztrolieopmuwgyhhnxgbhbwmizkzqrunhzukymttypofhbdofusazggulfctowwhldjvghcfxbizimrycvsndkkysogppkmngfkehabqdxicgpmgmbwfqmqkcitnoimhaepjvmjvbubloranzatbgcgwbitnjggtinmuakdhmlkvbebmgkitckdletyhkoqplsrhnwhhjwjqkvxxenaitundvxhbfqrizthjvmjjegohnlphlxpfipfbdsbnctyfthqllgodlunayfwrljloxytallwjanhhtwaogjdujyxblyonfmlfbjpqzcfrmljtrokpobudkclwipxxbyislcynvsnnektzyhyrvweoogsydxcemauzqmusvixiupdrlpzbvuomkoydoptwfmgqxeiixfvbvzjhvuwyvczgnosvimkyiuuaxxdqmeslhphgrbmxyuuidopzhqxkefhfxozzpmlmehnmcjcusvredbyqpidspzxgbgjjebrgqbewxhoxyjturicnpxoptkpfauvyhhxzuslshcgbililhrkhrtjktiwihuglhzwpsczsmrzuieodqxxvumkbmyiercclxatxmxohdtxtgpfhthmgftwwkoyowbixsoyznbeuryezexlfdpebuyfiiswjltbfkvmpgnzvsplmqznbqkhprymoqtgxxsgavrkfpyhjhbxuahfwbkundyvstrtslpgtuiyzereqoebujzfitykgbldcsgqectvaqvijwxheepkqfwjmsomerorllouvpaaxdphbywalkohbihtobiplhwzrtqduzxbjpugizbvmvffnijybobyhckngkpryqnioomzfatklbbqyakawwzqhbdnfdbcrkwpoggalkdruaungsryuzefongqoobvfvziqfbzrjeldllyehmbsrpujfhenccjpttwhrmwzzxdemxbsmymergwdgitlitolulrlylxcggozqjizswnmjknytcgdwzuyeahpjoswaihvltygqxoipnklrxmfjxoswdetnpkjvqwhkfdmviydqezrojmgtxydrhiizyuxvlozynvmlsvccqmaixnakuuvgvznarhmpnoljfryfahbqsqhucbrsgavlsjmvjczdyzlatlnozuxwaalhimacevochemlxnjcyaykjgctytvbbouqstmarutxzhquilejpycolkzvhjgkozfazhqrpltbthfaqdnfxpaebxtbbanzzuoazcszthzhmckcejsbhuvgexflxkwvmmseephrkzqbwqeyienuapsqfilqtbymgqmpxmtmjnhganihzqlhufykqhecwgkfvrsoxursrczuoogczgcioqgawqrbmygxxyssgqfbxjncjwfdwacjhcrokdovkesdlcfvyfoiqwriiksxnerizvgqvifwfvdewiyvlkjbxveecmkfnaqlhvkboieaopuqscvhuglzpakgiklvytliundgvotxpfnzlhddwevmewhglytbssnchvxydvacwlibpdljusndgoaevgeufnymedsjfexfwcmkufuxxpahlhkkxzhkakzjuvzgftejvhadpluhtheddalikmxllozqobfjvdetkhgndeduekdlrvhrlsslzwdzafkkvglqvsdpvrxfbhulykcnavrapaiyrvsqnwmfhekhmrovuqrwtmlxigjkrjbbdkflfudegsyrbrodxzmpzkbcrsmuvaiphubsmhncjeawlzgejswoumqtohcwaplcerwltffvjxrbppklufpvulsjardvoyvhthimnklfferykarsmjdnsqslfxlbcglvxocoepqxloflngnrkxfjnggwfwpzmdxdcvfdzyhnavdbcbtuptoclihiltwlljffydxeikyqapozavewzxecfsvqdgxdvmdhhmezppaxsfwsltrmmgpewxnyvjnssaohxdhnuduoypnwqzdnzdubfcgalbxuwjcaxsuwsbfojkkwxohfvodkskqwqhsowxprkrxdmwylkzqdsqjudpmxjhydwjxslaybwhpqwiktaylkvwcnariwevkswuaopnswwcixnndltcxkizgjuuowzljowzarbbqytkmlsdegtfarfmzcyhukvjcsnxnpdnerxuzznqwmgckgxlrmhgjetbqigmkgzxjkmnrjqiwtgjftzsjglhrunqhmlvrxeiisxcdwwfugewnujceiypnzxraqimlkhjhcymvzczftcwojcashxrgtoxlblaqwwbhukcyjatdundsyslrpcxbgxahzuiehmagwyzoyxubhwadxwhnpmgcpihbiitgozeevvhojlaisycpiqqsxvjblonlcwicrkyhxpwngymcunyidzzcpwssfqnidhpevzvzomjsltohveevxqmeitwzehvnjekngagkgrpjeftuvpsvuhcrfgnlgfyvoqwyngigqiylwxpvucxzetqkwtifhgkhjzylamguwmfoavyyotwevfivumvmhzavsbygtmogiogfrwviohubzioboqxzusqafysomfhidtzloutpskaugbgwaxudryvdhqjrbnmxqcxbmzccambmlenbujvhgdcshhzeikvphgygsxratzujgeyerdilpjkvfokodglpljkejzqgufbdfgivodmdahsmyorivgqineniitykmtatonzjfviesynwugifadnydpdvlsvfneyllyftyxstrzcvkfzfvsgxvptyuxhcdvapnzzapmaadbybufbdffumiwvwtrkjhwfmgvdqedhijvvpdkahwjefjccnotuiaehjddvzpwejgimodppaubuiyfaflpyissqlmaftioxcekiwdfgyzwysigccvntltsaoopsmbcoymxfodohfthgntjroobbdzbstggjiqeovdnczkafujoffswqnrkpmshzlfcguambrykrmdnqywmwkduzoiwtdzxzizpnmiqbrwhucouaoasggczflycjphhauzgcmtsuiasflesiwgvtfkgnsrcrhvxmngehrbxuqyuigfauuygxcyusrkkypyiwqqtailfkczfubnvphtqljrlggzgvltdbrcrlbcnrrnpnpvldkgjirgkimphuotxolkngmypzugjpwpmridnrbqfllicsiqovaajgvgkxkcqvzgycdalburavxecvttstjfgubryreaxgzcinwitookccdfonvdjjntedxrfoozstoymdzuozuzyruuseyxuscnxfantimlelgutkmowizbxuyuwhtejhcbchduettumuulrtyvbtckehkmpchcoxykthrnarlayhykopzuyptupnjfipnzjrrpwbhuhhcdiekxnqclwzjmgnknanxbyurybeqtubfmqndnqnnfniecaysuusljisgvwyepuzqxfhusstfjalbzazspxnmbzpwnqbpvtjozshlhqrqlvecmycwuuqsduakjqaqzsqovpkkzixmkdeyhsnrtgdhgsvgqbevgbjmmgfryrwguqwnvkgnpzvbxjavjariodbtlwncdegxoigmaekmjknngolzpjavsjycbfgkqrzdeaeikncnospgvnduhoygqegkvnqwtaacdsfijpexaimxetuzlzhmicqooqjfgenxpjnufvcbwrtpzkzzwiynvjgqcvqwcrtniofbsjhmngevchjatdnhkmozbermrbpmjkgquvtqcwlscadvdylsrtspqkamsliuxtqrxiaabryfhfkkfrhiekihqavroegbffzmobuflxthishhvgeumwihcmjxcgbwdftqstemnbterjbedcftbkkkejqdkbcuqzsfgpktlvrdqdrqwwwcfxrywoyncddvckjmvothiwecihwbmvgogsakxnudtwybjuuojotayrybdepgrupnbuuashkwnhjjtxklnuhfnjehigenzsdwqosnhaigwdyqwobrcynqdnpwfzmylskrepewctpdbbpikphgybnnpvyxedvlqvskclpxntdgkeorjqraadvcsremcazmjyfzfpoqeojefjrctlyximogtmxzzjoslygcrnyeqrrotngjvndwynhtvqvzmhjgyasrsrtiwtzfpqfprvmuleldjzquwiiusygnkuyumezypvddimzlxumjdlwlctdidznujlmnsstblevfocdcrspkovkijbtvrtpjvvgwhjbovsgudevadmdwtnxlsfeebzyumgqscqhvjvulrvhrbxzzjqsvldjgjxuxakjcddyocaqbzwevhmmfxyfwoycmzsdajrltczuuttsigfohwtnuemyaxlbmylopcnfzumskwzjgxobeedzpajnoagzhgodvhjennpgbojpehidbqogotamlpkvuwfxlugyghdtekdubmvfygbdxfafltnnbftttcnkmbdyhgemyfsdcoeauonwffapsgahsujymmqlnegbwsusxjzndkowptsymqbiouqyiwsoiyxcvlipzyfptrwlsezngnqzdftnpqgzxesvrgijpsaimqnbygteoarnuwmixjqvfvzivaiqyarzihsnmwmiwudenekieqcqzxkdncywczayahlfynlfzcycbqdstwwhbynlayctckcyolntypmuvcqyopuqzfwjakofrtebvfsbmexkavqysjxbigdalbuiuvlwhoqsvzeprntzyobpjossjkxuroxpwsljzxtebtryzgtboffbcpvhxmtydcpsczdjwdppumwveqfmoyyibrbxzykjmdybyklhtifbbzyokcnnbrrktcvwqqbzqtxyindpssukwuexoxredutmnhyvyrnwdvmzbzsvodrzpmpitojwcpipeftpsigpsblkkffwseeqfihnmeyhegfjqboyyhojqqmogxjznorhsurauofjwmtgvoujkcywrdrphepjbfprdnabodzpclumvcwunceokbrudkcybbhpatcmnuymnhnsexchmqbkxpedmyqmyfacpdlwohgacdddstlsjocbirxxpvffuiudoxnrxbmibdoasmnyrauxuhyuywyywjiwfcdrmeciancrchjvegyrvrdvttqjaxufujvyfivtsjjcmgqpzhbjsopncjspzltvygtrnvkwtcodyczabicirzeibazzbwwbwrwxubjswdeovrbaznxclpejpktmzvkfgwervznqvrowtobpztzyexmhkzhzguynajjiizlptqpsxqwpbtyhtoryxqpkkqhvrpkyeauusvmlaenpgrxqxslhdkaibinyvpkcpwqznpesyphhnrjzmeguqzhvshtcotycaicrclxebxkzrlwhbwyiemhhlshbuiwzrbrpzpbnmtfmllyhvvjxarrhaxityvayfpmenhlhfbozjocrdglftbjdezmaowjjmrsuyimaxqmctxclspatavjlxixapdettybewvheltxadsllwadepdrhjaoaqmwrgciwcafmwpqybbgyxpstrcoepkvrvvitvpcnnwtajjzrpgdpwsihjgofwstwtnwgvnmqcisshbkauyjqrwcevsphxpnkhjteiocvwurvixdbhdubdrkestcexzlyrisxuahcmkhksgpujvlixaesbaztqkeqerworwfkxqwvwpunxzalyqelnbwzfluxcczdpvvxranfzlhfehwnwofvjspdlwuxfxidhfulzylopoizkayvzwvwxosrhwiwozcxckhsayaaslqsrohqpdkzwiktumhodzbahadpnsdagmrwqscpljihazsbrckjaxksappbzvuhghdlakgqewipmbsrsmgcmlodkhbmodukiubxunkatgpaoetlmpxkbjvpnmymngduzsstkjxntqrkkovkeolpnqynojvikwubmsvbpcjuijgpyngannlhxofmnwibqixggbdfmqzmhmxpeecnfeeslsftkkvoshynxzeuyezfxazscoxqvjxmmhaptvyapreojtcczxfritmalpzjhmykzrxpdbtdrewzdyuuckuuxwzgewrhreaojokglbdtjkblkawzbddwtlubqaeywufsumrdpdqnplkbbgufxnpbnzorynrreimfrmmqyoeafzwbojxwhhdolbphkgvlmchmdigldhuezqzfjtvidytumghmabcfkteqoexthwqnxbcgptkbnpeqntyjbuoxcyuyhtqsoyobwwjtdwhhyqrmpvvmkxkypdhwxdgvtbchlazfqqocrbajgmrlxapyxrovxsmqpvdodmubeqbdtiynsxiqedjzjtfepllnqnkrpmcmonofsohkkhoortpkawelxkshmsntjiqjuoyaixmxgjxbvfcvudwgcplwxbpzwwrrvvvkwbnwjcvarjoalzlwowayjemwvwivzrbcfgygpuavulgextzhycefhynofrjuelxwvopfcgwsrxbdyvlohywororznyotkwapttsylosingsyamtkdhqusfnlxmscplkwnqtxhlsekzfaytimvqnrgsvktlpuynyikaqujebvtblhydaylgryjjmdlixmgwzozdthjtaztemtpsxdiwbsrezxxbkboihfksihjhijmnlyoxqvqiyxljfvetibchojpilqiesdsoqbogrcitvovhpzccopaesuvgucmnyxddtbsziupcjgggecpznasizcavodpbpkvyiyodtnbmbibimbgvxpsmniecjqocfsqbbythsgfeceqjcjsldgkjocdlcqnpadcncwkxmiebsxufrojnurbmhytilzaeyqvnhzasktnqjoxhputvlfvudwkgumncmivfqohmnlzqwuqdbrenphalhgnliszhczwdzbeyafjerlcbnwkhdyvtywxweyayifuyvaslmhwuqhkvdzagwlpxmkanletokiutwwwvenpvbvgrkvhlhjcnowlftylujhujgymdmthtzxlktgqwlvzuaiqynaotesxfkifykzoliyigjyteemoqctqioopreqbhzmivvbyppxejpfwhnimjzcuvmenqxrtzdjtzwxxoueuhlocjjxpjutgzqnefeoicchxvjefvaowfoqtuhvgcowaomymxrhjrzluoqjcaetazqebgntyjejjkcmngnchwcumzufyofvwknntyjwrhqhhvlkskkjibpeadepgzoxuupsnveppjnwmyrftcbgwszzswadhwvfihcrszsjuugoapqokadicoaqrjkejloqiopfgsnedsfmyycbeygeyxtzpaolqiojcjlygvimnlsstwbhnmoynfhpzbgofwjonkeexilaxelmuhwsbktccoqsxypvenresnsacfwrkeogmygrmlipxvgynhcdslbxgmpgkfiaqeypsqqjzwxanordadocuogvelzkcjimxixmfmfqxpjjejqcubzsbjyulfvqanntcjzzefczahymbzltjjqrnbqjemnhbcadeoqyoxodexpnnsbzzceproxyvphvtlopkywarbsimfnqneluhufinphkqlditctcuxuqastcrrnswvixvmebghdujguwcahwckwtdpdmvcjpigntkuidpqagmcbxntbrzxffjtnojcaegzccjsbcxrragmvpmbviodeeebyiwjzfzupavfherelrliwnwtpanvpatoqshhnxkadmlsobazuidlpzbrxaeuyrbhavlnxquccakduxgmhoojnfxrdtboqgsrmzcnemkewikoijzyihzzvkvtoqkpgctzuaikbnapazpgzxbjehkznnknjqimijblgcstzeqythtfmktfzzklzzuavcprqksvzbgamhsitnufmdwfbuordkxzxtzkdjtanhbzvziedslfjiseirpqdvxeeszpmpxwrzcmpganrgywonmogmbflyfjicxogetcnecpclhkzojcxormymhctnoayeldcjijcbhoqwstovljbxcaipvolcufdzwqqgxzjlaljflcmzoelmswojzovveygthojhqbnuyfrcanlcghkankwvjdymtaqxrmaoudzflhiklrfnmhajwawhsdriqlbmoqxheqmnultcgbibwixytapejoawatxpkjxnqdajenpcrftuotsosichttclmapagtqbdmsyqtsuyvmwedxadkpcmmjuafbvcdjmckgnzfjukebbmjiyweqhijegapbtstcykekoinuadbgwvyelfbnmeqbwgmgnahkjmucthzsbhmpnagovukefsmbidqdhbrnkcnmxgcvqrgrftaypckdvbhfbykrpvxbvhutbwgzuuzhiiwmhiscnlkvrcowbadhlafpnhpzlxqbjbantccyqsbqqfpuzeuxerfqzzhfepxwmvrkzmulykeligactsdemdhbpejwstbsolgakvqnxqwuvgxveupabxjqpgsscuehezngajirvbormcqlndzebjovrfbbsqzmcxkqzwftsjixgwcgvvuwebbtaaeltcvjjnxegrjfkygbglzdukomurcooxafsmhopvwlyafdhjtaggxurjivnxbpqzyrwwikmcklbqhpiicjuppteeulhjvtdcruvyqwvhncyvfombcurwnrjliuuusqdusllqyrofqkwkaxmpfzwykhsdbirswmxsfdulkptinezjnqqlkawwcpdrffvoucfgonyrlmuzeqcxcstugutiylztopvpobtqwrdetybaxdlugoqsmqekoltfvuqgkpspecerobbdxgzxhfzowwtodoubrcexbhgekswxdwtdfyattlkojarpxucemqmaujlczaejbwhvkdczkysxkkngekgqbngwkwcrtthkxjqlsipwflmputqiemcwenpnneqkphxxufyultdqnjrfxvrdqkgnplyvoquvbnkrvjrpctrkachffsnppmxmorhqsmsaparcigzivutfaagftzzieuncsrqxtrdejfdeoxfhqcbpownygjnqtxhdrikblerissfyjbsdpvctjbozewdpavtsygwycrxlnfeyqbrpxwgudllqavqdyatvegufwvrwddouvperwzgpbnczbtyymspsmhwfpafsxegmszbbqgvqxmujwwxvywigpvulwoswqerlztjahnmixdxukjoeebsuyeiidwpyezzoemaocholipyopsdxlcwyzmturjjfmerpdhtxfbnpuvlbntkicdbcsmbclxempxlickykdcqjnpbfaawninsgxzuscdzvqbfkdbxbwzoxnnfjnxbcyzguzanlfkaqsrxtuclremmbzgqikthsgmrxbedtjnfikpunlayrbrnzbhjcwxsaldclraokmwyuokyflnaovynwfqgtvpfjvvknpdugxlfswsxycdiqrinwajhisklnmngdevxcteddmfyclujcrpnhxdcttlsjmksxqqthxhclboetikcvrqichbdpraxbvvgsslxzxyxiwzwnmtdufjttojuxjzppjdojmsfnvlxgmnzyblsmsgmhwdxeqivgmjmjahlawumwkrvhvesknfgjuxurhkmrjvgfljicdmqnflzkmopndrxafmocizrysylfeeogxxqektokwrwaledubnvouxbfgnnqwyjnxwwpbtyztqilsvrgrrkneizsowzxxtitzasmeypukpaoquzqbpkhsvdgzxdjvzulkbgvchvlxxpmladpgjtzowytirdclujtpdubkjlunuwpobssbruikqucxwatoxkrhzxxdhnorkxxnbicpjlduxtsintgpggnqqdyozxgtxjbxtvmkbflutvxnwyeimfugazvraotpflrjreccluswdeczsuusehdgotpyydsbddcwlygejsulrmjitbsicvqcjcjwxczmcpzexfvatjrwauoydyogevycynnzhkbyewrmmdsjznoscsetlkqoqeuduolvpsultowbckvmcjdhcqxcrlfmjeyuzggmajgkxeyroqwljrdpwldmjtdvtpbxwojqlzathsylugaawkrxixxjycgvqscwyipawdmpjptlyfnepgnmenzcxdnamoowshrqjbhfqvbobchgomawgygxwahansekufbxeszyrbeakunrrztqduniwvwxdqrfkgagjqjerkqwdxjwmaerqlisesehirvxphavoulunizclengaqjchesbzihffxxybtgdhsnuqrrhitvbojfumejjygvxnirxozlzjaudmazmkayfijdrfhhkkiaiigicnzdyyxvmvwgxkrqekcbdexrhrlhqgvzoavgcfjcnfgkqjmwbwtybkoocleqvdfdjyrzgwphnmdgrziiiiwkqoijtmknkvyazhblcmbyubmytyslzwsxlprruogcqsekezkxlrcifzfegzplfujovlsicyfahgcomespkmkdyobiarqtdpbgazdoyzixfvkuckllxvrfteorxnztweayokpdrdtzrgouzayvvqnloaavupajqbcpxybzmevhgzosmwibdgikfgdjhebsjurysnleryectbvxqhdzvsnvodreandjsigrbrgkxmzidikiyanlwlhdyoheolldrrukdusrvjkvnqpgkmsvjwkrjdyxaavxummrxzteqohopguksvkearehmxhgzbjgwutglmgpydnstvcwroxobqgxknqzdbgfwfzjhqlcpvkwkrvpgehdbjagdxhmmfjhkolzfxujxntldczjqxguqytworlplkhjvdronxvpeppxhqwummbbvwztcrtujsfesgyypsbdfxsacwspdhlpskfyuwjzjgcbyptevrddiudpqyujbqvamxrxwgnpazyljccmvtahbvukppmlhrebqenkmflnjejcnthmjfhvrjvblvwoxywcvpqcayfhlvmxgglpjiirjuwkbizjwzlmqxuuzlwgtughxvvzoxlusrqljvmlsbtqgokrhciauhwhkhudzlykodnzfzwbcphzhjdfxslpqsxgagfslooovcnvzqmeanoftarwvgtcgpitrdovbwdoipaugunqhxtxcxsclyxtivkviegppwchwzkmktpbaqyjbbgdzfnyoikxkozfyrhuewefpisnwpdifskmsqbblaqmmpimhfmugimavinfpnmblxgwhrzjbvenlqmxsdoogafvibfipduhlbyvgsseqvcltxehujnpqmmzmlfxrkynxchlcnwxurlvmyxlszkvvhizdzrocevaajdmvxjcklfmnkfgfxmhwilyvuufofhruldkbjnyioxbmycvianhkwxibstuyalkifbbxgvqqdmnoxnzqmtwrscbqwhkomdwnqmiybheblrxdjoepcfjfvlvavwhrtkssjwymvefsfjvpnmdantohdijttsjyoxnzrbtsqasahfixzxuyukfaisdjbpmqehplvqmnrhknxoegknxdjvsogjjxtxxmrcygafscusnfcvyqvwtyznavhwesftfqhigvqitobtlgqwnftzdrqggfnczjkmohbjxqkyffofprwneogyvivmbfsbahylgrhgsvjcjwhmplpcptcgaxsvbokghgqpuadtpuuhkpguergmrpxgzivvpjbixravudzgycootlzispxmemlouqlhjpqpzzmqxzkcgohuzxxwskfigkpjcgomrombnoomatduneesnykskgkxbkvwanlgqfkarbsybjrgvsnaotmjzicdhcvckxprsllnckgqvmizqnbwaietgscklxtuvsaabrqzmsvxapverzacoibscjvroweqjidblbznmgvlxqvzxgtljpqnwynpiysmtfxksusutzygupyvcysfueucpqwdwarxgbvdpidzehghfotvqirfkkciniiufwaoiofeyxhwvzxiyvvqgcoebufsthvebyvnpeiiyiuyfgyxnfjezrnqjvnectmdwuviloafqadoeeksonmhyijuswaorqanzmiysdehulhvacknxfiihkdpexaqwbuotspxfgezktxmsuhjlggqeumfymcgwrgwfheirhjcxhqrmdregxcbdbmduulhioezmzawyicrstebeylavlqvgmrkhoctyulvbftmrgmdvocfzpgdrwgraichsdbcfovhelpzzxckamfcyvpdkikekekkuzdbsrcuzkpbvqvsxwclmitbnukkqhnjsvarjcwisykresbzuzebeigwehaeeszqzrrpbpvnojvkixselosefhehrkwzvyiahcucfzbygmvjboibqdemtbewieuymcbfsvnddunmqwbwtbbvyqqufebjzlovoumxlfrixakvshorxsbknhvhukcgjaktyjoznpxllrlmljvkqlpqlkdbstpnnlwclqzecnvjmukwakyrgqjgdvmsxgrqpdhgrlgtzuvbctoixkesrdeqwdgebhnusolfhfhiygbomd"; + System.out.println(isAnagram(s, t)); + } + + + /** + * 自己的思路:维护两个hashMap("字符",出现次数) + * 速度击败16.2%,内存击败28.34% + * + * @param s + * @param t + * @return + */ + public boolean isAnagram(String s, String t) { + + HashMap sMap = new HashMap(); + HashMap tMap = new HashMap(); + + for (char c : s.toCharArray()) { + if (sMap.containsKey(c)) { + sMap.put(c, sMap.get(c) + 1L); + } else { + sMap.put(c, 1L); + } + } + + for (char c : t.toCharArray()) { + if (tMap.containsKey(c)) { + tMap.put(c, tMap.get(c) + 1L); + } else { + tMap.put(c, 1L); + } + } + + //防止另一个Map是这个map的子集的情况,避免多for循环一次 + if (sMap.size() != tMap.size()) { + return false; + } + + for (Character character : sMap.keySet()) { + if (tMap.containsKey(character)) { + //这里使用equal方法而不是==, + // 因为无论是Integer还是Long都是包装类型,包装类型首先会缓存-127-128以内的值在一个数组里,在这个范围内==和equal方法等价 + //但是如果超过这个范围,包装类型比较的是内存地址,只有equal方法会先比较类型再比较值大小 + // 也可用longValue()方法,将Long型先转为long型,在用 == 判断是否相等。 + if (!tMap.get(character).equals(sMap.get(character))) { + return false; + } + } else { + return false; + } + } + return true; + } + + /** + * 代码随想录的思路:维护一个26位数组,分别存在a-z各个位置的出现次数 + * 再遍历另一个字符串,将对应的次数减一,如果最后每个位置的次数都是0则是true + * 速度击败100%,内存击败94.94% + * + * @param s + * @param t + * @return + */ + public boolean isAnagram1(String s, String t) { + + int[] nums = new int[26]; + + for (char c : s.toCharArray()) { + nums[c - 'a']++; + } + + for (char c : t.toCharArray()) { + nums[c - 'a']--; + } + + for (int num : nums) { + if (num != 0) { + return false; + } + } + + return true; + + } + + /** + * 官方hashMap的思路:维护一个hashMap("字符",出现次数) + * 速度击败21.88%,内存击败28.17% + * + * @param s + * @param t + * @return + */ + public boolean isAnagram2(String s, String t) { + + if(s.length()!=t.length()){ + return false; + } + + HashMap sMap = new HashMap(); + + for (char c : s.toCharArray()) { + sMap.put(c,sMap.getOrDefault(c,0)+1); + } + + for (char c : t.toCharArray()) { + sMap.put(c,sMap.getOrDefault(c,0)-1); + if(sMap.get(c)!=0){ + return false; + } + } + return true; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hashtable/TwoSum.java b/Leecode/src/main/java/com/markilue/leecode/hashtable/TwoSum.java new file mode 100644 index 0000000..b547e31 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hashtable/TwoSum.java @@ -0,0 +1,123 @@ +package com.markilue.leecode.hashtable; + +import org.junit.Test; + +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.HashMap; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.hashtable + * @Author: dingjiawen + * @CreateTime: 2022-09-07 12:45 + * @Description: + * TODO leecode第1题:两数之和: + * 给定一个整数数组 nums和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标。 + * 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 + * 你可以按任意顺序返回答案。 + + * @Version: 1.0 + */ +public class TwoSum { + + @Test + public void test(){ + + int[] nums = {2, 7, 11, 15}; + int target = 9; + System.out.println(Arrays.toString(twoSum(nums, target))); + + } + + @Test + public void test1(){ + + int[] nums = {3,2,4}; + int target = 6; + System.out.println(Arrays.toString(twoSum(nums, target))); + + } + @Test + public void test2(){ + + int[] nums = {3,3}; + int target = 6; + System.out.println(Arrays.toString(twoSum(nums, target))); + + } + + @Test + public void test3(){ + + int[] nums = {3,2,3}; + int target = 6; + System.out.println(Arrays.toString(twoSum(nums, target))); + + } + + /** + * 自己的思路:维护一个hashMap<数组位置,需要的值> + * 速度击败53.1%,内存击败7.31% + * @param nums + * @param target + * @return + */ + public int[] twoSum(int[] nums, int target) { + + HashMap map = new HashMap<>(); + int[] result=new int[2]; + + for (int i = 0; i < nums.length; i++) { + map.put(target-nums[i],i); + } + + int last=0; + int index=0; + boolean flag=false; + for (int i = 0; i < nums.length; i++) { + if(flag){ + if(nums[i]==last){ + result[0]=i; + result[1]=index; + return result; + } + } + if (map.containsKey(nums[i])) { + //如果进了这里还没有返回,那么可能是两数相等的情况 + flag=true; + last=nums[i]; + index=i; + if(map.get(nums[i])!=map.get(target-nums[i])){ + result[0]=map.get(nums[i]); + result[1]=map.get(target-nums[i]); + return result; + } + + } + } + + return result; + } + + /** + * 官方的思路:维护一个hashMap<数组位置,需要的值>,代码更加简洁,只使用一次循环,避免了很多的重复判断 + * 速度击败73.35%,内存击败54.57% + * @param nums + * @param target + * @return + */ + public int[] twoSum1(int[] nums, int target) { + + HashMap map = new HashMap<>(); + + for (int i = 0; i < nums.length; i++) { + if (map.containsKey(target-nums[i])) { + return new int[]{i,map.get(target-nums[i])}; + } + map.put(nums[i],i); + } + return new int[0]; + + } +} From c9f66d2929f495a75c4b28e765a8425d2b1091dd Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Thu, 8 Sep 2022 09:05:59 +0800 Subject: [PATCH 10/38] =?UTF-8?q?flink=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/day01/scala/Example_scala1.scala | 8 +- .../main/java/day08/selftry/Example10.java | 119 ++++++++++++++++++ 2 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 Big_data_example/Flink/src/main/java/day08/selftry/Example10.java diff --git a/Big_data_example/Flink/src/main/java/day01/scala/Example_scala1.scala b/Big_data_example/Flink/src/main/java/day01/scala/Example_scala1.scala index d18b520..055b11a 100644 --- a/Big_data_example/Flink/src/main/java/day01/scala/Example_scala1.scala +++ b/Big_data_example/Flink/src/main/java/day01/scala/Example_scala1.scala @@ -1,9 +1,9 @@ package day01.scala -import org.apache.flink.api.common.functions.FlatMapFunction -import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator +//import org.apache.flink.api.common.functions.FlatMapFunction +//import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment -import org.apache.flink.util.Collector +//import org.apache.flink.util.Collector object Example_scala1 { @@ -40,7 +40,7 @@ object Example_scala1 { // } // }) // value.print() - env.execute() +// env.execute() // stream.flatMap { // words => { diff --git a/Big_data_example/Flink/src/main/java/day08/selftry/Example10.java b/Big_data_example/Flink/src/main/java/day08/selftry/Example10.java new file mode 100644 index 0000000..a9a3675 --- /dev/null +++ b/Big_data_example/Flink/src/main/java/day08/selftry/Example10.java @@ -0,0 +1,119 @@ +package day08.selftry; + +import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner; +import org.apache.flink.api.common.eventtime.WatermarkStrategy; +import org.apache.flink.api.common.functions.MapFunction; +import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; +import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; +import org.apache.flink.table.api.EnvironmentSettings; +import org.apache.flink.table.api.Table; +import org.apache.flink.table.api.bridge.java.StreamTableEnvironment; + + +import java.sql.Timestamp; + +import static org.apache.flink.table.api.Expressions.$; + +/** + * @BelongsProject: Flink + * @BelongsPackage: day08.selftry + * @Author: dingjiawen + * @CreateTime: 2022-09-07 16:46 + * @Description: TODO example10的自己尝试 pv的Top10 + * @Version: 1.0 + */ +public class Example10 { + + public static void main(String[] args) throws Exception { + + StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); + env.setParallelism(1); + + SingleOutputStreamOperator stream = env.readTextFile("D:\\example\\self_example\\Big_data_example\\Flink\\src\\main\\resources\\UserBehavior.csv") + .map(new MapFunction() { + @Override + public UserBehavior map(String s) throws Exception { + String[] array = s.split(","); + return new UserBehavior(array[0], array[1], array[2], array[3], Long.parseLong(array[4])); + } + }) + .filter(userBehavior -> userBehavior.behavior.equals("pv")) + .assignTimestampsAndWatermarks( + WatermarkStrategy.forMonotonousTimestamps() + .withTimestampAssigner(new SerializableTimestampAssigner() { + @Override + public long extractTimestamp(UserBehavior userBehavior, long l) { + return userBehavior.timeStamp; + } + }) + ); + + //注册表的环境 + EnvironmentSettings settings = EnvironmentSettings.newInstance().inStreamingMode().build(); + StreamTableEnvironment tableEnvironment = StreamTableEnvironment.create(env, settings); + + Table table = tableEnvironment.fromDataStream( + stream, + $("userId"), + $("itemId"), + $("categoryId"), + $("behavior"), + $("timeStamp").rowtime().as("ts") + ); + + tableEnvironment.createTemporaryView("userBehavior",table); + + String countsql="select itemId,COUNT(itemId) as cnt,HOP_END(ts , INTERVAL '5' MINUTE ,INTERVAL '1' HOUR) as end_time " + + "from userBehavior group by itemId,HOP(ts,INTERVAL '5' MINUTE,INTERVAL '1' HOUR)"; + + //开窗求rank + String ranksql="select *,ROW_NUMBER() OVER(PARTITION BY end_time ORDER BY cnt DESC) as rk " + + "FROM ("+countsql+")"; + + //取前三名 + String resultSql = "select * from ("+ranksql+") WHERE rk<=3"; + + Table result = tableEnvironment.sqlQuery(resultSql); + + tableEnvironment.toChangelogStream(result).print(); + env.execute(); + + + } + + /** + * 用户行为POJO类 + */ + public static class UserBehavior { + public String userId; + public String itemId; + public String categoryId; + public String behavior; + public Long timeStamp; + + public UserBehavior() { + + } + + public UserBehavior(String userId, String itemId, String categoryId, String behavior, Long timeStamp) { + this.userId = userId; + this.itemId = itemId; + this.categoryId = categoryId; + this.behavior = behavior; + this.timeStamp = timeStamp; + } + + @Override + public String toString() { + return "UserBehavior{" + + "userId='" + userId + '\'' + + ", itemId='" + itemId + '\'' + + ", categoryId='" + categoryId + '\'' + + ", behavior='" + behavior + '\'' + + ", timeStamp=" + new Timestamp(timeStamp) + + '}'; + } + } + + +} From 84ad855669d486f9148ba7f3c26f0d0c3c440336 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Thu, 8 Sep 2022 09:06:31 +0800 Subject: [PATCH 11/38] =?UTF-8?q?flink=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Big_data_example/Flink/pom.xml | 16 +++++++++++----- .../Flink/src/main/java/day08/Example10.java | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Big_data_example/Flink/pom.xml b/Big_data_example/Flink/pom.xml index 6cd64ca..704c0f1 100644 --- a/Big_data_example/Flink/pom.xml +++ b/Big_data_example/Flink/pom.xml @@ -91,9 +91,6 @@ ${flink.verison} - - - org.slf4j slf4j-log4j12 @@ -127,15 +124,24 @@ ${flink.verison} + + + + + + + + org.apache.bahir - flink-connector-redis_2.11 - 1.0 + flink-connector-redis_2.12 + 1.1.0 + diff --git a/Big_data_example/Flink/src/main/java/day08/Example10.java b/Big_data_example/Flink/src/main/java/day08/Example10.java index dce1421..27a988b 100644 --- a/Big_data_example/Flink/src/main/java/day08/Example10.java +++ b/Big_data_example/Flink/src/main/java/day08/Example10.java @@ -28,7 +28,7 @@ public class Example10 { env.setParallelism(1); SingleOutputStreamOperator stream = env - .readTextFile("E:\\Big_data_example\\Flink\\src\\main\\resources\\UserBehavior.csv") + .readTextFile("D:\\example\\self_example\\Big_data_example\\Flink\\src\\main\\resources\\UserBehavior.csv") .map( new MapFunction() { @Override From 0eb1de8bcf9a485bbfb6162a37d1fc28fa1ab10f Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Thu, 8 Sep 2022 15:47:22 +0800 Subject: [PATCH 12/38] =?UTF-8?q?leecode=E5=93=88=E5=B8=8C=E8=A1=A8?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../markilue/leecode/hashtable/FourSum.java | 180 +++++++++++++++++ .../leecode/hashtable/FourSumCount.java | 186 ++++++++++++++++++ .../markilue/leecode/hashtable/ThreeSum.java | 81 ++++++++ 3 files changed, 447 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/hashtable/FourSum.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hashtable/FourSumCount.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hashtable/ThreeSum.java diff --git a/Leecode/src/main/java/com/markilue/leecode/hashtable/FourSum.java b/Leecode/src/main/java/com/markilue/leecode/hashtable/FourSum.java new file mode 100644 index 0000000..8682409 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hashtable/FourSum.java @@ -0,0 +1,180 @@ +package com.markilue.leecode.hashtable; + +import org.junit.Test; + +import java.util.*; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.hashtable + * @Author: dingjiawen + * @CreateTime: 2022-09-08 12:24 + * @Description: TODO 力扣18题:四数之和 + * 给你一个由 n 个整数组成的数组nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组[nums[a], nums[b], nums[c], nums[d]](若两个四元组元素一一对应,则认为两个四元组重复): + * 1)0 <= a, b, c, d< n + * 2)a、b、c 和 d 互不相同 + * 3)nums[a] + nums[b] + nums[c] + nums[d] == target + * 你可以按 任意顺序 返回答案 。 + * @Version: 1.0 + */ +public class FourSum { + + @Test + public void test() { + int[] nums = {2, 2, 2, 2, 2}; + int target = 8; + System.out.println(fourSum1(nums, target)); + } + + @Test + public void test1() { + int[] nums = {1,0,-1,0,-2,2}; + int target = 0; + System.out.println(fourSum1(nums, target)); + } + + @Test + public void test2() { + int[] nums = {-1,0,1,2,-1,-4}; + int target = -1; + System.out.println(fourSum1(nums, target)); + } + + @Test + public void test3() { + int[] nums = {1,-2,-5,-4,-3,3,3,5}; + int target = -11; + System.out.println(fourSum1(nums, target)); + } + + @Test + public void test4() { + int[] nums = {1000000000,1000000000,1000000000,1000000000}; + int target = -294967296; + System.out.println(1000000000+1000000000); + System.out.println(-294967296-(1000000000+1000000000)); + System.out.println(fourSum1(nums, target)); + } + + + + /** + * 本人思路:这里如果还想使用双指针法,时间复杂度会是O(n^3),考虑还是使用hash法 + * 维护一个hash表<两数之和,list<两数>> 如何避免两数重复? 先排序在加入,但是有出现了问题:虽然不重复,但是会存在覆盖问题 + * 如下面的实现所示 + * + * @param nums + * @param target + * @return + */ + public List> fourSum(int[] nums, int target) { + if (nums.length < 4) { + return new ArrayList<>(); + } + Arrays.sort(nums); + HashMap> map = new HashMap<>(); + + for (int i = 0; i < nums.length; i++) { + if (i > 0 && nums[i] == nums[i - 1]) { + continue; + } + for (int j = i + 1; j < nums.length; j++) { + if (j > i + 1 && nums[j] == nums[j - 1]) { + continue; + } + map.put(nums[i] + nums[j], new ArrayList<>(Arrays.asList(nums[i], nums[j]))); + } + } + + + List> lists = new ArrayList<>(); + + for (int i = 0; i < nums.length; i++) { + if (i > 0 && nums[i] == nums[i - 1]) { + continue; + } + for (int j = i + 1; j < nums.length; j++) { + if (j > i + 1 && nums[j] == nums[j - 1]) { + continue; + } + if (map.containsKey(target - nums[i] - nums[j])) { + map.get(target - nums[i] - nums[j]).add(nums[i]); + map.get(target - nums[i] - nums[j]).add(nums[j]); + lists.add(map.get(target - nums[i] - nums[j])); + map.get(target - nums[i] - nums[j]).remove(3); + map.get(target - nums[i] - nums[j]).remove(4); + } + map.put(nums[i] + nums[j], new ArrayList<>(Arrays.asList(nums[i], nums[j]))); + } + } + + + Collection> values = map.values(); + for (List value : values) { + lists.add(value); + } + + + return lists; + + } + + /** + * 代码思想录思路:还是使用双指针法,在外面在套一层循环,将四数问题转化为3数问题 + * 如下所示 + * 速度超过49.9%,内存超过93.76% + * @param nums + * @param target + * @return + */ + public List> fourSum1(int[] nums, int target) { + if (nums.length < 4) { + return new ArrayList<>(); + } + Arrays.sort(nums); + + List> lists = new ArrayList<>(); + + for (int i = 0; i < nums.length; i++) { + + if (i > 0 && nums[i] == nums[i - 1]) { + continue; + } + for (int j = i + 1; j < nums.length; j++) { + + if (j > i + 1 && nums[j] == nums[j - 1]) { + continue; + } + int mid = j + 1; + int right = nums.length - 1; + + while (mid < right) { + //解决int超过限制的问题 + long sum = (long) nums[i] + nums[j] + nums[mid] + nums[right]; + if (sum < target) { + mid++; + } else if (sum > target) { + right--; + } else { + lists.add(new ArrayList<>(Arrays.asList(nums[i], nums[j], nums[mid], nums[right]))); + while (mid < right && nums[mid] == nums[mid + 1]) { + mid++; + } + while (mid < right && nums[right] == nums[right - 1]) { + right--; + } + mid++; + right--; + } + } + + } + } + + + return lists; + + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hashtable/FourSumCount.java b/Leecode/src/main/java/com/markilue/leecode/hashtable/FourSumCount.java new file mode 100644 index 0000000..398c834 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hashtable/FourSumCount.java @@ -0,0 +1,186 @@ +package com.markilue.leecode.hashtable; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.hashtable + * @Author: dingjiawen + * @CreateTime: 2022-09-08 09:09 + * @Description: + * TODO leecode454题:四数相加II: + * 给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足: + * 1) 0 <= i, j, k, l < n + * 2) nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0 + * @Version: 1.0 + */ +public class FourSumCount { + + + @Test + public void test(){ + + int[] nums1 = {1, 2}; + int[] nums2 = {-2, -1}; + int[] nums3 = {-1, 2}; + int[] nums4 = {0, 2}; + System.out.println(fourSumCount1(nums1, nums2, nums3, nums4)); + + } + + @Test + public void test2(){ + + int[] nums1 = {1, 2}; + int[] nums2 = {-2, -1}; + int[] nums3 = {0, 2}; + int[] nums4 = {0, 2}; + System.out.println(fourSumCount1(nums1, nums2, nums3, nums4)); + + } + + @Test + public void test1(){ + + int[] nums1 = {0}; + int[] nums2 = {0}; + int[] nums3 = {0}; + int[] nums4 = {0}; + System.out.println(fourSumCount1(nums1, nums2, nums3, nums4)); + + } + + + /** + * 自己的思路: + * 1)使用递归来解决,把四数相加转换为三数相加转为两数相加,这种方式时间复杂度直接O(n^4) + * 2)构建两个hash表,分别遍历两个数组,时间复杂度O(n^2) + * 以下是第二种思路,hashset暂时还有问题没有解决,如test2的问题 + * @param nums1 + * @param nums2 + * @param nums3 + * @param nums4 + * @return + */ + public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { + + + //构建一个hash表, + HashSet set1 = new HashSet<>(); + + for (int i = 0; i < nums1.length; i++) { + for (int j = 0; j < nums2.length; j++) { + set1.add(nums1[i]+nums2[j]); + } + } + + + HashSet set2 = new HashSet<>(); + + for (int i = 0; i < nums3.length; i++) { + for (int j = 0; j < nums4.length; j++) { + set2.add(nums3[i]+nums4[j]); + } + } + + int count=0; + for (Integer integer : set1) { + if(set2.contains(0-integer)){ + count++; + } + } + + + return count; + + } + + /** + * 代码思想录的思路: + * 2)构建两个hash表<两数之和,这两数之和出现的次数>,分别遍历两个数组,时间复杂度O(n^2) + * 速度击败20.33%,内存击败13.78% + * @param nums1 + * @param nums2 + * @param nums3 + * @param nums4 + * @return + */ + public int fourSumCount1(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { + + //构建一个hash表<两数之和,这两数之和出现的次数> + HashMap map1 = new HashMap<>(); + + for (int i = 0; i < nums1.length; i++) { + for (int j = 0; j < nums2.length; j++) { + map1.put(nums1[i]+nums2[j],map1.getOrDefault(nums1[i]+nums2[j],0)+1); + } + } + + + HashMap map2 = new HashMap<>(); + + for (int i = 0; i < nums3.length; i++) { + for (int j = 0; j < nums4.length; j++) { + map2.put(nums3[i]+nums4[j],map2.getOrDefault(nums3[i]+nums4[j],0)+1); + } + } + + int count=0; + for (Integer integer : map1.keySet()) { + if(map2.containsKey(0-integer)){ + count+=map1.get(integer)*map2.get(0-integer); + } + } + + + + return count; + + } + + /** + * 官方的思路: + * 2)构建一个hash表<两数之和,这两数之和出现的次数>,分别遍历两个数组,时间复杂度O(n^2) + * 速度击败28.59%,内存击败91.98% 时间空间复杂度均为O(n^2) + * @param nums1 + * @param nums2 + * @param nums3 + * @param nums4 + * @return + */ + public int fourSumCount2(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { + + //构建一个hash表<两数之和,这两数之和出现的次数> + HashMap map1 = new HashMap<>(); + + for (int i = 0; i < nums1.length; i++) { + for (int j = 0; j < nums2.length; j++) { + map1.put(nums1[i]+nums2[j],map1.getOrDefault(nums1[i]+nums2[j],0)+1); + } + } + + int count=0; + + for (int i = 0; i < nums3.length; i++) { + for (int j = 0; j < nums4.length; j++) { + if(map1.containsKey(0-nums3[i]-nums4[j])){ + count+=map1.get(0-nums3[i]-nums4[j]); + } + } + } + + return count; + + } + + + + + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hashtable/ThreeSum.java b/Leecode/src/main/java/com/markilue/leecode/hashtable/ThreeSum.java new file mode 100644 index 0000000..5dcb089 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hashtable/ThreeSum.java @@ -0,0 +1,81 @@ +package com.markilue.leecode.hashtable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.hashtable + * @Author: dingjiawen + * @CreateTime: 2022-09-08 10:49 + * @Description: + * TODO 力扣15题:三数之和: + * 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请 + * 你返回所有和为 0 且不重复的三元组。 + * 注意:答案中不可以包含重复的三元组。 + * @Version: 1.0 + */ +public class ThreeSum { + + /** + * 这道题使用哈希法的思路: + * 使用两层循环,先计算出a+b,最后再遍历一遍找到-a-b的值,最后再进行去重,整体时间复杂度是O(n^2),但是仍然是比较费时的操作,因为去重比较麻烦 + * 这里可以使用双指针法:先对数组进行整体的排序,作为一个有序的数组,使用头尾指针,寻找中间的数据,时间复杂度O(n^2) + * @param nums + * @return + */ + public List> threeSum(int[] nums) { + + if(nums.length<3){ + return new ArrayList<>(); + } + + Arrays.sort(nums); + + List> lists = new ArrayList<>(); + + + for (int left = 0; left < nums.length - 2; left++) { + + if(nums[left]>0){ + break; + } + //避免重复 + if(left>0&&nums[left]==nums[left-1]){ + continue; + } + + //定义尾指针 + int right= nums.length-1; + //定义中间指针 + int mid =left+1; + while (mid0){ + right--; + }else if(sum<0){ + mid++; + }else { + //sum==0 + ArrayList list = new ArrayList<>(Arrays.asList(nums[left],nums[mid],nums[right])); + //判断一下左右避免重复 + while (mid Date: Fri, 9 Sep 2022 15:02:46 +0800 Subject: [PATCH 13/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../markilue/leecode/string/ReverseStr.java | 147 ++++++++++++++++++ .../leecode/string/ReverseString.java | 63 ++++++++ .../markilue/leecode/string/ReverseWords.java | 104 +++++++++++++ 3 files changed, 314 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/string/ReverseStr.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/string/ReverseString.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/string/ReverseWords.java diff --git a/Leecode/src/main/java/com/markilue/leecode/string/ReverseStr.java b/Leecode/src/main/java/com/markilue/leecode/string/ReverseStr.java new file mode 100644 index 0000000..50387ac --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/string/ReverseStr.java @@ -0,0 +1,147 @@ +package com.markilue.leecode.string; + +import org.junit.Test; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.string + * @Author: dingjiawen + * @CreateTime: 2022-09-09 10:16 + * @Description: TODO 力扣541题 反转字符串II: + * 给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。 + * 1)如果剩余字符少于 k 个,则将剩余字符全部反转。 + * 2)如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。 + * @Version: 1.0 + */ +public class ReverseStr { + + @Test + public void test() { + + String s = "abcdefghij"; + int k = 3; + String s1 = reverseStr(s, k); + System.out.println(s1); + + } + + @Test + public void test1() { + + String s = "abcd"; + int k = 2; + String s1 = reverseStr(s, k); + System.out.println(s1); + + } + + @Test + public void test2() { + + String s = "hyzqyljrnigxvdtneasepfahmtyhlohwxmkqcdfehybknvdmfrfvtbsovjbdhevlfxpdaovjgunjqlimjkfnqcqnajmebeddqsgl"; + int k = 39; + String s1 = reverseStr(s, k); + System.out.println(s1); + + } + + @Test + public void test3() { + + String s = "abcdefg"; + int k = 39; + String s1 = reverseStr(s, k); + System.out.println(s1); + + } + + /** + * 本人的思路:fori一下,i步长为2k,2k内部就自己进行交换;for完之后判断i==length还是i 2 * k) { + //留下最后2k以内的范围单独处理,因为要分情况单独处理 + for (; i < chars.length - 2 * k; i += 2 * k) { + int z = i; + //前k个字母反转:i和i+k-1交换 + while (z < i + k / 2) { + exchange(chars, z, i + k - 1 - z + i); + z++; + } + } + } + + //出来以后判断是从什么条件出来的 + if (i >= chars.length - k) { + //剩下的长度= chars.length - 2 * k) { + //剩下的长度<2k + //交换前k个 + int z = i; + while (z < i + k / 2) { + exchange(chars, z, i + k - 1 - z + i); + z++; + } + } + + + String result = ""; + for (char aChar : chars) { + result += aChar; + } + return result; + } + + /** + * 官方的思路:与本人的类似,但是不用留下剩下的做判断,都把他视作交换全部的一部分,只不过是左右范围不同 + * 速度击败100%,内存击败35% + * + * @param s + * @param k + * @return + */ + public String reverseStr1(String s, int k) { + + char[] chars = s.toCharArray(); + //均是交换,只不过是交换的范围不同,这样就可以不用分头处理了 + for (int i = 0; i < chars.length; i += 2 * k) { + reverse(chars,i,Math.min(i+k,chars.length)-1); + } + + return new String(chars); + + } + + public void reverse(char[] chars,int left,int right){ + while (left= 0; i--) { + if (!"".equals(s1[i]) ) { + result += s1[i] + " "; + } + } + + return result.trim(); + + } + + /** + * 速度超过12%,内存超过5% + * @param s + * @return + */ + public String reverseWords1(String s) { + + String[] s1 = s.trim().split(" "); + String result = ""; + for (int i = s1.length - 1; i >= 0; i--) { + if (!"".equals(s1[i]) ) { + if(i==0){ + result += s1[i]; + }else { + result += s1[i] + " "; + } + + } + } + return result; + + } + + /** + * 官方使用API的代码 + * 速度超过12%,内存超过5% + * @param s + * @return + */ + public String reverseWords2(String s) { + + // 除去开头和末尾的空白字符 + s = s.trim(); + // 正则匹配连续的空白字符作为分隔符分割 + List wordList = Arrays.asList(s.split("\\s+")); + Collections.reverse(wordList); + return String.join(" ", wordList); + + + } + + + + + + +} From bb316cd55c040fcceea47ef912a735beb295238a Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Mon, 12 Sep 2022 14:37:24 +0800 Subject: [PATCH 14/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../string/RepeatedSubstringPattern.java | 63 +++++++ .../com/markilue/leecode/string/StrStr.java | 167 ++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/string/RepeatedSubstringPattern.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/string/StrStr.java diff --git a/Leecode/src/main/java/com/markilue/leecode/string/RepeatedSubstringPattern.java b/Leecode/src/main/java/com/markilue/leecode/string/RepeatedSubstringPattern.java new file mode 100644 index 0000000..f5cc458 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/string/RepeatedSubstringPattern.java @@ -0,0 +1,63 @@ +package com.markilue.leecode.string; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.string + * @Author: dingjiawen + * @CreateTime: 2022-09-12 12:15 + * @Description: TODO 力扣459题:重复的子字符串: + * 给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。 + * @Version: 1.0 + */ +public class RepeatedSubstringPattern { + + @Test + public void test() { + String s = "abcabcabc"; + System.out.println(repeatedSubstringPattern(s)); +// int[] next1 = getNext1(s); +// System.out.println(Arrays.toString(next1)); + } + + + /** + * 这一题也可以用经典的KMP算法进行解决,又KMP算法可知:如果string由重复子字符串组成,其next数组一定是前面全是-1,后面全是升序排列 + * 如"abcabcabc",其next数组为[-1, -1, -1, 0, 1, 2, 3, 4, 5],所以规律是最后一个数+1可以整除是-1的数 + * 速度击败74.63%,内存击败10.85% + * @param s + * @return + */ + public boolean repeatedSubstringPattern(String s) { + + int[] next1 = getNext1(s); + + int length = next1.length; + if (next1[length - 1] != -1 && length % (length - next1[length - 1] - 1) == 0) { + return true; + } + + return false; + } + + public int[] getNext1(String needle) { + int[] next = new int[needle.length()]; + next[0] = -1; + int k = -1; + for (int i = 1; i < needle.length(); ++i) { + while (k != -1 && needle.charAt(k + 1) != needle.charAt(i)) { + k = next[k]; + } + if (needle.charAt(k + 1) == needle.charAt(i)) { + ++k; + } + next[i] = k; + } + return next; + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/string/StrStr.java b/Leecode/src/main/java/com/markilue/leecode/string/StrStr.java new file mode 100644 index 0000000..c880ea3 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/string/StrStr.java @@ -0,0 +1,167 @@ +package com.markilue.leecode.string; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.string + * @Author: dingjiawen + * @CreateTime: 2022-09-12 09:01 + * @Description: TODO 力扣28题:实现strStr() + * 实现strStr()函数。 + * 给你两个字符串haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。 + *

+ * 说明: + * 当needle是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 + * 对于本题而言,当needle是空字符串时我们应当返回 0 。这与 C 语言的strstr()以及 Java 的indexOf()定义相符。 + * @Version: 1.0 + */ +public class StrStr { + + @Test + public void test() { + + String haystack = "hello"; + String needle = "ll"; + int i = strStr(haystack, needle); + System.out.println(i); + + } + + @Test + public void test1() { + + String haystack = "aaaaa"; + String needle = "bba"; + int i = strStr(haystack, needle); + System.out.println(i); + + } + + @Test + public void test2() { + + String haystack = "baabbbbababbbabab"; + String needle = "abbab"; + int i = strStr(haystack, needle); + System.out.println(i); + + } + + @Test + public void test3() { + + String haystack = "ababaabbbbababbaabaaabaabbaaaabbabaabbbbbbabbaabbabbbabbbbbaaabaababbbaabbbabbbaabbbbaaabbababbabbbabaaabbaabbabababbbaaaaaaababbabaababaabbbbaaabbbabb"; + String needle = "abbabbbabaa"; + int i = strStr(haystack, needle); + System.out.println(i); + + } + + @Test + public void test4() { + + String haystack = "ababac"; +// String needle = "abbabbbabaa"; + int[] next = getNext1(haystack); + System.out.println(Arrays.toString(next)); + + } + + + /** + * 尝试使用KMP算法:维护一个next数组,存储needle的最小前缀和最小后缀匹配的长度,从而减少从头开始匹配的次数,从而将时间复杂度从O(n*m)降到O(n+m) + * 具体内容参考代码随想录和数据结构与算法之美的讲解内容 + * 速度击败39.11%,内存击败91.79% + * + * @param haystack + * @param needle + * @return + */ + public int strStr(String haystack, String needle) { + int[] next = getNext(needle); + int j = 0; + for (int i = 0; i < haystack.length(); ++i) { + + while (j > 0 && haystack.charAt(i) != needle.charAt(j)) { + j = next[j - 1] + 1; + } + + if (haystack.charAt(i) == needle.charAt(j)) { + ++j; + } + + if (j == needle.length()) { + return i - j + 1; + } + + + } + return -1; + + } + + + public int[] getNext(String needle) { + + int[] result = new int[needle.length()]; + + for (int i = 0; i < needle.length(); i++) { + result[i] = -1; + if (i == 0) { + continue; + } + int right = i; + for (int left = i - 1; left >= 0; left--) { + boolean flag = false; + if (needle.charAt(left) == needle.charAt(right)) { + flag = true; + for (int z = left - 1, k = right - 1; z >= 0; z--, k--) { + if (needle.charAt(z) != needle.charAt(k)) { + flag = false; + break; + } + } + } + if (flag) { + result[i] = left; + break; + } + } + } + return result; + } + + /** + * 官方获取next数组的方法:精髓在于这次的next[i]可以通过上一次的next[i-1]来获取,分为两种情况: + * 1)如果next[i-1]的下一个数和next[i]的下一个数相等,那么最大子串一定是在上一个的基础上+1,对应下面的if的内容 + * 2)如果next[i-1]的下一个数和next[i]的下一个数不相等,那么寻找上一个最大子串,看看上一次最大子串的下一个数和next[i]的下一个数相等,如果不相等就寻找在上一次的,对应于下面的while内容 + * 下所述的看就是用来记录上一次最大子串的索引 + * + * 速度击败39.11%,内存击败73.88% + * 但是只用了1ms + * @param needle + * @return + */ + public int[] getNext1(String needle) { + int[] next = new int[needle.length()]; + next[0] = -1; + int k = -1; + for (int i = 1; i < needle.length(); ++i) { + while (k != -1 && needle.charAt(k + 1) != needle.charAt(i)) { + k = next[k]; + } + if (needle.charAt(k + 1) == needle.charAt(i)) { + ++k; + } + next[i] = k; + } + + return next; + + } + + +} From 806e02d3860f7ebb16d510f18f5ce5e187a23a2c Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Tue, 13 Sep 2022 14:43:06 +0800 Subject: [PATCH 15/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leecode/stackAndDeque/EvalRPN.java | 123 ++++++++++++++++++ .../leecode/stackAndDeque/IsValid.java | 87 +++++++++++++ .../leecode/stackAndDeque/MyQueue.java | 111 ++++++++++++++++ .../leecode/stackAndDeque/MyQueue1.java | 99 ++++++++++++++ .../leecode/stackAndDeque/MyStack.java | 120 +++++++++++++++++ .../leecode/stackAndDeque/MyStack1.java | 95 ++++++++++++++ 6 files changed, 635 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/stackAndDeque/EvalRPN.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/stackAndDeque/IsValid.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyQueue.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyQueue1.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyStack.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyStack1.java diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/EvalRPN.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/EvalRPN.java new file mode 100644 index 0000000..3a176b3 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/EvalRPN.java @@ -0,0 +1,123 @@ +package com.markilue.leecode.stackAndDeque; + +import org.junit.Test; + +import java.util.*; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.stackAndDeque + * @Author: dingjiawen + * @CreateTime: 2022-09-13 12:06 + * @Description: + * TODO 力扣150题 逆波兰表达式求值: + * 根据 逆波兰表示法,求表达式的值。 + * 有效的算符包括+、-、*、/。每个运算对象可以是整数,也可以是另一个逆波兰表达式。 + * 注意两个整数之间的除法只保留整数部分。 + * 可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。 + * @Version: 1.0 + */ +public class EvalRPN { + + @Test + public void test(){ + String[] tokens = {"2", "1", "+", "3", "*"}; + + System.out.println(evalRPN(tokens)); + } + + @Test + public void test1(){ + String[] tokens = {"4","13","5","/","+"}; + + System.out.println(evalRPN(tokens)); + } + + @Test + public void test2(){ + String[] tokens = {"10","6","9","3","+","-11","*","/","*","17","+","5","+"}; + + System.out.println(evalRPN(tokens)); + } + + @Test + public void test3(){ + String[] tokens = {"2", "1", "+", "3", "*"}; + + System.out.println(evalRPN(tokens)); + } + + /** + * 由于没有括号等操作,考虑使用一个stack解决,遇上运算符,就在往前消两栈,计算出的结果再入栈 + * 由于保证了给定的逆波兰表达式总是有效的,所以不需要额外的判断 + * 速度击败55%,内存击败47% + * @param tokens + * @return + */ + public int evalRPN(String[] tokens) { + + Stack stack = new Stack<>(); + + for (String token : tokens) { + if(!token.equals("+")&&!token.equals("-")&&!token.equals("*")&&!token.equals("/")){ + stack.push(Integer.valueOf(token)); + }else { + int num2=stack.pop(); + int num1=stack.pop(); + if(token.equals("+")){ + stack.push(num1+num2); + }else if(token.equals("-")){ + stack.push(num1-num2); + }else if(token.equals("*")){ + stack.push(num1*num2); + }else if(token.equals("/")){ + stack.push(num1/num2); + } + } + } + return stack.pop(); + + + } + + /** + * 官方给的使用数组模拟栈代码 + * @param tokens + * @return + */ + public int evalRPN1(String[] tokens) { + int n = tokens.length; + int[] stack = new int[(n + 1) / 2]; + int index = -1; + for (int i = 0; i < n; i++) { + String token = tokens[i]; + switch (token) { + case "+": + index--; + stack[index] += stack[index + 1]; + break; + case "-": + index--; + stack[index] -= stack[index + 1]; + break; + case "*": + index--; + stack[index] *= stack[index + 1]; + break; + case "/": + index--; + stack[index] /= stack[index + 1]; + break; + default: + index++; + stack[index] = Integer.parseInt(token); + } + } + return stack[index]; + } + + + + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/IsValid.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/IsValid.java new file mode 100644 index 0000000..bce2c3d --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/IsValid.java @@ -0,0 +1,87 @@ +package com.markilue.leecode.stackAndDeque; + +import org.junit.Test; + +import java.util.Stack; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.stackAndDeque + * @Author: dingjiawen + * @CreateTime: 2022-09-13 11:17 + * @Description: TODO 力扣20题 有效的括号: + * 给定一个只包括 '(',')','{','}','[',']'的字符串 s ,判断字符串是否有效。 + *

+ * 有效字符串需满足: + * 左括号必须用相同类型的右括号闭合。 + * 左括号必须以正确的顺序闭合。 + * 每个右括号都有一个对应的相同类型的左括号。 + * @Version: 1.0 + */ +public class IsValid { + @Test + public void test() { + String s = "{([([])])}"; + System.out.println(isValid(s)); + } + + /** + * 速度击败98%,内存击败35.56% + * + * @param s + * @return + */ + public boolean isValid(String s) { + + if (s.length() % 2 != 0) { + return false; + } + + Stack stack = new Stack<>(); + + for (char c : s.toCharArray()) { + if (c == '{' || c == '(' || c == '[') { + stack.push(c); + } + if (c == ')') { + if (stack.size() == 0 || stack.pop() != '(') { + return false; + } + } + if (c == '}') { + if (stack.size() == 0 || stack.pop() != '{') { + return false; + } + } + if (c == ']') { + if (stack.size() == 0 || stack.pop() != '[') { + return false; + } + } + } + if (!stack.empty()) { + return false; + } + return true; + + } + + /* + 某大佬巧妙思路,不过就是效率不高 + 执行用时:47 ms, 在所有 Java 提交中击败了5.62%的用户 + 内存消耗:41.4 MB, 在所有 Java 提交中击败了5.01%的用户 + + */ + public boolean isValid1(String s) { + while (true) { + int l = s.length(); + s = s.replace("()", ""); + s = s.replace("{}", ""); + s = s.replace("[]", ""); + if (s.length() == l) { + return l == 0; + } + } + } + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyQueue.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyQueue.java new file mode 100644 index 0000000..8a50a73 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyQueue.java @@ -0,0 +1,111 @@ +package com.markilue.leecode.stackAndDeque; + +import org.junit.Test; +import org.omg.CORBA.PUBLIC_MEMBER; + +import java.util.Stack; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.stackAndDeque + * @Author: dingjiawen + * @CreateTime: 2022-09-13 09:17 + * @Description: + * TODO 力扣232题 用栈实现队列: + * 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty): + * + * 实现 MyQueue 类: + * void push(int x) 将元素 x 推到队列的末尾 + * int pop() 从队列的开头移除并返回元素 + * int peek() 返回队列开头的元素 + * boolean empty() 如果队列为空,返回 true ;否则,返回 false + * + * 说明: + * 你只能使用标准的栈操作 —— 也就是只有push to top,peek/pop from top,size, 和is empty操作是合法的。 + * 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。 + * + + * @Version: 1.0 + */ +public class MyQueue { + + public Stack stack1; + public Stack stack2; + + public MyQueue() { + stack1=new Stack<>(); + stack2=new Stack<>(); + + } + + /** + * 本人思路: + * stack1维护一个反向的stack,stack2就维护一个正向的stack + * push时只push进stack1,每调用一次pop就将stack1的值push进stack2 + * 速度击败100%,内存击败50% + * 代码随想录与本思路类似,但是他额peek复用了pop(),即pop()之后再添加回去,另外也不需要每次再pop会stack1,具体见MyQueue1 + * @param x + */ + public void push(int x) { + stack1.push(x); + + } + + public int pop() { + + //放入stack2 + while (!stack1.empty()){ + stack2.push(stack1.pop()); + } + //获取结果 + int result=stack2.pop(); + //放回stack1 + while (!stack2.empty()){ + stack1.push(stack2.pop()); + } + //返回结果 + return result; + + } + + public int peek() { + //放入stack2 + while (!stack1.empty()){ + stack2.push(stack1.pop()); + } + //查看结果结果 + int result=stack2.peek(); + //放回stack1 + while (!stack2.empty()){ + stack1.push(stack2.pop()); + } + return result; + } + + public boolean empty() { + return stack1.empty(); + } + + @Test + public void test(){ + MyQueue myQueue = new MyQueue(); + myQueue.push(1); // queue is: [1] + myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue) + System.out.println(myQueue.peek());// return 1 + + System.out.println(myQueue.pop());// return 1, queue is [2] + System.out.println(myQueue.empty());// return false + + } + + +} + +/** + * Your MyQueue object will be instantiated and called as such: + * MyQueue obj = new MyQueue(); + * obj.push(x); + * int param_2 = obj.pop(); + * int param_3 = obj.peek(); + * boolean param_4 = obj.empty(); + */ diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyQueue1.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyQueue1.java new file mode 100644 index 0000000..4240e37 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyQueue1.java @@ -0,0 +1,99 @@ +package com.markilue.leecode.stackAndDeque; + +import org.junit.Test; + +import java.util.Stack; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.stackAndDeque + * @Author: dingjiawen + * @CreateTime: 2022-09-13 09:17 + * @Description: + * TODO 力扣232题 用栈实现队列: + * 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty): + * + * 实现 MyQueue 类: + * void push(int x) 将元素 x 推到队列的末尾 + * int pop() 从队列的开头移除并返回元素 + * int peek() 返回队列开头的元素 + * boolean empty() 如果队列为空,返回 true ;否则,返回 false + * + * 说明: + * 你只能使用标准的栈操作 —— 也就是只有push to top,peek/pop from top,size, 和is empty操作是合法的。 + * 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。 + * + + * @Version: 1.0 + */ +public class MyQueue1 { + + public Stack stack1; + public Stack stack2; + + public MyQueue1() { + stack1=new Stack<>(); + stack2=new Stack<>(); + + } + + /** + * 官方思路: + * 但是他额peek复用了pop(),即pop()之后再添加回去,另外也不需要每次再pop会stack1,具体见MyQueue1 + * 由于充分利用了两个stack,内存利用率大大提高 + * 速度击败100%,内存击败96.07% + * @param x + */ + public void push(int x) { + stack1.push(x); + + } + + public int pop() { + + dumpStack(); + //返回结果 + return stack2.pop(); + + } + + public int peek() { + dumpStack(); + return stack2.peek(); + } + + public boolean empty() { + return stack1.empty()&& stack2.empty(); + } + + private void dumpStack(){ + if(stack2.empty()){ + while (!stack1.empty()){ + stack2.push(stack1.pop()); + } + } + } + + @Test + public void test(){ + MyQueue1 myQueue = new MyQueue1(); + myQueue.push(1); // queue is: [1] + myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue) + System.out.println(myQueue.peek());// return 1 + + System.out.println(myQueue.pop());// return 1, queue is [2] + System.out.println(myQueue.empty());// return false + + } + + +} + +/** + * Your MyQueue object will be instantiated and called as such: + * MyQueue obj = new MyQueue(); + * obj.push(x); + * int param_2 = obj.pop(); + * int param_3 = obj.peek(); + * boolean param_4 = obj.empty(); + */ diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyStack.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyStack.java new file mode 100644 index 0000000..e1b86ae --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyStack.java @@ -0,0 +1,120 @@ +package com.markilue.leecode.stackAndDeque; + +import org.junit.Test; + +import java.util.ArrayDeque; +import java.util.Queue; +import java.util.concurrent.PriorityBlockingQueue; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.stackAndDeque + * @Author: dingjiawen + * @CreateTime: 2022-09-13 09:59 + * @Description: TODO 力扣225题 用队列实现栈: + * 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。 + * 实现 MyStack 类: + * void push(int x) 将元素 x 压入栈顶。 + * int pop() 移除并返回栈顶元素。 + * int top() 返回栈顶元素。 + * boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。 + *

+ *

+ * 注意: + * 你只能使用队列的基本操作 —— 也就是push to back、peek/pop from front、size 和is empty这些操作。 + * 你所使用的语言也许不支持队列。你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列, 只要是标准的队列操作即可。 + * @Version: 1.0 + */ +public class MyStack { + + public Queue queue1; + public Queue queue2; + + + public MyStack() { + queue1 = new ArrayDeque<>(); + queue2 = new ArrayDeque<>(); + } + + /** + * 上述方式是使用两个队列实现栈,事实上还可以使用一个队列实现栈,具体参考MyStack1 + * 速度击败100%,内存击败50% + * @param x + */ + public void push(int x) { + if(queue1.isEmpty()&&queue2.isEmpty()){ + queue1.add(x); + return; + } + + if(queue1.isEmpty()){ + //queue1为空,那么queue2不为空 + queue1.add(x); + while (!queue2.isEmpty()){ + queue1.add(queue2.poll()); + } + }else if(queue2.isEmpty()){ + //queue1为空,那么queue2为空 + queue2.add(x); + while (!queue1.isEmpty()){ + queue2.add(queue1.poll()); + } + } + + + + } + + public int pop() { + if(!queue1.isEmpty()){ + return queue1.poll(); + }else { + return queue2.poll(); + } + + } + + public int top() { + if(!queue1.isEmpty()){ + return queue1.peek(); + }else { + return queue2.peek(); + } + } + + public boolean empty() { + return queue1.isEmpty()&&queue2.isEmpty(); + } + +// public void dumpStack(){ +// if(queue2.isEmpty()){ +// while (!queue1.isEmpty()){ +// queue2.add(queue1.poll()); +// } +// } +// } + + @Test + public void test() { + MyStack obj = new MyStack(); + obj.push(1); + obj.push(2); + obj.push(3); + int param_2 = obj.pop(); + int param_3 = obj.top(); + boolean param_4 = obj.empty(); + + System.out.println(param_2); + System.out.println(param_3); + System.out.println(param_4); + } +} + +/** + * Your MyStack object will be instantiated and called as such: + * MyStack obj = new MyStack(); + * obj.push(x); + * int param_2 = obj.pop(); + * int param_3 = obj.top(); + * boolean param_4 = obj.empty(); + */ diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyStack1.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyStack1.java new file mode 100644 index 0000000..6d93e2e --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MyStack1.java @@ -0,0 +1,95 @@ +package com.markilue.leecode.stackAndDeque; + +import org.junit.Test; + +import java.util.ArrayDeque; +import java.util.Queue; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.stackAndDeque + * @Author: dingjiawen + * @CreateTime: 2022-09-13 09:59 + * @Description: TODO 力扣225题 用队列实现栈: + * 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。 + * 实现 MyStack 类: + * void push(int x) 将元素 x 压入栈顶。 + * int pop() 移除并返回栈顶元素。 + * int top() 返回栈顶元素。 + * boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。 + *

+ *

+ * 注意: + * 你只能使用队列的基本操作 —— 也就是push to back、peek/pop from front、size 和is empty这些操作。 + * 你所使用的语言也许不支持队列。你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列, 只要是标准的队列操作即可。 + * @Version: 1.0 + */ +public class MyStack1 { + + public Queue queue1; + + + public MyStack1() { + queue1 = new ArrayDeque<>(); + } + + /** + * 一个队列实现stack,即先把元素加到队列尾部,然后再把头pop出在添加到尾部即可 + * 速度击败100%,内存击败17% + * + * @param x + */ + public void push(int x) { + int size = queue1.size(); + queue1.offer(x); + while (size-- > 0) { + queue1.offer(queue1.poll()); + } + + + } + + public int pop() { + return queue1.poll(); + } + + public int top() { + return queue1.peek(); + } + + public boolean empty() { + return queue1.isEmpty(); + } + +// public void dumpStack(){ +// if(queue2.isEmpty()){ +// while (!queue1.isEmpty()){ +// queue2.add(queue1.poll()); +// } +// } +// } + + @Test + public void test() { + MyStack1 obj = new MyStack1(); + obj.push(1); + obj.push(2); + obj.push(3); + int param_2 = obj.pop(); + int param_3 = obj.top(); + boolean param_4 = obj.empty(); + + System.out.println(param_2); + System.out.println(param_3); + System.out.println(param_4); + } +} + +/** + * Your MyStack object will be instantiated and called as such: + * MyStack obj = new MyStack(); + * obj.push(x); + * int param_2 = obj.pop(); + * int param_3 = obj.top(); + * boolean param_4 = obj.empty(); + */ From 06d21ded9ba6bae82e9486e05eb4555c57ad2b0b Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Tue, 13 Sep 2022 19:57:45 +0800 Subject: [PATCH 16/38] =?UTF-8?q?=E5=A4=9A=E7=BA=BF=E7=A8=8B=E5=92=8CStrin?= =?UTF-8?q?g=E7=B1=BB=E6=B5=8B=E8=AF=95=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Big_data_example/java_learning/pom.xml | 65 ++++++++++ .../markilue/java_learning/string/Equal.java | 112 ++++++++++++++++++ .../markilue/java_learning/thread/Daemon.java | 42 +++++++ .../java_learning/thread/ThreadDemo1.java | 92 ++++++++++++++ .../com/markilue/leecode/test/Fibonaqi.java | 2 + 5 files changed, 313 insertions(+) create mode 100644 Big_data_example/java_learning/pom.xml create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/string/Equal.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/Daemon.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadDemo1.java diff --git a/Big_data_example/java_learning/pom.xml b/Big_data_example/java_learning/pom.xml new file mode 100644 index 0000000..d5b5d3b --- /dev/null +++ b/Big_data_example/java_learning/pom.xml @@ -0,0 +1,65 @@ + + + 4.0.0 + + com.markilue.java_learning + java_learning + 1.0-SNAPSHOT + + + 8 + 8 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + + + + + + + + + + + org.projectlombok + lombok + 1.18.12 + provided + + + + + junit + junit + 4.13.2 + test + + + junit + junit + 4.13.2 + compile + + + org.projectlombok + lombok + RELEASE + compile + + + + \ No newline at end of file diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/string/Equal.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/string/Equal.java new file mode 100644 index 0000000..f3c7d36 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/string/Equal.java @@ -0,0 +1,112 @@ +package com.markilue.java_learning.string; + +import org.junit.Test; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.string + * @Author: dingjiawen + * @CreateTime: 2022-09-13 18:45 + * @Description: + * TODO 解释string中的==和equal方法,以及string的intern()方法: + * 1)String类型不是基本类型,其构造方法有String s=“”;new String()/new String("")/new String(char[] a)等 + * 2)String由于其不是基本类型,因此使用构造方法new String(“abc”)创建对象,其对象会放在堆中(对象引用放在栈里),"abc"存放在对象的value数组中(源码可知) + * 3)使用String s=“abc”创建的String,由于“abc”是一个不可变常量(在常量池中只会维护一份,并且可以共享),因此"abc"会存在常量池中,s的对象引用也是指向常量池 + * 4) String调用的equal()方法,本身是调用了Object类的equal()方法比较内存,但是String类重写了equal()方法,变成了比较值 + * 4.1)String的intern()方法就是将string放入常量池中,并返回他的索引,如果在常量池中则直接返回他的索引 + * 5)关于拼接和存储问题: + * (1)常量+常量:结果是常量池 + * (2)常量与变量 或 变量与变量:结果是堆 + * (3)拼接后调用intern方法:结果在常量池 + * (4)在初始化时使用String s=new String("abc")+new String("def")进行拼接时,不会马上解析,只有当这个字面量s被调用或者abcdef被调用时,采用创建对应的String实例 + * @Version: 1.0 + */ +public class Equal { + + @Test + public void test1() { + //参考2)、3) + String str1 = "hello"; + String str2 = "hello"; + System.out.println(str1 == str2);//true + + String str3 = new String("hello"); + String str4 = new String("hello"); + System.out.println(str1 == str4); //false + System.out.println(str3 == str4); //false + } + + + @Test + public void test2() { + //参考5)的第三点 + String s1 = "hello"; + String s2 = "world"; + String s3 = "helloworld"; + + String s4 = (s1 + "world").intern();//把拼接的结果放到常量池中 + String s5 = (s1 + s2).intern(); + + System.out.println(s3 == s4);//true + System.out.println(s3 == s5);//true + } + + @Test + public void test05() { + //参考5)的第一点 + //用final修饰存放在常量池中 + final String s1 = "hello"; + final String s2 = "world"; + String s3 = "helloworld"; + + String s4 = s1 + "world";//s4字符串内容也helloworld,s1是常量,"world"常量,常量+ 常量 结果在常量池中 + String s5 = s1 + s2;//s5字符串内容也helloworld,s1和s2都是常量,常量+ 常量 结果在常量池中 + String s6 = "hello" + "world";//常量+ 常量 结果在常量池中,因为编译期间就可以确定结果 + + System.out.println(s3 == s4);//true + System.out.println(s3 == s5);//true + System.out.println(s3 == s6);//true + } + + @Test + public void test04() { + //参考5)的第2点 + String s1 = "hello"; + String s2 = "world"; + String s3 = "helloworld"; + + String s4 = s1 + "world";//s4字符串内容也helloworld,s1是变量,"world"常量,变量 + 常量的结果在堆中 + String s5 = s1 + s2;//s5字符串内容也helloworld,s1和s2都是变量,变量 + 变量的结果在堆中 + String s6 = "hello" + "world";//常量+ 常量 结果在常量池中,因为编译期间就可以确定结果 + + System.out.println(s3 == s4);//false + System.out.println(s3 == s5);//false + System.out.println(s3 == s6);//true + } + + @Test + public void test03() { + //参考5)的第4点 存疑?现在运行好像是false + String s1 = new String("1"); + s1.intern(); + String s2 = "1"; + System.out.println(s1 == s2);//false + + String s3 = new String("1") + new String("1"); + s3.intern(); + String s4 = "11"; + System.out.println(s3 == s4);//true =>现在运行好像是false了? + } + + @Test + public void test07() { + //参考5)的第4点 + String s1 = new String("mark") + new String("ilue"); //这一步会将mark和ilue放入常量池中 + s1.intern(); //这里拼接的字符串markilue被调用,将markilue放入常量池中,这时才返回markilue索引给s1 + String s2=new StringBuilder("marki").append("lue").toString(); //这里将marki和lue放入常量池中,然后在toString中被调用,所以创建markilue的String对象(存放在堆中),然后返回这个堆索引 + System.out.println(s1 == s2);//false 这里一个是返回的在堆对象中的索引,一个是返回的在常量池中的索引,因此不相等 + System.out.println(s1 == s2.intern());//true 这里调用intern()方法后获取到了在常量池中的索引,因此两者相等 + } + + +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/Daemon.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/Daemon.java new file mode 100644 index 0000000..59ca1aa --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/Daemon.java @@ -0,0 +1,42 @@ +package com.markilue.java_learning.thread; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.thread + * @Author: dingjiawen + * @CreateTime: 2022-09-13 19:54 + * @Description: + * TODO 守护线程: + * 有一种线程,它是在后台运行的,它的任务是为其他线程提供服务的,这种线程被称为“守护线程”。JVM的垃圾回收线程就是典型的守护线程。 + * 守护线程有个特点,就是如果所有非守护线程都死亡,那么守护线程自动死亡。 + * 调用setDaemon(true)方法可将指定线程设置为守护线程。必须在线程启动之前设置,否则会报IllegalThreadStateException异常。 + * 调用isDaemon()可以判断线程是否是守护线程。 + * @Version: 1.0 + */ +public class Daemon { + + public static void main(String[] args) { + MyDaemon m = new MyDaemon(); + m.setDaemon(true); + m.start(); + + for (int i = 1; i <= 100; i++) { + System.out.println("main:" + i); + } + } + + public static class MyDaemon extends Thread { + public void run() { + while (true) { + System.out.println("我一直守护者你..."); + try { + Thread.sleep(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadDemo1.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadDemo1.java new file mode 100644 index 0000000..5d62249 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadDemo1.java @@ -0,0 +1,92 @@ +package com.markilue.java_learning.thread; + +import java.util.Scanner; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning + * @Author: dingjiawen + * @CreateTime: 2022-09-13 18:32 + * @Description: + * TODO 多线程尝试强行加塞: + * Thread.sleep方法使得线程沉睡,等到了指定时间,重新开始执行 + * Thread.start方法使得线程开始执行 + * Thread,join方法等待该线程终止。只有终止程序才会继续往下执行 + * @Version: 1.0 + */ +public class ThreadDemo1 { + + public static void main(String[] args) { + ChatThread t = new ChatThread(); + t.start(); + + for (int i = 1; i < 10; i++) { + System.out.println("main:" + i); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + //当main打印到5之后,需要等join进来的线程停止后才会继续了。 + if(i==5){ + try { + t.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + /* + 实现的结果: + main:1 + main:2 + main:3 + main:4 + main:5 + 是否结束?(Y、N) + y + main:6 + main:7 + main:8 + main:9 + + + =========================================== + 第二次结果: + main:1 + main:2 + 是否结束?(Y、N) + main:3 + main:4 + main:5 + n + 是否结束?(Y、N) + n + 是否结束?(Y、N) + y + main:6 + main:7 + main:8 + main:9 + */ + } + + public static class ChatThread extends Thread{ + public void run(){ + Scanner input = new Scanner(System.in); + while(true){ + System.out.println("是否结束?(Y、N)"); + char confirm = input.next().charAt(0); + if(confirm == 'Y' || confirm == 'y'){ + break; + } + } + input.close(); + } + } + + + + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/test/Fibonaqi.java b/Leecode/src/main/java/com/markilue/leecode/test/Fibonaqi.java index 4cf42d6..e9cfa0e 100644 --- a/Leecode/src/main/java/com/markilue/leecode/test/Fibonaqi.java +++ b/Leecode/src/main/java/com/markilue/leecode/test/Fibonaqi.java @@ -1,5 +1,7 @@ package com.markilue.leecode.test; +import java.text.SimpleDateFormat; + public class Fibonaqi { From 26376573fb9adf9e67f9c85288092eb036f638e4 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Thu, 15 Sep 2022 15:15:46 +0800 Subject: [PATCH 17/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stackAndDeque/MaxSlidingWindow.java | 331 ++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MaxSlidingWindow.java diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MaxSlidingWindow.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MaxSlidingWindow.java new file mode 100644 index 0000000..0b2144e --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MaxSlidingWindow.java @@ -0,0 +1,331 @@ +package com.markilue.leecode.stackAndDeque; + +import org.junit.Test; + +import java.util.*; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.stackAndDeque + * @Author: dingjiawen + * @CreateTime: 2022-09-14 09:31 + * @Description: TODO 力扣239题 滑动窗口最大值: + * 给你一个整数数组 nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k个数字。滑动窗口每次只向右移动一位。 + * 返回 滑动窗口中的最大值 。 + * @Version: 1.0 + */ +public class MaxSlidingWindow { + + + @Test + public void test() { + int[] nums = {1, 3, -1, -3, -5, -7, -9, 5, 3, 6, 7}; + int k = 3; + int[] ints = maxSlidingWindow(nums, k); + System.out.println(Arrays.toString(ints));//[3, 3, -1, -3, -5, 5, 5, 6, 7] + } + + @Test + public void test1() { + int[] nums = {1, 3, -1, -3, -5, -3, -9, 5, 3, 6, 7};//[3, 3, -1, -3, -3, 5, 5, 6, 7] + int k = 3; + int[] ints = maxSlidingWindow3(nums, k); + System.out.println(Arrays.toString(ints)); + } + + @Test + public void test4() { + int[] nums = {1, 3, -1, -3, -3, -3, -9, 5, 3, 6, 7};//[3, 3, -1, -3, -3, 5, 5, 6, 7] + int k = 3; + int[] ints = maxSlidingWindow(nums, k); + System.out.println(Arrays.toString(ints)); + } + + @Test + public void test2() { + int[] nums = {1, 3, -1, -3, 5, 3, 6, 7}; + int k = 3; + int[] ints = maxSlidingWindow(nums, k); + System.out.println(Arrays.toString(ints));//[3, 3, 5, 5, 6, 7] + } + + @Test + public void test3() { + int[] nums = {1}; + int k = 1; + int[] ints = maxSlidingWindow(nums, k); + System.out.println(Arrays.toString(ints));//[1] + } + + @Test + public void test5() { + int[] nums = {1, 3, 1, 2, 0, 5}; + int k = 3; + int[] ints = maxSlidingWindow4(nums, k); + System.out.println(Arrays.toString(ints));//[3, 3, 2, 5] + } + + @Test + public void test6() { + int[] nums = {7,2,4}; + int k = 2; + int[] ints = maxSlidingWindow3(nums, k); + System.out.println(Arrays.toString(ints));//[3, 3, 2, 5] + } + + + /** + * 本人思路:滑动窗口看似需要知道全部的值,实际上只需要知道连续增大的数及其他的索引即可: + * 例如[1,3,-1,-3,5,3,6,7] ,事实上真正重要的信息是[1,3,5,6,7]以及他们的索引[0,1,4,6,7] + * 可以发现的是这个数是否被使用可以看其索引和左右的差值 如(1-0)+(4-1-1)=3 (3+1)-3+1=2所以3使用2次;同理,(4-1-1)+(6-4-1)=3 (3+1)-3+1=2所以5使用2次 + * 其中添加了太多逻辑判断,导致逻辑混乱,目前还有问题 + * + * @param nums + * @param k + * @return + */ + public int[] maxSlidingWindow(int[] nums, int k) { + + //使用一个栈,用于存放进来的数据 + Stack stack = new Stack<>(); + + boolean flag = false; + int lastIndex = 0; + //记录stack栈顶的数的索引 + int index = 0; + for (int i = 0; i < nums.length; i++) { + if (stack.empty()) { + stack.push(nums[i]); + //被迫放的,将flag改一下 + flag = true; + index = i; + continue; + } + //一个数与栈顶元素的索引之差大于3,那么就把他固化下来,并且把他的下一个元素放进去,并设置flag + if (i - index >= k && flag) { + //将flag设置回来 +// flag=true; +// index=i-k; + lastIndex = index; + stack.push(nums[i - k + 1]); + //再把flag设置回去 + index = i - k + 1; + } + + if (nums[i] >= stack.peek() && !flag) { + //前面的数是想要的数 + lastIndex = index; + stack.push(nums[i]); + index = i; + continue; + } else if (nums[i] >= stack.peek() && flag) { + //前面的数不是想要的数 + stack.pop(); + + if (stack.empty() || stack.peek() < nums[i]) { + lastIndex = index; + flag = false; + } + index = i; + stack.push(nums[i]); +// lastIndex=index; + + + continue; + } + + if (nums[i] < stack.peek() && !flag) { + //栈顶元素想要,再放一次 + stack.push(stack.peek()); + //这个元素可能要,所以放一下 + lastIndex = index; + stack.push(nums[i]); + index = i; + flag = true; + continue; + } else if (nums[i] < stack.peek() && flag && index - lastIndex + (i - index) + 1 > k) { + //中间的数是大数,但是没有上一次的大,但是已经达到范围了,就将这个数设置成想要的 + flag = false; + } + + } + + int[] result = new int[nums.length - k + 1]; + + for (int i = result.length - 1; i >= 0; i--) { + result[i] = stack.pop(); + } + + + return result; + + } + + + /** + * 官方使用优先队列完成的做法:时间复杂度O(nlogn) + * 对于「最大值」,我们可以想到一种非常合适的数据结构,那就是优先队列(堆),其中的大根堆可以帮助我们实时维护一系列元素中的最大值。 + * 对于本题而言,初始时,我们将数组 nums 的前 kk 个元素放入优先队列中。每当我们向右移动窗口时,我们就可以把一个新的元素放入优先队列中,此时堆顶的元素就是堆中所有元素的最大值。然而这个最大值可能并不在滑动窗口中,在这种情况下,这个值在数组 nums 中的位置出现在滑动窗口左边界的左侧。因此,当我们后续继续向右移动窗口时,这个值就永远不可能出现在滑动窗口中了,我们可以将其永久地从优先队列中移除。 + * 我们不断地移除堆顶的元素,直到其确实出现在滑动窗口中。此时,堆顶元素就是滑动窗口中的最大值。为了方便判断堆顶元素与滑动窗口的位置关系,我们可以在优先队列中存储二元组(num,index),表示元素 num 在数组中的下标为 index。 + *

+ * TODO 本质上就是维护一个可以比较大小的优先队列,队列中存放(值,索引) + * 当遍历到索引等于这个队列中第一个数的索引时,就把第一个数弹出去,每次遍历都peek第一个数,则就是最大的数 + * 遍历数组复杂度O(n),将元素放入优先队列O(logn),因此时间复杂度O(nlogn) + * @param nums + * @param k + * @return + */ + public int[] maxSlidingWindow1(int[] nums, int k) { + int n = nums.length; + PriorityQueue pq = new PriorityQueue(new Comparator() { + public int compare(int[] pair1, int[] pair2) { + return pair1[0] != pair2[0] ? pair2[0] - pair1[0] : pair2[1] - pair1[1]; + } + }); + //先构建窗口大小的优先队列 + for (int i = 0; i < k; ++i) { + pq.offer(new int[]{nums[i], i}); + } + int[] ans = new int[n - k + 1]; + ans[0] = pq.peek()[0]; + for (int i = k; i < n; ++i) { + pq.offer(new int[]{nums[i], i}); + //如果索引小于等于这个队列中第一个数的索引,就弹出这个数,因为这个数已经越界了 + while (pq.peek()[1] <= i - k) { + pq.poll(); + } + ans[i - k + 1] = pq.peek()[0]; + } + return ans; + } + + /** + * 官方使用单调队列的做法:时间复杂度O(n) + * 由于我们需要求出的是滑动窗口的最大值,如果当前的滑动窗口中有两个下标 i 和 j,其中 i 在 j 的左侧(i < j),并且 ii 对应的元素不大于 jj 对应的元素(nums[i]≤nums[j]),那么会发生什么呢? + * 当滑动窗口向右移动时,只要 i 还在窗口中,那么 j 一定也还在窗口中,这是 i 在 j 的左侧所保证的。因此,由于 nums[j] 的存在,nums[i] 一定不会是滑动窗口中的最大值了,我们可以将 nums[i] 永久地移除。 + * 因此我们可以使用一个队列存储所有还没有被移除的下标。在队列中,这些下标按照从小到大的顺序被存储,并且它们在数组 nums 中对应的值是严格单调递减的。因为如果队列中有两个相邻的下标,它们对应的值相等或者递增,那么令前者为 ii,后者为 jj,就对应了上面所说的情况,即 nums[i] 会被移除,这就产生了矛盾。 + * 当滑动窗口向右移动时,我们需要把一个新的元素放入队列中。为了保持队列的性质,我们会不断地将新的元素与队尾的元素相比较,如果前者大于等于后者,那么队尾的元素就可以被永久地移除,我们将其弹出队列。我们需要不断地进行此项操作,直到队列为空或者新的元素小于队尾的元素。 + * 由于队列中下标对应的元素是严格单调递减的,因此此时队首下标对应的元素就是滑动窗口中的最大值。但与方法一中相同的是,此时的最大值可能在滑动窗口左边界的左侧,并且随着窗口向右移动,它永远不可能出现在滑动窗口中了。因此我们还需要不断从队首弹出元素,直到队首元素在窗口中为止。 + * 为了可以同时弹出队首和队尾的元素,我们需要使用双端队列。满足这种单调性的双端队列一般称作「单调队列」。 + *

+ * TODO 实际理念就是:维护一个两端都可以操作的队列(这个队列是单调的) + * 1)在一个窗口中,如果一个数组的左边元素比右边元素小,那么他就永远不会被用到,那么将它从队列的尾部移除 + * 2)如果在右边,但是比他小,那么他可能被用到,则加在队列的尾部 + * 3) 那么根据1)和2)可以得到一个单调递减的队列了,队列最前面一定是最大的元素 + * 4)通过每次i++之后都会result数组都会赋值一次,保证进来的数一定是窗口里的数,永远维护着窗口 + * + * @param nums + * @param k + * @return + */ + public int[] maxSlidingWindow2(int[] nums, int k) { + int n = nums.length; + Deque deque = new LinkedList(); + //先构建第一个窗口 + for (int i = 0; i < k; ++i) { + while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) { + deque.pollLast(); + } + deque.offerLast(i); + } + + int[] ans = new int[n - k + 1]; + ans[0] = nums[deque.peekFirst()]; + //由于i每+1,ans都会赋值一个元素,因此进来的数永远在窗口里,不存在把队列里的数全挪完了,窗口数也超过的情况 + for (int i = k; i < n; ++i) { + //移除比他小的元素 + while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) { + deque.pollLast(); + } + deque.offerLast(i); + //移除过期元素 + while (deque.peekFirst() <= i - k) { + deque.pollFirst(); + } + ans[i - k + 1] = nums[deque.peekFirst()]; + } + return ans; + } + + + /** + * 自己尝试实现一次官方单调队列(双端队列)的做法 + * 速度超过66%,内存超过90% + */ + public int[] maxSlidingWindow3(int[] nums, int k) { + + int n = nums.length; + Deque deque = new LinkedList<>(); + + //创建第一个窗口 + for (int i = 0; i < k; i++) { + while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) { + deque.removeLast(); + } + deque.offerLast(i); + } + + //创建结果 + int[] result = new int[n - k + 1]; + //将第一个窗口的结果赋值给result + result[0] = nums[deque.peekFirst()]; + for (int i = k; i < n; i++) { + //如果新来的数比这个数大,就把他移除 + while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) { + deque.removeLast(); + } + deque.offerLast(i); + //移除过期元素 + while (deque.peekFirst() <= i - k) { + deque.removeFirst(); + } + //将最前面的数赋值给结果 + result[i - k + 1] = nums[deque.peekFirst()]; + } + + return result; + + + } + + + /** + * 官方分块+预处理法:时间复杂度O(n) + * + * TODO 实际上就是将数据分头处理; + * 1)窗口两端的一定是可以被窗口长度整除的,这些数单独跟窗口两端的进行比较 + * 2)不在窗口两端的则需要在窗口前缀和窗口后缀中找到最大值,在取前缀和后缀中的最大值,就可以得到那个位置上的最大值 + * 3)因此根据2)可以提前从前往后遍历和从后往前遍历,分别获取到最大值 + * @param nums + * @param k + * @return + */ + public int[] maxSlidingWindow4(int[] nums, int k) { + int n = nums.length; + int[] prefixMax = new int[n]; + int[] suffixMax = new int[n]; + for (int i = 0; i < n; ++i) { + if (i % k == 0) { + prefixMax[i] = nums[i]; + } + else { + prefixMax[i] = Math.max(prefixMax[i - 1], nums[i]); + } + } + for (int i = n - 1; i >= 0; --i) { + if (i == n - 1 || (i + 1) % k == 0) { + suffixMax[i] = nums[i]; + } else { + suffixMax[i] = Math.max(suffixMax[i + 1], nums[i]); + } + } + + int[] ans = new int[n - k + 1]; + for (int i = 0; i <= n - k; ++i) { + ans[i] = Math.max(suffixMax[i], prefixMax[i + k - 1]); + } + return ans; + } + + +} From 9afc59fc65a8f591b03178be802d1148ac172aa2 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Fri, 16 Sep 2022 12:51:56 +0800 Subject: [PATCH 18/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stackAndDeque/MaxSlidingWindow.java | 2 +- .../leecode/stackAndDeque/TopKFrequent.java | 129 ++++++++++++++++++ 2 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 Leecode/src/main/java/com/markilue/leecode/stackAndDeque/TopKFrequent.java diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MaxSlidingWindow.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MaxSlidingWindow.java index 0b2144e..0573eae 100644 --- a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MaxSlidingWindow.java +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/MaxSlidingWindow.java @@ -165,7 +165,7 @@ public class MaxSlidingWindow { /** * 官方使用优先队列完成的做法:时间复杂度O(nlogn) * 对于「最大值」,我们可以想到一种非常合适的数据结构,那就是优先队列(堆),其中的大根堆可以帮助我们实时维护一系列元素中的最大值。 - * 对于本题而言,初始时,我们将数组 nums 的前 kk 个元素放入优先队列中。每当我们向右移动窗口时,我们就可以把一个新的元素放入优先队列中,此时堆顶的元素就是堆中所有元素的最大值。然而这个最大值可能并不在滑动窗口中,在这种情况下,这个值在数组 nums 中的位置出现在滑动窗口左边界的左侧。因此,当我们后续继续向右移动窗口时,这个值就永远不可能出现在滑动窗口中了,我们可以将其永久地从优先队列中移除。 + * 对于本题而言,初始时,我们将数组 nums 的前 k 个元素放入优先队列中。每当我们向右移动窗口时,我们就可以把一个新的元素放入优先队列中,此时堆顶的元素就是堆中所有元素的最大值。然而这个最大值可能并不在滑动窗口中,在这种情况下,这个值在数组 nums 中的位置出现在滑动窗口左边界的左侧。因此,当我们后续继续向右移动窗口时,这个值就永远不可能出现在滑动窗口中了,我们可以将其永久地从优先队列中移除。 * 我们不断地移除堆顶的元素,直到其确实出现在滑动窗口中。此时,堆顶元素就是滑动窗口中的最大值。为了方便判断堆顶元素与滑动窗口的位置关系,我们可以在优先队列中存储二元组(num,index),表示元素 num 在数组中的下标为 index。 *

* TODO 本质上就是维护一个可以比较大小的优先队列,队列中存放(值,索引) diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/TopKFrequent.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/TopKFrequent.java new file mode 100644 index 0000000..3eae9a6 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/TopKFrequent.java @@ -0,0 +1,129 @@ +package com.markilue.leecode.stackAndDeque; + +import org.junit.Test; + +import java.util.*; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.stackAndDeque + * @Author: dingjiawen + * @CreateTime: 2022-09-16 09:24 + * @Description: TODO 力扣347题 前k个高频元素 + * 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 + * @Version: 1.0 + */ +public class TopKFrequent { + + + @Test + public void test() { + int[] nums = {1, 1, 1, 2, 2, 3}; + int k = 2; + int[] result = topKFrequent1(nums, k); + System.out.println(Arrays.toString(result)); + } + + @Test + public void test1() { + int[] nums = {1}; + int k = 1; + int[] result = topKFrequent(nums, k); + System.out.println(Arrays.toString(result)); + } + + + /** + * 自己的思路一:先给nums排序,那么相同的数一定在临近,然后遍历一遍获取count, ->如果使用数组进行记录则数组大小跟nums里最大的数有关,这里使用优先队列进行记录 + * 整体时间复杂度O(nlogn),因为排序O(nlogn),遍历一遍O(n),放入优先队列O(logn) + * 速度击败99.59%,内存击败13.35% + * + * @param nums + * @param k + * @return + */ + public int[] topKFrequent(int[] nums, int k) { + + Arrays.sort(nums); + + int lastNum = nums[0]; + int count = 0; + //使用优先队列记录 + PriorityQueue deque = new PriorityQueue<>(new Comparator() { + @Override + public int compare(int[] nums1, int[] nums2) { + return nums1[1] != nums2[1] ? nums2[1] - nums1[1] : nums2[0] - nums1[0]; + } + }); + + for (int i = 0; i < nums.length; i++) { + if (nums[i] == lastNum) { + count += 1; + } + if (nums[i] != lastNum) { + deque.offer(new int[]{lastNum, count}); + count = 1; + lastNum = nums[i]; + } + //如果是最后一个数了,那就直接放 + if (i == nums.length - 1) { + deque.offer(new int[]{nums[i], count}); + } + } + int[] result = new int[k]; + for (int i = 0; i < k; i++) { + result[i] = deque.poll()[0]; + } + + return result; + + } + + + /** + * 官方思路:不用先排序,直接用map装,装完以后遍历map,用一个小顶堆维护一个大小为k的堆,少于k直接装,大于k就和堆顶元素比 + * map装复杂度O(n),取map O(1),堆大小只有k,所以堆化操作复杂度O(logk)个,所以最后时间复杂度O(nlogk) + * 速度超过94.94%,内存超过25.05% + */ + public int[] topKFrequent1(int[] nums, int k) { + + HashMap map = new HashMap<>(); + + for (int num : nums) { + map.put(num, map.getOrDefault(num, 0) + 1); + } + + //创建一个小顶堆 + PriorityQueue deque = new PriorityQueue<>(new Comparator() { + @Override + public int compare(int[] nums1, int[] nums2) { + return nums1[1] - nums2[1]; + } + }); + + for (Map.Entry entry : map.entrySet()) { + Integer num = entry.getKey(); + Integer count = entry.getValue(); + + if(deque.size()deque.peek()[1]){ + deque.poll(); + deque.offer(new int[]{num,count}); + } + } + } + + int[] result = new int[k]; + for (int i = 0; i < k; i++) { + result[i]=deque.poll()[0]; + } + + return result; + + + } + + +} From dfa5a3299cd0183e13d542e9c788049859de7e97 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Fri, 16 Sep 2022 17:32:23 +0800 Subject: [PATCH 19/38] =?UTF-8?q?=E5=A4=9A=E7=BA=BF=E7=A8=8B=E5=AD=A6?= =?UTF-8?q?=E4=B9=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java_learning/thread/DeadLock.java | 84 +++++++++++ .../thread/ThreadCommunicate.java | 141 ++++++++++++++++++ .../thread/ThreadCommunicate1.java | 130 ++++++++++++++++ .../java_learning/thread/ThreadDemo1.java | 1 + .../java_learning/thread/ThreadSafe.java | 80 ++++++++++ .../java_learning/thread/ThreadSafe1.java | 106 +++++++++++++ 6 files changed, 542 insertions(+) create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/DeadLock.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadCommunicate.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadCommunicate1.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadSafe.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadSafe1.java diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/DeadLock.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/DeadLock.java new file mode 100644 index 0000000..42bb8b1 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/DeadLock.java @@ -0,0 +1,84 @@ +package com.markilue.java_learning.thread; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.thread + * @Author: dingjiawen + * @CreateTime: 2022-09-16 17:27 + * @Description: + * TODO 死锁问题: + * 不同的线程分别锁住对方需要的同步监视器对象不释放,都在等待对方先放弃时就形成了线程的死锁。 + * 一旦出现死锁,整个程序既不会发生异常,也不会给出任何提示,只是所有线程处于阻塞状态,无法继续。 + * @Version: 1.0 + */ +public class DeadLock { + + public static void main(String[] args) { + Object g = new Object(); + Object m = new Object(); + //两个人彼此都需要对方的同步锁释放才能运行下面的同步锁内容,但是对方都没有释放锁的操作 + Owner s = new Owner(g,m); + Customer c = new Customer(g,m); + new Thread(s).start(); + new Thread(c).start(); + + /* + 先给钱 + 先发货 + */ + } + + + public static class Owner implements Runnable{ + private Object goods; + private Object money; + + public Owner(Object goods, Object money) { + super(); + this.goods = goods; + this.money = money; + } + + @Override + public void run() { + synchronized (goods) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("先给钱"); + synchronized (money) { + System.out.println("发货"); + } + } + } + } + + + public static class Customer implements Runnable{ + private Object goods; + private Object money; + + public Customer(Object goods, Object money) { + super(); + this.goods = goods; + this.money = money; + } + + @Override + public void run() { + synchronized (money) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("先发货"); + synchronized (goods) { + System.out.println("再给钱"); + } + } + } + } +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadCommunicate.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadCommunicate.java new file mode 100644 index 0000000..34caaa6 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadCommunicate.java @@ -0,0 +1,141 @@ +package com.markilue.java_learning.thread; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.thread + * @Author: dingjiawen + * @CreateTime: 2022-09-16 16:05 + * @Description: + * TODO 线程之间的通信: + * 当线程之间彼此额操作具有先后顺序,比如线程A做包子,线程B吃包子,需要在A做完以后B在做时,两个线程之间需要怎么进行通信呢? ->等待唤醒机制 + * 等待唤醒机制:就是在一个线程进行了规定操作后,就进入等待状态wait(), 等待其他线程执行完他们的指定代码过后 再将其唤醒notify(); + * 在有多个线程进行等待时, 如果需要,可以使用 notifyAll()来唤醒所有的等待线程。wait/notify 就是线程间的一种协作机制。 + * 1) wait:线程不再活动,不再参与调度,进入 wait set 中,因此不会浪费 CPU 资源,也不会去竞争锁了,这时的线程状态即是 WAITING。它还要等着别的线程执行一个特别的动作,也即是“通知(notify)”在这个对象上等待的线程从wait set 中释放出来,重新进入到调度队列(ready queue)中 + * 2) notify:则选取所通知对象的 wait set 中的一个线程释放; + * 3) notifyAll:则释放所通知对象的 wait set 上的全部线程。 + * 需要注意的是:并不是notify以后就一定直接从wait的地方恢复运行,而是需要看是否存在同步锁的竞争问题,只有不存在或者其他线程的该同步锁代码运行完,才恢复 + * 如果能获取锁,线程就从 WAITING 状态变成 RUNNABLE(可运行) 状态; + * 否则,线程就从 WAITING 状态又变成 BLOCKED(等待锁) 状态 + * 还需要注意的是: + * 1. wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。 + * 2. wait方法与notify方法是属于Object类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。 + * 3. wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这2个方法。 + * @Version: 1.0 + */ +public class ThreadCommunicate { + + public static void main(String[] args) { + //等待唤醒案例 + BaoZi bz = new BaoZi(); + + //这里使用同一个bz,同时在同步锁中也是加入bz,以此保证注意1、2、3 + ChiHuo ch = new ChiHuo("吃货",bz); + BaoZiPu bzp = new BaoZiPu("包子铺",bz); + + ch.start(); + bzp.start(); + + /* + 包子铺开始做包子 + 包子造好了:厚皮牛肉大葱 + 吃货来吃吧 + 吃货正在吃:厚皮,牛肉大葱包子 + 包子铺开始做包子 + 包子造好了:薄皮蟹黄灌汤 + 吃货来吃吧 + 吃货正在吃:薄皮,蟹黄灌汤包子 + 包子铺开始做包子 + 包子造好了:厚皮牛肉大葱 + 吃货来吃吧 + 吃货正在吃:厚皮,牛肉大葱包子 + 包子铺开始做包子 + */ + } + + + + + + public static class BaoZi { + String pier ; + String xianer ; + boolean flag = false ;//包子资源 是否准备好 包子资源状态 + } + + public static class ChiHuo extends Thread{ + private BaoZi bz; + + public ChiHuo(String name,BaoZi bz){ + super(name); + this.bz = bz; + } + @Override + public void run() { + while(true){ + synchronized (bz){ + if(bz.flag == false){//没包子 + try { + bz.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + System.out.println("吃货正在吃:"+bz.pier+","+bz.xianer+"包子"); + bz.flag = false; + bz.notify(); + } + } + } + } + + public static class BaoZiPu extends Thread { + + private BaoZi bz; + + public BaoZiPu(String name,BaoZi bz){ + super(name); + this.bz = bz; + } + + @Override + public void run() { + int count = 0; + //造包子 + while(true){ + //同步 + synchronized (bz){ + if(bz.flag == true){//包子资源 存在 + try { + bz.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + // 没有包子 造包子 + System.out.println("包子铺开始做包子"); + if(count%2 == 0){ + // 薄皮 蟹黄包 + bz.pier = "薄皮"; + bz.xianer = "蟹黄灌汤"; + }else{ + // 厚皮 牛肉大葱 + bz.pier = "厚皮"; + bz.xianer = "牛肉大葱"; + } + count++; + + bz.flag=true; + System.out.println("包子造好了:"+bz.pier+bz.xianer); + System.out.println("吃货来吃吧"); + //唤醒等待线程 (吃货) + bz.notify(); + } + } + } + } + + + +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadCommunicate1.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadCommunicate1.java new file mode 100644 index 0000000..ef674e3 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadCommunicate1.java @@ -0,0 +1,130 @@ +package com.markilue.java_learning.thread; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.thread + * @Author: dingjiawen + * @CreateTime: 2022-09-16 16:05 + * @Description: + * TODO 线程之间的通信:等待唤醒机制之多对多问题:生产者消费者问题 + * 案例:有家餐馆的取餐口比较小,只能放10份快餐,厨师做完快餐放在取餐口的工作台上,服务员从这个工作台取出快餐给顾客。现在有多个厨师和多个服务员。 + * @Version: 1.0 + */ +public class ThreadCommunicate1 { + + public static void main(String[] args) { + Workbench bench = new Workbench(); + Cook c1 = new Cook("大拿",bench); + Cook c2 = new Cook("吉祥",bench); + Waiter w1 = new Waiter("翠花",bench); + Waiter w2 = new Waiter("如意",bench); + + c1.start(); + c2.start(); + w1.start(); + w2.start(); + /* + 大拿厨师制作了一份快餐,现在工作台上有:1份快餐 + 大拿厨师制作了一份快餐,现在工作台上有:2份快餐 + 大拿厨师制作了一份快餐,现在工作台上有:3份快餐 + 大拿厨师制作了一份快餐,现在工作台上有:4份快餐 + 大拿厨师制作了一份快餐,现在工作台上有:5份快餐 + 如意服务员取走了一份快餐,现在工作台上有:4份快餐 + 如意服务员取走了一份快餐,现在工作台上有:3份快餐 + 翠花服务员取走了一份快餐,现在工作台上有:2份快餐 + 吉祥厨师制作了一份快餐,现在工作台上有:3份快餐 + 吉祥厨师制作了一份快餐,现在工作台上有:4份快餐 + 吉祥厨师制作了一份快餐,现在工作台上有:5份快餐 + 翠花服务员取走了一份快餐,现在工作台上有:4份快餐 + 翠花服务员取走了一份快餐,现在工作台上有:3份快餐 + 翠花服务员取走了一份快餐,现在工作台上有:2份快餐 + 翠花服务员取走了一份快餐,现在工作台上有:1份快餐` + */ + + } + + public static class Workbench { + private static final int MAX_VALUE = 10; + private int num; + public synchronized void put() { + while(num >= MAX_VALUE){ + try { + this.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + try { + Thread.sleep(100); + //加入睡眠时间是放大问题现象,去掉同步和wait等,可观察问题 + } catch (InterruptedException e) { + e.printStackTrace(); + } + num++; + System.out.println(Thread.currentThread().getName()+ "厨师制作了一份快餐,现在工作台上有:" + num + "份快餐"); + this.notifyAll(); + } + public synchronized void take() { + while(num <=0){ + try { + this.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + try { + Thread.sleep(100); + //加入睡眠时间是放大问题现象,去掉同步和wait等,可观察问题 + } catch (InterruptedException e) { + e.printStackTrace(); + } + num--; + System.out.println(Thread.currentThread().getName()+"服务员取走了一份快餐,现在工作台上有:" + num + "份快餐"); + this.notifyAll(); + } + } + + + public static class Waiter extends Thread{ + private Workbench workbench; + + public Waiter(String name,Workbench workbench) { + super(name); + this.workbench = workbench; + } + + public void run(){ + for (int i = 1; i <= 10; i++) { + workbench.take(); + } + } + } + + + public static class Cook extends Thread{ + private Workbench workbench; + + public Cook(String name,Workbench workbench) { + super(name); + this.workbench = workbench; + } + + public void run(){ + for (int i = 1; i <= 10; i++) { + workbench.put(); + } + } + } + + + + + + + + + + + + +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadDemo1.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadDemo1.java index 5d62249..eed5161 100644 --- a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadDemo1.java +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadDemo1.java @@ -30,6 +30,7 @@ public class ThreadDemo1 { //当main打印到5之后,需要等join进来的线程停止后才会继续了。 if(i==5){ try { + //join以后,如果这个线程不停,程序就不会往下运行,所以start是开始运行,join以后是必须等他运行完再往后运行 t.join(); } catch (InterruptedException e) { e.printStackTrace(); diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadSafe.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadSafe.java new file mode 100644 index 0000000..6b82211 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadSafe.java @@ -0,0 +1,80 @@ +package com.markilue.java_learning.thread; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.thread + * @Author: dingjiawen + * @CreateTime: 2022-09-16 14:42 + * @Description: + * TODO 线程安全问题演示: + * 电影院要卖票,我们模拟电影院的卖票过程。假设要播放的电影是 “葫芦娃大战奥特曼”,本次电影的座位共100个 + * (本场电影只能卖100张票)。 + * 我们来模拟电影院的售票窗口,实现多个窗口同时卖 “葫芦娃大战奥特曼”这场电影票(多个窗口一起卖这100张票) + * + * + * @Version: 1.0 + */ +public class ThreadSafe { + + public static void main(String[] args) { + // 创建线程任务对象 + Ticket ticket = new Ticket(); + // 创建三个窗口对象 + Thread t1 = new Thread(ticket, "窗口1"); + Thread t2 = new Thread(ticket, "窗口2"); + Thread t3 = new Thread(ticket, "窗口3"); + // 同时卖票 + t1.start(); + t2.start(); + t3.start(); + /* + 线程安全问题在于:多个线程在操作同一个共享变量时,可能出现多重篡改的问题 + 窗口1正在卖:5 + 窗口3正在卖:4 + 窗口2正在卖:5 + 窗口2正在卖:3 + 窗口3正在卖:1 + 窗口1正在卖:2 + */ + } + + + //第一步 创建资源类,在资源类中定义属性和方法 + public static class Ticket implements Runnable { + private int ticket = 100; + + //第二步,在资源操作方法中进行判断和干活 + private void saleTicket(){ + + + + + if (ticket > 0) { // 有票可以卖 + // 出票操作 + // 使用sleep模拟一下出票时间 + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + // 获取当前线程对象的名字 + String name = Thread.currentThread().getName(); + System.out.println(name + "正在卖:" + ticket--); + }else { + + } + } + + /* + * 执行卖票操作 + */ + @Override + public void run() { + // 每个窗口卖票的操作 + // 窗口永远开启 + while (true) { + saleTicket(); + } + } + } +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadSafe1.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadSafe1.java new file mode 100644 index 0000000..431d3b8 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/ThreadSafe1.java @@ -0,0 +1,106 @@ +package com.markilue.java_learning.thread; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.thread + * @Author: dingjiawen + * @CreateTime: 2022-09-16 14:52 + * @Description: TODO 线程安全问题演示: + * 第二种情况演示 :使用一个static变量ticket来作为共享变量,放入常量池中,因此new ticket操作的都是同一个ticket变量 + *

+ * TODO 解决线程安全问题的方法:同步代码块或者同步方法或者锁机制(暂时不管) + * 1)同步代码块: + * synchronized (需要锁住的东西如 ThreadSafe1.class){需要锁的代码 +* } + * 2)同步方法: + * 在方法名前加synchronized关键字 + * 如public synchronized void method(){ + * 可能会产生线程安全问题的代码 + * } + * 同步方法的锁对象: + * (1)静态方法:当前类的Class对象 + * (2)非静态方法:this + * 所以当需要创建多个对象时,需要锁住的方法必须使用static关键字 + * @Version: 1.0 + */ +public class ThreadSafe1 { + + public static void main(String[] args) { + + Ticket t1 = new Ticket("窗口一"); + Ticket t2 = new Ticket("窗口二"); + Ticket t3 = new Ticket("窗口三"); + + t1.start(); + t2.start(); + t3.start(); + /* + 窗口一正在卖:10 + 窗口二正在卖:10 + 窗口三正在卖:9 + 窗口一正在卖:7 + 窗口二正在卖:8 + 窗口三正在卖:5 + 窗口一正在卖:4 + 窗口二正在卖:6 + 窗口二正在卖:3 + 窗口三正在卖:3 + 窗口一正在卖:3 + 窗口三正在卖:1 + 窗口二正在卖:0 + 窗口一正在卖:2 + + 加了同步代码块以后,连顺序都是对的: + 窗口二正在卖:47 + 窗口二正在卖:46 + 窗口二正在卖:45 + 窗口三正在卖:44 + 窗口三正在卖:43 + 窗口三正在卖:42 + 窗口一正在卖:41 + */ + } + + + public static class Ticket extends Thread { + private static int ticket = 100; + + public Ticket() { + super(); + } + + public Ticket(String name) { + super(name); + } + + /* + * 执行卖票操作 + */ + @Override + public void run() { + // 每个窗口卖票的操作 + // 窗口永远开启 + while (true) { + + synchronized (Ticket.class) { //这里不能选用this作为锁,因为这几个线程的this不是同一个,如果是同一个ticket对象才可以使用 + + if (ticket > 0) { // 有票可以卖 + // 出票操作 + // 使用sleep模拟一下出票时间 + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + // 获取当前线程对象的名字 + System.out.println(getName() + "正在卖:" + ticket--); + } else { + break; + } + + } + + } + } + } +} From 67b46dbcac909b15206dfe8921fbeec76d810a54 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Fri, 16 Sep 2022 17:34:51 +0800 Subject: [PATCH 20/38] =?UTF-8?q?=E5=A4=9A=E7=BA=BF=E7=A8=8B=E5=AD=A6?= =?UTF-8?q?=E4=B9=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java_learning/thread/sleepAndWait.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/sleepAndWait.java diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/sleepAndWait.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/sleepAndWait.java new file mode 100644 index 0000000..0af0910 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/thread/sleepAndWait.java @@ -0,0 +1,17 @@ +package com.markilue.java_learning.thread; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.thread + * @Author: dingjiawen + * @CreateTime: 2022-09-16 17:33 + * @Description: + * TODO sleep()和wait()的区别 + * (1)sleep()不释放锁,wait()释放锁 + * (2)sleep()指定休眠的时间,wait()可以指定时间也可以无限等待直到notify或notifyAll + * (3)sleep()在Thread类中声明的静态方法,wait方法在Object类中声明 + * 因为我们调用wait()方法是由锁对象调用,而锁对象的类型是任意类型的对象。那么希望任意类型的对象都要有的方法,只能声明在Object类中。 + * @Version: 1.0 + */ +public class sleepAndWait { +} From 82812f32ff1deea7120e1e71969140b26e5a600d Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Sun, 18 Sep 2022 12:39:18 +0800 Subject: [PATCH 21/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../markilue/leecode/stackAndDeque/Trap.java | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/stackAndDeque/Trap.java diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/Trap.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/Trap.java new file mode 100644 index 0000000..5f39a12 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/Trap.java @@ -0,0 +1,199 @@ +package com.markilue.leecode.stackAndDeque; + +import org.junit.Test; + +import java.util.Deque; +import java.util.LinkedList; +import java.util.PriorityQueue; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.stackAndDeque + * @Author: dingjiawen + * @CreateTime: 2022-09-18 09:14 + * @Description: TODO 力扣42题 接雨水: + * 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 + * @Version: 1.0 + */ +public class Trap { + + + @Test + public void test() { + int[] height = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}; + System.out.println(trap3(height)); + } + + + @Test + public void test1() { + int[] height = {4, 2, 0, 3, 2, 5}; + System.out.println(trap2(height)); + } + + @Test + public void test2() { + int[] height = {5, 4, 1, 2}; + System.out.println(trap2(height)); + } + + @Test + public void test3() { + int[] height = {5, 5, 1, 3}; + System.out.println(trap3(height)); + } + + @Test + public void test4() { + int[] height = {2, 0, 1, 1, 0, 1, 3, 2, 1, 2, 1}; + System.out.println(trap3(height)); + } + + + /** + * 自己的思路:这题和滑动窗口的题非常相似,都是需要记录在右边比他小的值,如果右边的比他大则出栈 + * 因此仍然使用一个双端队列(单调队列)进行遍历,遇上下一个比他大的就出栈,则接雨水数就等于索引之差 + * 速度击败30.41%,内存击败71.84% + * + * @param height + * @return + */ + public int trap(int[] height) { + + //int[元素,索引] + Deque deque = new LinkedList<>(); + + //记录上一次出栈的高度 + int lastHeight = 0; + int result = 0; + boolean flag = false; + + for (int i = 0; i < height.length; i++) { + while (deque.size() != 0 && deque.peek()[0] <= height[i]) { + int[] poll = deque.poll(); + //高度乘以宽度=蓄水量 =>(i-poll[1]-1)索引之差即宽度;这次出栈的高度-lastHeight即高度 + result += (i - poll[1] - 1) * (poll[0] - lastHeight); + lastHeight = poll[0]; + flag = true; + } + //防止在内部时,不出站计算不了对应的雨水量的情况 + //这里使用flag记录是否进入过上面的接雨水环节,如果接过雨水还没出栈完,那么计算那部分的雨水量 + //这里使用if即可,因为flag出来以后一定遇上的是比他大的第一个数 + if (deque.size() != 0 && flag && height[i] > lastHeight) { + int[] peek = deque.peek(); + //高度乘以宽度=蓄水量 =>(i-poll[1]-1)索引之差即宽度;这次这次高度-lastHeight即高度 + result += (i - peek[1] - 1) * (height[i] - lastHeight); + } + flag = false; + deque.push(new int[]{height[i], i}); + } + + return result; + + } + + + /** + * 官方动态规划解法:只要记录左边柱子的最高高度和右边柱子的最高高度,就可以计算当前位子的雨水面积 + * TODO 当前位置的雨水面积: [min(左边柱子的最高高度,右边柱子的最高高度)-当前柱子高度]*单位宽度 + * 因此可以分别将左右两边柱子的最高高度分别记录在两个数组maxLeft和maxRight中,这时就用到了动态规划 + * 精髓在于当前位置的雨水面积的计算方式 + * 时间复杂度O(n),空间复杂度O(n) + * 速度超过76.2%,内存超过79.9% + * + * @param height + * @return + */ + public int trap2(int[] height) { + + int n = height.length; + int[] maxLeft = new int[n]; + + maxLeft[0] = height[0]; + + for (int i = 1; i < n; i++) { + maxLeft[i] = Math.max(height[i], maxLeft[i - 1]); + } + int[] maxRight = new int[n]; + + maxRight[n - 1] = height[n - 1]; + + for (int i = n - 2; i >= 0; i--) { + maxRight[i] = Math.max(height[i], maxRight[i + 1]); + } + + int result = 0; + for (int i = 0; i < n; i++) { + result += Math.min(maxLeft[i], maxRight[i]) - height[i]; + } + + return result; + } + + + /** + * 官方单调栈解法:使用一个单调栈维护一个单调递减的栈,栈顶元素小于栈低元素,栈中存放索引 + * 栈中必须要有两个元素才会有凹槽,才能接雨水 + * 速度击败39.81%,内存击败86.4% + * @param height + * @return + */ + public int trap3(int[] height) { + + int n = height.length; + + Deque deque = new LinkedList<>(); + + int result=0; + + for (int i = 0; i < n; i++) { + while (!deque.isEmpty() && height[i] > height[deque.peek()]) { + int top=deque.pop(); + if(deque.isEmpty()){ + //栈中必须有两个元素才会有凹槽 + break; + } + int left=deque.peek(); + int currWidth = i - left - 1; + int currHeight = Math.min(height[left], height[i]) - height[top]; + result += currWidth * currHeight; + } + deque.push(i); + } + + return result; + + + } + + + /** + * 官方进阶双指针法:思路是动态规划法为基础,同时将空间复杂度降到了O(1) + * 注意到下标 i 处能接的雨水量由 leftMax[i] 和 rightMax[i] 中的最小值决定。 + * 由于数组 leftMax 是从左往右计算,数组 rightMax 是从右往左计算,因此可以使用双指针和两个变量代替两个数组。 + * + * TODO 精髓在于:如果左边比右边的小,那么就算左边的高度,因为右边比左边大了,那么左边的水一定可以蓄起来;反之亦然 + * 速度超过100%,内存超过18.38% + */ + public int trap4(int[] height) { + + int ans = 0; + int left = 0, right = height.length - 1; + int leftMax = 0, rightMax = 0; + while (left < right) { + leftMax = Math.max(leftMax, height[left]); + rightMax = Math.max(rightMax, height[right]); + if (height[left] < height[right]) { + //如果左边的小,那么左边的水一定可以蓄起来,那么就计算左边的水 + ans += leftMax - height[left]; + ++left; + } else { + ans += rightMax - height[right]; + --right; + } + } + return ans; + + } + +} From 571f1185f565a38c0a01788a0c78d11daca041b0 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Sun, 18 Sep 2022 17:16:35 +0800 Subject: [PATCH 22/38] =?UTF-8?q?=E9=9B=86=E5=90=88List,Set=E5=AD=A6?= =?UTF-8?q?=E4=B9=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../collection/CollectionCommonFunction.java | 92 ++++++ .../java_learning/collection/Iterable.java | 110 +++++++ .../java_learning/collection/ListTest.java | 88 ++++++ .../java_learning/collection/MyArrayList.java | 57 ++++ .../java_learning/collection/SetTest.java | 268 ++++++++++++++++++ 5 files changed, 615 insertions(+) create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/CollectionCommonFunction.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/Iterable.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/ListTest.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/MyArrayList.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/SetTest.java diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/CollectionCommonFunction.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/CollectionCommonFunction.java new file mode 100644 index 0000000..d3c7fa6 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/CollectionCommonFunction.java @@ -0,0 +1,92 @@ +package com.markilue.java_learning.collection; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.collection + * @Author: dingjiawen + * @CreateTime: 2022-09-18 14:34 + * @Description: + * TODO collection的addAll,add,retainAll方法: + * 1)addAll(另一个集合)方法会将单个元素都加进去 + * 2)add(另一个集合)方法会将其作为一个整体加入 + * 3)retainAll(另一个集合)方法会将两个集合的交集保留下来,其他的丢弃 =>注意:不是返回一个新集合,而是改变原来的集合 + * @Version: 1.0 + */ +public class CollectionCommonFunction { + + + //addAll + @Test + public void test2(){ + Collection coll = new ArrayList(); + coll.add(1); + coll.add(2); + + System.out.println("coll集合元素的个数:" + coll.size()); //2 + + Collection other = new ArrayList(); + other.add(1); + other.add(2); + other.add(3); + + coll.addAll(other); +// coll.add(other); + System.out.println("coll集合元素的个数:" + coll.size()); //5 + + for (Object o : coll) { + System.out.println(o);// 1 2 1 2 3 + } + } + + //add + @Test + public void test3(){ + Collection coll = new ArrayList(); + coll.add(1); + coll.add(2); + + System.out.println("coll集合元素的个数:" + coll.size()); //2 + + Collection other = new ArrayList(); + other.add(1); + other.add(2); + other.add(3); + + coll.add(other); +// coll.add(other); + System.out.println("coll集合元素的个数:" + coll.size()); //3 + + for (Object o : coll) { + System.out.println(o);// 1 2 [1 2 3] + } + } + + //retainAll + @Test + public void test5(){ + Collection coll = new ArrayList(); + coll.add(1); + coll.add(2); + coll.add(3); + coll.add(4); + coll.add(5); + System.out.println("coll集合元素的个数:" + coll.size());//5 + + Collection other = new ArrayList(); + other.add(1); + other.add(2); + other.add(8); + + coll.retainAll(other);//保留交集 + System.out.println("coll集合元素的个数:" + coll.size());//2 + + for (Object o : coll) { + System.out.println(o); //1 2 + } + } +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/Iterable.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/Iterable.java new file mode 100644 index 0000000..ebb301b --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/Iterable.java @@ -0,0 +1,110 @@ +package com.markilue.java_learning.collection; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.collection + * @Author: dingjiawen + * @CreateTime: 2022-09-18 14:50 + * @Description: + * TODO iterator是一个可迭代接口,collection对象都实现了这个接口(java.util.Iterator) + * 1)其使用方法是:首先通过调用集合的iterator()方法获得迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素,如果存在,则调用next()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。 + * 内部是通过迭代器获取索引实现的:在调用Iterator的next方法之前,迭代器的索引位于第一个元素之前,不指向任何元素,当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next方法时,迭代器的索引会指向第二个元素并将该元素返回,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。 + * 2)可以通过iterable对collection里的元素进行删除,相比于.remove()方法的好处是通过iterable的方式可以加上条件判断 =>使用方式iterator.remove + * 3)未实现java.util.Iterator的类如果想实现foreach等增强for循环的方式,可以去实现java.lang.Iterable接口,具体方式见MyArrayList类 + * 4)快速失败(fail-fast)机制: 在调用iterator方法获取迭代器操作时调用迭代器自身以外的方法对集合中的结构进行改变,如调用list.add()或remove()方法,否则会报错ConcurrentModificationException。 + * 注意,迭代器的快速失败行为不能得到保证,一般来说,存在不同步的并发修改时,不可能作出任何坚决的保证。快速失败迭代器尽最大努力抛出 `ConcurrentModificationException`。 + * 因此,编写依赖于此异常的程序的方式是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测 bug + * 实现方式:1)在ArrayList等集合类中都有一个modCount变量。它用来记录集合的结构被修改的次数。 + * 2)当我们给集合添加和删除操作时,会导致modCount++。 + * 3)然后当我们用Iterator迭代器遍历集合时,创建集合迭代器的对象时,用一个变量记录当前集合的modCount。 + * 例如:`int expectedModCount = modCount;`,并且在迭代器每次next()迭代元素时,都要检查 `expectedModCount != modCount`, + * 如果不相等了,那么说明你调用了Iterator迭代器以外的Collection的add,remove等方法,修改了集合的结构,使得modCount++,值变了,就会抛出ConcurrentModificationException。 + * @Version: 1.0 + */ +public class Iterable { + + //测试iterator.remove方法 + @Test + public void test02(){ + Collection coll = new ArrayList<>(); + coll.add("陈琦"); + coll.add("李晨"); + coll.add("邓超"); + coll.add("黄晓明"); + + //删除名字有三个字的 +// coll.remove(o)//无法编写 + + Iterator iterator = coll.iterator(); + while(iterator.hasNext()){ + String element = iterator.next(); + if(element.length()==3){ +// coll.remove(element);//错误的 + iterator.remove(); + } + } + System.out.println(coll); + } + + + //测试继承了java.lang.Iterator的MyArrayList类 + @Test + public void test(){ + MyArrayList my = new MyArrayList(); + my.add("hello"); + my.add("java"); + my.add("world"); + my.add("atguigu"); + my.add("list"); + my.add("data"); + + + for (String string : my) { + System.out.println(string); + } + } + + @Test + public void test01() { + Collection list = new ArrayList<>(); + list.add("hello"); + list.add("java"); + list.add("atguigu"); + list.add("world"); + + Iterator iterator = list.iterator(); + while(iterator.hasNext()){ + list.remove(iterator.next()); + } + } + + @Test + public void test03() { + ArrayList list = new ArrayList<>(); + list.add("hello"); + list.add("java"); + list.add("atguigu"); + list.add("world"); + + //以下代码没有发生ConcurrentModificationException异常 + Iterator iterator = list.iterator(); + while(iterator.hasNext()){ + String str = iterator.next(); + + if("atguigu".endsWith(str)){ + list.remove(str); + } + } + } + + + +} + diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/ListTest.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/ListTest.java new file mode 100644 index 0000000..aefa425 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/ListTest.java @@ -0,0 +1,88 @@ +package com.markilue.java_learning.collection; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.collection + * @Author: dingjiawen + * @CreateTime: 2022-09-18 15:57 + * @Description: + * TODO List的实现类:ArrayList,Vector,LinkedList + * 1)ArrayList: + * 1.数据存储的结构是数组结构。元素增删慢,查找快; + * 2.发生扩容时,ArrayList扩容为原来的1.5倍; + * 3.初始化为长度为0的空数组,之后在添加第一个元素时,再创建长度为10的数组。 + * 2)Vector: + * 1.底层也用的是数组结构,线程安全,效率低; + * 2.发生扩容时,Vector扩容为原来的2倍; + * 3.初始容量默认为10 + * 4.支持Enumeration 迭代器。但是该迭代器不支持快速失败。面对并发的修改,迭代器很快就完全失败 + * 3)LinkedList: + * 1.数据存储的结构是链表结构(双向链表)。方便元素添加、删除的集合。 + * 2.LinkedList还实现了Deque接口。为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。 + * 3.Stack与LinkedList都能作为栈结构,对外表现的功能效果是一样,但是它们的物理结构不同,Stack的物理结构是顺序结构的数组,而LinkedList的物理结构是链式结构的双向链表。我们推荐使用LinkedList。 + * 4.每种方法都存在两种形式:一种形式在操作失败时抛出异常(add,remove,get),另一种形式返回一个特殊值(null 或 false,具体取决于操作)(offer,poll,peek)。 + * + * 4)ListTest 集合额外提供了一个 listIterator() 方法,该方法返回一个 ListIterator 对象, ListIterator 接口继承了 Iterator 接口,提供了专门操作 ListTest 的方法: + * @Version: 1.0 + */ +public class ListTest { + + + //LinkedList作为栈;使用addFirst和removeFirst方法 + @Test + public void test(){ + LinkedList list = new LinkedList<>(); + //入栈 + list.addFirst(1); + list.addFirst(2); + list.addFirst(3); + + //出栈: LIFO(后进先出) + System.out.println(list.removeFirst());//3 + System.out.println(list.removeFirst());//2 + System.out.println(list.removeFirst());//1 + //栈空了,会报异常java.util.NoSuchElementException + System.out.println(list.removeFirst()); + } + + //LinkedList作为队列;使用addLast和pollFirst方法 + @Test + public void test1(){ + LinkedList list = new LinkedList<>(); + //入队 + list.addLast(1); //或者使用offerLast + list.addLast(2); + list.addLast(3); + + //出队, FIFO(先进先出) + System.out.println(list.pollFirst());//1 //或者使用removeFirst + System.out.println(list.pollFirst());//2 + System.out.println(list.pollFirst());//3 + //队空了,返回null + System.out.println(list.pollFirst());//null + } + + + //测试List中的listIterator迭代器方法 + @Test + public void test2(){ + List c = new ArrayList(); + c.add("张三"); + c.add("李四"); + c.add("王五"); + + //从指定位置往前遍历 + ListIterator listIterator = c.listIterator(c.size()); + while(listIterator.hasPrevious()){ + String previous = listIterator.previous(); + System.out.println(previous); + } + } +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/MyArrayList.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/MyArrayList.java new file mode 100644 index 0000000..b8aa4d8 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/MyArrayList.java @@ -0,0 +1,57 @@ +package com.markilue.java_learning.collection; + +import java.util.Arrays; +import java.util.Iterator; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.collection + * @Author: dingjiawen + * @CreateTime: 2022-09-18 15:13 + * @Description: TODO 测试实现java.lang.Iterator类,实现增强for + * @Version: 1.0 + */ +public class MyArrayList implements java.lang.Iterable { + + private Object[] array; + private int size; + + public MyArrayList() { + array = new Object[5]; + } + + public void add(E e) { + ensureCapacityEnough(); + array[size++] = e; + + } + + public void ensureCapacityEnough() { + if (size >= array.length) { + array = Arrays.copyOf(array, array.length * 2); + } + } + + + @Override + public Iterator iterator() { + return new Iter(); + } + + private class Iter implements Iterator { + int cursor; + + + @Override + public boolean hasNext() { + return cursor <= size; + } + + @Override + public E next() { + return (E) array[cursor++]; + } + } + + +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/SetTest.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/SetTest.java new file mode 100644 index 0000000..9f633c2 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/SetTest.java @@ -0,0 +1,268 @@ +package com.markilue.java_learning.collection; + +import org.junit.Test; + +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.TreeSet; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.collection + * @Author: dingjiawen + * @CreateTime: 2022-09-18 16:46 + * @Description: + * TODO Set的三个实现类 HashSet、LinkedHashSet、TreeSet: + * Set接口是Collection的子接口,set接口没有提供额外的方法。但是比`Collection`接口更加严格了。Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。 + * 1)HashSet: + * 1.底层的实现其实是一个java.util.HashMap支持.底层物理实现是一个Hash表 + * 2.HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。因此,存储到HashSet的元素要重写hashCode和equals方法。具体写法可以参照Employee类 + * 2)LinkedHashSet: + * 1.LinkedHashSet是HashSet的子类,它在HashSet的基础上,在结点中增加两个属性before和after维护了结点的前后添加顺序。 + * 2.`java.util.LinkedHashSet`,它是链表和哈希表组合的一个数据存储结构。LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。 + * 3)TreeSet: + * 1.底层结构:里面维护了一个TreeMap,都是基于红黑树实现的 + * 2.特点:不允许重复;实现排序(自然排序或定制排序) + * 如何实现去重:如果使用的是自然排序,则通过调用实现的compareTo方法;如果使用的是定制排序,则通过调用比较器的compare方法 + * 如何实现排序: + * 方式一:自然排序:让待添加的元素类型实现Comparable接口,并重写compareTo方法 + * 方式二:定制排序:创建Set对象时,指定Comparator比较器接口,并实现compare方法 + * @Version: 1.0 + */ +public class SetTest { + + + //测试将重写了hashcode和equal方法的类放入HashSet中 + @Test + public void test() { + HashSet set = new HashSet<>(); + set.add(new Employee("张三", new Employee.MyDate(1990, 1, 1))); + //重复元素无法添加,因为MyDate和Employee重写了hashCode和equals方法 + set.add(new Employee("张三", new Employee.MyDate(1990, 1, 1))); + set.add(new Employee("李四", new Employee.MyDate(1992, 2, 2))); + + for (Employee object : set) { + System.out.println(object); + } + } + + + //测试LinkedHashSet + @Test + public void test1() { + LinkedHashSet set = new LinkedHashSet<>(); + set.add("张三"); + set.add("李四"); + set.add("王五"); + set.add("张三"); + + System.out.println("元素个数:" + set.size()); //3 + for (String name : set) { + System.out.println(name); //张三 李四 王五 + } + } + + + //测试TreeSet的自然排序 + @Test + public void test2() { + + TreeSet set = new TreeSet<>(); + set.add("zhangsan"); //String它实现了java.lang.Comparable接口 + set.add("zisi"); + set.add("wangwu"); + set.add("hangsan"); + + System.out.println("元素个数:" + set.size()); + for (String str : set) { + System.out.println(str); + } + } + + //测试TreeSet的定制排序 + @Test + public void test3() { + + TreeSet set = new TreeSet(new Comparator(){ + @Override + public int compare(Student o1, Student o2) { + return o1.getId() - o2.getId(); + } + }); + set.add(new Student(3,"张三")); + set.add(new Student(1,"李四")); + set.add(new Student(2,"王五")); + set.add(new Student(3,"张三风")); + + System.out.println("元素个数:" + set.size()); //3 + for (Student stu : set) { + System.out.println(stu); //Student [id=1, name=李四];Student [id=2, name=王五];Student [id=3, name=张三] + } + } +} + + +class Employee { + private String name; + private MyDate birthday; + + public Employee(String name, MyDate birthday) { + super(); + this.name = name; + this.birthday = birthday; + } + + public Employee() { + super(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public MyDate getBirthday() { + return birthday; + } + + public void setBirthday(MyDate birthday) { + this.birthday = birthday; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((birthday == null) ? 0 : birthday.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Employee other = (Employee) obj; + if (birthday == null) { + if (other.birthday != null) + return false; + } else if (!birthday.equals(other.birthday)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + + @Override + public String toString() { + return "姓名:" + name + ", 生日:" + birthday; + } + + static class MyDate { + private int year; + private int month; + private int day; + + public MyDate(int year, int month, int day) { + super(); + this.year = year; + this.month = month; + this.day = day; + } + + public MyDate() { + super(); + } + + public int getYear() { + return year; + } + + public void setYear(int year) { + this.year = year; + } + + public int getMonth() { + return month; + } + + public void setMonth(int month) { + this.month = month; + } + + public int getDay() { + return day; + } + + public void setDay(int day) { + this.day = day; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + day; + result = prime * result + month; + result = prime * result + year; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MyDate other = (MyDate) obj; + if (day != other.day) + return false; + if (month != other.month) + return false; + if (year != other.year) + return false; + return true; + } + + @Override + public String toString() { + return year + "-" + month + "-" + day; + } + } + +} + +class Student{ + private int id; + private String name; + public Student(int id, String name) { + super(); + this.id = id; + this.name = name; + } + public int getId() { + return id; + } + public void setId(int id) { + this.id = id; + } + //......这里省略了name属性的get/set + @Override + public String toString() { + return "Student [id=" + id + ", name=" + name + "]"; + } +} + From 7d9b21790c5c58ddd1c0c329b94d1bccf21a4304 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Mon, 19 Sep 2022 15:31:02 +0800 Subject: [PATCH 23/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leecode/tree/InorderTraversal.java | 160 ++++++++++--- .../leecode/tree/PreOrderTraversal.java | 211 ++++++++++++++++++ 2 files changed, 336 insertions(+), 35 deletions(-) create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/PreOrderTraversal.java diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java b/Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java index 920a458..e9ec1a8 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java @@ -1,9 +1,9 @@ package com.markilue.leecode.tree; - import java.util.ArrayList; import java.util.List; +import java.util.Stack; /** * 中序遍历二叉排序树 @@ -25,34 +25,34 @@ public class InorderTraversal { TreeNode2.setRight(TreeNode5); TreeNode3.setLeft(TreeNode6); - List integers = inorderTraversal1(root); + List integers = inorderTraversal4(root); System.out.println(integers); - } - public static List list =new ArrayList(); - public static List list2 =new ArrayList(); + public static List list = new ArrayList(); + public static List list2 = new ArrayList(); /** * 递归法:中序遍历 + * * @param root */ - public static void inorderTraversal(TreeNode root){ + public static void inorderTraversal(TreeNode root) { - if(root == null){ + if (root == null) { return; } - if(root.left !=null){ + if (root.left != null) { inorderTraversal(root.left); } list.add(root); - if(root.right !=null){ + if (root.right != null) { inorderTraversal(root.right); } @@ -60,73 +60,163 @@ public class InorderTraversal { /** * 递归法原题:中序遍历 => O(n) + * * @param root */ - public static List inorderTraversal2(TreeNode root){ + public static List inorderTraversal2(TreeNode root) { - if(root == null){ + if (root == null) { return null; } - if(root.left !=null){ + if (root.left != null) { inorderTraversal2(root.left); } list2.add(root.val); - if(root.right !=null){ + if (root.right != null) { inorderTraversal2(root.right); } return list2; } + /** + * 自己的非递归法:使用一个栈记录上次还需要进一步遍历的节点,等现在的遍历完了,就可以出栈到这里,让上一次的继续去遍历 + * + * @param root + * @return + */ + public static List inorderTraversal3(TreeNode root) { + List list = new ArrayList<>(); + + if (root == null) { + return list; + } + + //使用栈记录需要遍历的root + Stack stack = new Stack<>(); + TreeNode node = root; + + //核心理念是:先找到当前节点的最左节点,把这个值pop出之后就可以加入result,然后看看他的右子树 + while (stack.size() > 0 || node != null) { + //指针访问节点,访问到底层 + if (node != null) { + //将访问的节点放入栈 + stack.push(node); + node = node.left; + } else { + //从栈里弹出的数据就是要处理的数据(放入result数组的数据) + node = stack.pop(); + list.add(node.val); + node = node.right; + + } + } + + return list; + } + /** * 非递归法:中序遍历(题解第三种方法) ->空间复杂度 O(1)Morris 中序遍历 * 循环: - * 寻找当前节点的左子树: - * 如果左子树为空:将当前节点加入list,将当前节点右移 - * 如果不为空: - * 寻找当前节点的左子树最右节点flag,判断flag的右子节点是否为空: - * 如果为空:当前节点左移,设置flag的右子节点为当前节点 - * 如果不为空:说明已经遍历完当前节点的左子树,将flag的右子节点为置空,将当前节点加入list,当前节点右移 + * 寻找当前节点的左子树: + * 如果左子树为空:将当前节点加入list,将当前节点右移 + * 如果不为空: + * 寻找当前节点的左子树最右节点flag,判断flag的右子节点是否为空: + * 如果为空:当前节点左移,设置flag的右子节点为当前节点 + * 如果不为空:说明已经遍历完当前节点的左子树,将flag的右子节点为置空,将当前节点加入list,当前节点右移 + * * @param root */ - public static List inorderTraversal1(TreeNode root){ + public static List inorderTraversal1(TreeNode root) { - List list1 =new ArrayList(); + List list1 = new ArrayList(); - while (root != null){ - if(root.left ==null){ + while (root != null) { + if (root.left == null) { //如果左子树为空 list1.add(root.val); - root=root.right; - }else { + root = root.right; + } else { //如果左子树不为空: //记录左子树最右节点 - TreeNode p=root.left; + TreeNode p = root.left; //寻找flag - while (p.right !=null &&p.right != root){ - p=p.right; + while (p.right != null && p.right != root) { + p = p.right; } - TreeNode flag=p; + TreeNode flag = p; //判断flag是根据什么条件出来的,是flag.right ==null还是p.right != root - if(flag.right == null){ + if (flag.right == null) { //flag无右子节点,第一次遍历 - flag.right =root; - root=root.left; - }else if(flag.right == root){ + flag.right = root; + root = root.left; + } else if (flag.right == root) { //flag已经被加载过了,即当前节点的左子树已经被遍历完了 - flag.right =null; + flag.right = null; list1.add(root.val); - root=root.right; + root = root.right; } } } + return list1; + } + + + /** + * 自己尝试Morris中序遍历 + * 速度超过100%,内存超过81.82% + * @param root + */ + public static List inorderTraversal4(TreeNode root) { + + List list1 = new ArrayList(); + + TreeNode node1 = root; + TreeNode node2 = null; + + while (node1 != null) { + node2 = node1.left; + + //判断左边还有没有值 + if(node2!=null){ + //首先找到遍历node1之前的最后一个节点 + while (node2.right != null && node2.right != node1) { + node2 = node2.right; + } + + //判断是从哪个条件出来的 + if (node2.right == null) { + //如果是从第一个条件出来的,那么就是没有遍历过得节点 + + //将这个节点的右边定为node1方便以后回来,找到node1 + node2.right = node1; + //node1已经可以回溯,放心将node1左移 + node1 = node1.left; + continue; + } else { + //如果是从第二个条件出来的,那么就是遍历过的节点 + + //那么他的左边一定是遍历完了,这时将node的值加入结果 + list1.add(node1.val); + //左边遍历完了,往右移 + node1 = node1.right; + } + }else { + //左边没值了 + list1.add(node1.val); + node1=node1.right; + + } + + + } return list1; diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/PreOrderTraversal.java b/Leecode/src/main/java/com/markilue/leecode/tree/PreOrderTraversal.java new file mode 100644 index 0000000..6bffeb5 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/PreOrderTraversal.java @@ -0,0 +1,211 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; +import org.omg.CORBA.PUBLIC_MEMBER; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-19 09:45 + * @Description: + * TODO 力扣144题 二叉树的前序遍历: + * 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 + * @Version: 1.0 + */ +public class PreOrderTraversal { + + + @Test + public void test(){ + + TreeNode root = new TreeNode(1); +// TreeNode TreeNode2 = new TreeNode(2); +// TreeNode TreeNode3 = new TreeNode(3); +// TreeNode TreeNode4 = new TreeNode(1); +// TreeNode TreeNode5 = new TreeNode(3); +// TreeNode TreeNode6 = new TreeNode(5); + +// root.setRight(TreeNode2); +// TreeNode2.setLeft(TreeNode3); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setLeft(TreeNode6); + System.out.println(preorderTraversal1(root)); + } + + @Test + public void test1(){ + + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(3); +// TreeNode TreeNode4 = new TreeNode(1); +// TreeNode TreeNode5 = new TreeNode(3); +// TreeNode TreeNode6 = new TreeNode(5); + + root.setRight(TreeNode2); + TreeNode2.setLeft(TreeNode3); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setLeft(TreeNode6); + System.out.println(preorderTraversal1(root)); + } + + @Test + public void test2(){ + + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(3); +// TreeNode TreeNode4 = new TreeNode(1); +// TreeNode TreeNode5 = new TreeNode(3); +// TreeNode TreeNode6 = new TreeNode(5); + + root.setRight(TreeNode2); + TreeNode2.setLeft(TreeNode3); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setLeft(TreeNode6); + System.out.println(preorderTraversal1(null)); + } + + @Test + public void test3(){ + + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(3); + TreeNode TreeNode4 = new TreeNode(4); + TreeNode TreeNode5 = new TreeNode(5); + TreeNode TreeNode6 = new TreeNode(6); + TreeNode TreeNode7 = new TreeNode(7); + + root.setRight(TreeNode2); + root.setLeft(TreeNode3); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode6); + TreeNode3.setLeft(TreeNode7); + System.out.println(preorderTraversal2(root)); + } + + + + + public List preorderTraversal(TreeNode root) { + List list = new ArrayList<>(); + traversal(root, list); + return list; + } + + /** + * 自己的递归法 + * 速度击败100% ,内存击败76.4% + */ + public void traversal(TreeNode root,List list) { + + if(root==null){ + return; + } + list.add(root.val); + traversal(root.left,list); + traversal(root.right,list); + + } + + /** + * 自己的非递归法:使用一个栈记录上次还需要进一步遍历的节点,等现在的遍历完了,就可以出栈到这里,让上一次的继续去遍历 + * 速度击败100%,内存击败18% + * @param root + * @return + */ + public List preorderTraversal1(TreeNode root) { + List list = new ArrayList<>(); + + if(root==null){ + return list; + } + + //使用栈记录需要遍历的root + Stack stack = new Stack<>(); + stack.push(root); + + while (stack.size()>0){ + TreeNode node = stack.pop(); + list.add(node.val); + //如果右子树还需要遍历,等左子树遍历完了再遍历右子树 + if(node.right!=null){ + stack.push(node.right); + } + //如果左子树还需要遍历 + if(node.left!=null){ + stack.push(node.left); + } + } + + return list; + } + + + /** + * Morris 遍历:将空间复杂度降到O(1) + *Morris 遍历的核心思想是利用树的大量空闲指针,实现空间开销的极限缩减。其前序遍历规则总结如下: + * + * 1.新建临时节点,令该节点为 root; + * 2.如果当前节点的左子节点为空,将当前节点加入答案,并遍历当前节点的右子节点; + * 3.如果当前节点的左子节点不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点: + * 如果前驱节点的右子节点为空,将前驱节点的右子节点设置为当前节点。然后将当前节点加入答案,并将前驱节点的右子节点更新为当前节点。当前节点更新为当前节点的左子节点。 + * 如果前驱节点的右子节点为当前节点,将它的右子节点重新设为空。当前节点更新为当前节点的右子节点。 + * 4.重复步骤 2 和步骤 3,直到遍历结束。 + * + * TODO 核心理念是如何回到root节点的: + * 1)传统方法使用stack去回到root + * 2)这种方法利用叶子结点闲置的右指针,因为回到root的前提是左边的遍历完了,那么遍历完了之前的一个节点一定是叶子节点,可以提前找到这个叶子结点,将其右指针置为root,就可以回到root了 + * + * @param root + * @return + */ + public List preorderTraversal2(TreeNode root) { + List res = new ArrayList(); + if (root == null) { + return res; + } + + TreeNode p1 = root, p2 = null; + + while (p1 != null) { + p2 = p1.left; + if (p2 != null) { + //通过这个循环找到回到root的最后一个节点,第二个条件是判断是否遍历过这个节点 + while (p2.right != null && p2.right != p1) { + p2 = p2.right; + } + //从第一个条件出来的,证明这个节点没遍历过且是回到root前的最后一个节点 + if (p2.right == null) { + res.add(p1.val); + //让下次得以回到之前遍历的节点 + p2.right = p1; + //找到了回来的节点,放心的将root左移 + p1 = p1.left; + continue; + } else { + //从第二个条件出来的,证明这个节点遍历过了,那么就把他的右边置空 + p2.right = null; + } + } else { + //左边遍历完了 + res.add(p1.val); + } + p1 = p1.right; + } + return res; + } + + +} From cbf03608b0d0bf69774e685420090c327aac2059 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Mon, 19 Sep 2022 18:27:18 +0800 Subject: [PATCH 24/38] =?UTF-8?q?=E9=9B=86=E5=90=88map,HashMap=E6=BA=90?= =?UTF-8?q?=E7=A0=81=E5=AD=A6=E4=B9=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java_learning/collection/HashMapTest.java | 99 +++++++++++ .../java_learning/collection/MapTest.java | 166 ++++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/HashMapTest.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/MapTest.java diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/HashMapTest.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/HashMapTest.java new file mode 100644 index 0000000..4d0ebc6 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/HashMapTest.java @@ -0,0 +1,99 @@ +package com.markilue.java_learning.collection; + +import org.junit.Test; + +import java.util.HashMap; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.collection + * @Author: dingjiawen + * @CreateTime: 2022-09-19 17:03 + * @Description: TODO 测试HashMap的树化和反树化 + * @Version: 1.0 + */ +public class HashMapTest { + + @Test + public void test1(){ + + //这里为了演示的效果,我们造一个特殊的类,这个类的hashCode()方法返回固定值1 + //因为这样就可以造成冲突问题,使得它们都存到table[1]中 + HashMap map = new HashMap<>(); + for (int i = 1; i <= 11; i++) { + map.put(new MyKey(i), "value"+i);//树化演示 + } + + } + + @Test + public void test2(){ + + HashMap map = new HashMap<>(); + for (int i = 1; i <= 11; i++) { + map.put(new MyKey(i), "value"+i); + } + for (int i = 1; i <=11; i++) { + map.remove(new MyKey(i));//反树化演示 + } + + } + + @Test + public void test3(){ + + HashMap map = new HashMap<>(); + for (int i = 1; i <= 11; i++) { + map.put(new MyKey(i), "value"+i); + } + + for (int i = 1; i <=5; i++) { + map.remove(new MyKey(i)); + }//table[1]下剩余6个结点 + + for (int i = 21; i <= 100; i++) { + map.put(new MyKey(i), "value"+i);//添加到扩容时,反树化 + } + + } + +} + + +class MyKey{ + int num; + + public MyKey(int num) { + super(); + this.num = num; + } + + @Override + public int hashCode() { + //容量小于20全放一个里面 + if(num<=20){ + return 1; + }else{ + //大于30之后尽可能分开 + final int prime = 31; + int result = 1; + result = prime * result + num; + return result; + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MyKey other = (MyKey) obj; + if (num != other.num) + return false; + return true; + } + +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/MapTest.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/MapTest.java new file mode 100644 index 0000000..509ed1f --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/MapTest.java @@ -0,0 +1,166 @@ +package com.markilue.java_learning.collection; + +import org.junit.Test; + +import java.util.*; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.collection + * @Author: dingjiawen + * @CreateTime: 2022-09-19 15:35 + * @Description: + * TODO Map及其实现类:HashMap、HashTable、LinkedHashMap、TreeMap、Properties + * 1)Map: + * 1.这些实现类均继承自java.util.Map接口 + * 2.使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中; + * 若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。 + * 3.Map的遍历,不能支持foreach,因为Map接口没有继承java.lang.Iterable接口,也没有实现Iterator iterator()方法。 + * 但是可以分别遍历其key(keySet()方法)和value(values方法),也可以成对遍历(entrySet()方法) + * 4.Map.Entry是Map接口的内部接口。每一种Map内部有自己的Map.Entry的实现类。 + * 在Map中存储数据,实际上是将Key---->value的数据存储在Map.Entry接口的实例中,再在Map集合中插入Map.Entry的实例化对象 + * 2)HashMap: + * 1.底层是哈希表 数组加链表 JDK1.7散列表table[index]也称为bucket桶,其中table是一个HashMap.Entry是一个链表,HashMap.Entry中还存放着next指针,存放相同hashcode值的元素 + * JDK1.8封装为HashMap.Node类型或HashMap.TreeNode类型,它俩都直接或间接的实现了Map.Entry接口。即table[index]下的映射关系可能串起来一个链表或一棵红黑树(自平衡的二叉树)。 + * 链表长度大于8(且总容量大于等于64,不大的话会优先扩容而不是树化)转为红黑树(一种解释是节点规律服从泊松分布,经过计算得出这个值会比较好),树节点数小于6退化为链表 + * 2.评价两个key是否相等的指标是其hashcode相等,且equal方法返回true,所以存放的对象必须实现hashcode和equal方法 + * 3.线程不安全的,并允许使用 null 值和 null 键。 + * 4.默认初始化长度1<<4 即16(一定是2的倍数).每次扩容变为原来的两倍,未避免分布不均匀增加了扰动计算 + * 5.哈希算法:使用位运算代替取模运算(前提:容量length一定是2^n) 源码:hashcode&(length-1) X %2^n=X &(2^n-1) + * 3)HashTable: + * 1.底层实现是哈希表 + * 2.评价两个key是否相等的指标是其hashcode相等,且equal方法返回true,所以存放的对象必须实现hashcode和equal方法 + * 3.线程安全的,任何非 null 对象都可以用作键或值。 + * 4.默认初始化长度11(素数),内次扩容变为原来的2n+1倍,扩容结果也为奇数,素数使得节点取模更加均匀,分散效果越好 + * 5.哈希算法:在保证是正数的情况下直接取模 源码:(hashcode & 0x7FFFFFFF)%table.length + * 4)LinkedHashMap: + * 1.LinkedHashMap是HashMap的子类 + * 2.与HashMap的不同在于:前者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。 + * 5)TreeMap: + * 1.基于红黑树(Red-Black tree)的 NavigableMap 实现。 + * 2.该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。 + * 6)Properties: + * 1.Properties 类是 Hashtable 的子类,Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。 + * 2.存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法。 + * 7)HashSet与Map的关系: + * 1.Set的内部实现其实是一个Map。即HashSet的内部实现是一个HashMap,TreeSet的内部实现是一个TreeMap,LinkedHashSet的内部实现是一个LinkedHashMap。 + * 2.Set中只有一个元素,又是怎么变成(key,value)的呢? + * 源码实现:private static final Object PRESENT = new Object(); + * public boolean add(E e) { + * return map.put(e, PRESENT)==null; + * } + * public Iterator iterator() { + * return map.keySet().iterator(); + * } + * @Version: 1.0 + */ +public class MapTest { + + + //HashMap的put覆盖测试,和可以存放null值测试 + @Test + public void test(){ + HashMap map = new HashMap<>(); + map.put("张三", 10000.0); + //key相同,新的value会覆盖原来的value + //因为String重写了hashCode和equals方法 + map.put("张三", 12000.0); + map.put("李四", 14000.0); + //HashMap支持key和value为null值 + String name = null; + Double salary = null; + map.put(name, salary); + + Set> entrySet = map.entrySet(); + for (Map.Entry entry : entrySet) { + System.out.println(entry);//null=null;李四=14000.0;张三=12000.0 + } + } + + //LinkedHashMap的插入顺序测试 + @Test + public void test1(){ + LinkedHashMap map = new LinkedHashMap<>(); + map.put("张三", 10000.0); + //key相同,新的value会覆盖原来的value + //因为String重写了hashCode和equals方法 + map.put("张三", 12000.0); + map.put("李四", 14000.0); + //HashMap支持key和value为null值 + String name = null; + Double salary = null; + map.put(name, salary); + + Set> entrySet = map.entrySet(); + for (Map.Entry entry : entrySet) { + System.out.println(entry); //张三=12000.0;李四=14000.0;null=null + } + } + + //TreeMap自然顺序比较 + @Test + public void test2() { + TreeMap map = new TreeMap<>(); + map.put("Jack", 11000); + map.put("Alice", 12000); + map.put("zhangsan", 13000); + map.put("baitao", 14000); + map.put("Lucy", 15000); + + //String实现了Comparable接口,默认按照Unicode编码值排序 + Set> entrySet = map.entrySet(); + for (Map.Entry entry : entrySet) { + System.out.println(entry); + /* + Alice=12000 + Jack=11000 + Lucy=15000 + baitao=14000 + zhangsan=13000 + */ + } + } + + //TreeMap实现comparator比较器顺序 + @Test + public void test3() { + //指定定制比较器Comparator,按照Unicode编码值排序,但是忽略大小写 + TreeMap map = new TreeMap<>(new Comparator() { + + @Override + public int compare(String o1, String o2) { + return o1.compareToIgnoreCase(o2); + } + }); + map.put("Jack", 11000); + map.put("Alice", 12000); + map.put("zhangsan", 13000); + map.put("baitao", 14000); + map.put("Lucy", 15000); + + Set> entrySet = map.entrySet(); + for (Map.Entry entry : entrySet) { + System.out.println(entry); + /* + Alice=12000 + baitao=14000 + Jack=11000 + Lucy=15000 + zhangsan=13000 + */ + } + } + + //properties方法测试 + @Test + public void test4(){ +// Properties properties1 = new Properties(); +// properties1.setProperty() + Properties properties = System.getProperties(); + String p2 = properties.getProperty("file.encoding");//当前源文件字符编码 + System.out.println(p2); + } + + + +} From 2e5f398de6f49c691c23ba7f7bd579d8d5f011fd Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Tue, 20 Sep 2022 13:42:55 +0800 Subject: [PATCH 25/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/markilue/leecode/tree/LevelOrder.java | 171 +++++++++++ .../leecode/tree/PostOrderTraversal.java | 282 ++++++++++++++++++ .../leecode/tree/StackUnitTraversal.java | 170 +++++++++++ 3 files changed, 623 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/LevelOrder.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/PostOrderTraversal.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/StackUnitTraversal.java diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/LevelOrder.java b/Leecode/src/main/java/com/markilue/leecode/tree/LevelOrder.java new file mode 100644 index 0000000..60ac632 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/LevelOrder.java @@ -0,0 +1,171 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; +import sun.security.krb5.internal.CredentialsUtil; + +import java.util.*; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-20 11:44 + * @Description: TODO 力扣102题:二叉树的层序遍历: + * 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。 + * @Version: 1.0 + */ +public class LevelOrder { + + @Test + public void test() { + + TreeNode root = new TreeNode(3); + TreeNode TreeNode2 = new TreeNode(9); + TreeNode TreeNode3 = new TreeNode(20); +// TreeNode TreeNode4 = new TreeNode(4); +// TreeNode TreeNode5 = new TreeNode(5); + TreeNode TreeNode6 = new TreeNode(15); + TreeNode TreeNode7 = new TreeNode(7); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode7); + TreeNode3.setLeft(TreeNode6); + + System.out.println(levelOrder(root)); + + } + + @Test + public void test1() { + + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(9); + TreeNode TreeNode3 = new TreeNode(20); +// TreeNode TreeNode4 = new TreeNode(4); +// TreeNode TreeNode5 = new TreeNode(5); + TreeNode TreeNode6 = new TreeNode(15); + TreeNode TreeNode7 = new TreeNode(7); + +// root.setRight(TreeNode3); +// root.setLeft(TreeNode2); +//// TreeNode2.setLeft(TreeNode4); +//// TreeNode2.setRight(TreeNode5); +// TreeNode3.setRight(TreeNode7); +// TreeNode3.setLeft(TreeNode6); + + System.out.println(levelOrder(root)); + + } + + + /** + * 这里尝试使用之前统一的空指针标记法(将其换成队列):难点在于如何找到下一层的第一个节点 + * 速度超过58.94%,内存超过37.04% + * + * @param root + * @return + */ + public List> levelOrder(TreeNode root) { + + List> result = new ArrayList<>(); + + //使用队列完成 + Deque deque = new LinkedList(); + + if (root != null) { + deque.addLast(root); + } + + List mid = new ArrayList<>(); + TreeNode pre = root; + //是否需要找下一层 + boolean flag = true; + + while (deque.size() > 0) { + TreeNode node = deque.peek(); + + //遍历到了下一层 + if (pre == node && !flag) { + result.add(mid); + mid = new ArrayList(); + //需要找到一个不为0的值了 + flag = true; + } + + + if (node != null) { + //访问过还未处理 + deque.addFirst(null); + + if (node.left != null) { + deque.addLast(node.left); + //记录下层的第一个指针 + if (flag) { + pre = node.left; + flag = false; + } + } + + if (node.right != null) { + deque.addLast(node.right); + //记录下层的第一个指针 + if (flag) { + pre = node.right; + flag = false; + } + } + } else { + //处理访问数据 + deque.poll();//移除空指针 + mid.add(deque.poll().val); + } + } + + if (mid.size() != 0) { + result.add(mid); + } + + return result; + + } + + /** + * 官方队列法:使用了固定的size从而避免了找下一次的第一个值 + * 速度超过100%,内存超过81% + * + * @param root + * @return + */ + public List> levelOrder1(TreeNode root) { + + List> result = new ArrayList<>(); + + //使用队列完成 + Deque deque = new LinkedList(); + + if (root != null) { + deque.addLast(root); + } + while (deque.size() > 0) { + List mid = new ArrayList<>(); + + int size = deque.size(); + + //注意这里必须使用size,而不是deque.size,因为deque的size一直在发生变化 + for (int i = 0; i < size; i++) { + TreeNode poll = deque.poll(); + mid.add(poll.val); + if (poll.left != null) deque.offer(poll.left); + if (poll.right != null) deque.offer(poll.right); + } + result.add(mid); + } + return result; + + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/PostOrderTraversal.java b/Leecode/src/main/java/com/markilue/leecode/tree/PostOrderTraversal.java new file mode 100644 index 0000000..41bef86 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/PostOrderTraversal.java @@ -0,0 +1,282 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.*; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-19 09:45 + * @Description: TODO 力扣144题 二叉树的前序遍历: + * 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 + * @Version: 1.0 + */ +public class PostOrderTraversal { + + + @Test + public void test() { + + TreeNode root = new TreeNode(1); +// TreeNode TreeNode2 = new TreeNode(2); +// TreeNode TreeNode3 = new TreeNode(3); +// TreeNode TreeNode4 = new TreeNode(1); +// TreeNode TreeNode5 = new TreeNode(3); +// TreeNode TreeNode6 = new TreeNode(5); + +// root.setRight(TreeNode2); +// TreeNode2.setLeft(TreeNode3); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setLeft(TreeNode6); + System.out.println(postorderTraversal1(root)); + } + + @Test + public void test1() { + + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(3); +// TreeNode TreeNode4 = new TreeNode(1); +// TreeNode TreeNode5 = new TreeNode(3); +// TreeNode TreeNode6 = new TreeNode(5); + + root.setRight(TreeNode2); + TreeNode2.setLeft(TreeNode3); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setLeft(TreeNode6); + System.out.println(postorderTraversal1(root)); + } + + @Test + public void test2() { + + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(3); +// TreeNode TreeNode4 = new TreeNode(1); +// TreeNode TreeNode5 = new TreeNode(3); +// TreeNode TreeNode6 = new TreeNode(5); + + root.setRight(TreeNode2); + TreeNode2.setLeft(TreeNode3); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setLeft(TreeNode6); + System.out.println(postorderTraversal1(null)); + } + + @Test + public void test3() { + + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(3); + TreeNode TreeNode4 = new TreeNode(4); + TreeNode TreeNode5 = new TreeNode(5); + TreeNode TreeNode6 = new TreeNode(6); + TreeNode TreeNode7 = new TreeNode(7); + + root.setRight(TreeNode2); + root.setLeft(TreeNode3); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode6); + TreeNode3.setLeft(TreeNode7); + System.out.println(postorderTraversal4(root)); + } + + + public List postorderTraversal(TreeNode root) { + List list = new ArrayList<>(); + traversal(root, list); + return list; + } + + /** + * 自己的递归法 + * 速度击败100% ,内存击败44.85% + */ + public void traversal(TreeNode root, List list) { + + if (root == null) { + return; + } + traversal(root.left, list); + traversal(root.right, list); + list.add(root.val); + + } + + /** + * 自己的非递归法:使用一个栈记录上次还需要进一步遍历的节点,等现在的遍历完了,就可以出栈到这里,让上一次的继续去遍历 + * 速度击败100%,内存击败90.34% + * + * @param root + * @return + */ + public List postorderTraversal1(TreeNode root) { + + List result = new ArrayList<>(); + Stack stack = new Stack<>(); + TreeNode cur = root; + + while (cur != null || stack.size() > 0) { + + //判断是什么条件进来的 + if (cur != null) { + stack.push(cur); + cur = cur.left; + continue; + }else { + TreeNode node = stack.peek(); + //看看他右边还有没有 + if (node.right != null) { + //右边还有,让右边的在继续遍历 + cur = node.right; + //置空防止再次还来遍历 + node.right=null; + } else { + //左右都没有了,直接加入结果 + result.add(node.val); + stack.pop(); + } + } + + + } + return result; + } + + /** + * 代码随想录的非递归法:与前序遍历的非递归法类似,前序是中-左-右;后序是左-右-中,因此可以把前序的顺序稍微变一下变成中-右-左,最后的结果再反转一下即可 + * 速度击败100%,内存击败90.34% + * + * @param root + * @return + */ + public List postorderTraversal3(TreeNode root) { + + ArrayList result = new ArrayList<>(); + Stack stack = new Stack<>(); + stack.push(root); + + while (stack.size()>0){ + TreeNode node = stack.pop(); + result.add(node.val); + if(node.left!=null){ + stack.push(node.left); + } + if(node.right!=null){ + stack.push(node.right); + } + } + + //反转list + ArrayList realList = new ArrayList<>(); + + for (int i = result.size()-1; i >=0 ; i--) { + realList.add(result.get(i)); + } + + return realList; + } + + + /** + * 官方Morris 遍历:将空间复杂度降到O(1) + * TODO 这里实际上就是将前序遍历的顺序稍微变一下中-右-左 最后的结果再反转 + * + * @param root + * @return + */ + public List postorderTraversal2(TreeNode root) { + List res = new ArrayList(); + if (root == null) { + return res; + } + + TreeNode p1 = root, p2 = null; + + while (p1 != null) { + p2 = p1.left; + if (p2 != null) { + while (p2.right != null && p2.right != p1) { + p2 = p2.right; + } + if (p2.right == null) { + p2.right = p1; + p1 = p1.left; + continue; + } else { + p2.right = null; + addPath(res, p1.left); + } + } + p1 = p1.right; + } + addPath(res, root); + return res; + + } + + + public void addPath(List res, TreeNode node) { + int count = 0; + while (node != null) { + ++count; + res.add(node.val); + node = node.right; + } + //反转左右 + int left = res.size() - count, right = res.size() - 1; + while (left < right) { + int temp = res.get(left); + res.set(left, res.get(right)); + res.set(right, temp); + left++; + right--; + } + } + + + + /** + * 官方不改变指针的非递归法 + * @param root + * @return + */ + public List postorderTraversal4(TreeNode root) { + List res = new ArrayList(); + if (root == null) { + return res; + } + + Deque stack = new LinkedList(); + TreeNode prev = null; + while (root != null || !stack.isEmpty()) { + while (root != null) { + stack.push(root); + root = root.left; + } + root = stack.pop(); + //第二个条件表示右边的节点是上一次pop出的节点,因为只有pop出的值才会在prev赋值 + if (root.right == null || root.right == prev) { + res.add(root.val); + prev = root; + root = null; + } else { + stack.push(root); + root = root.right; + } + } + return res; + } + + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/StackUnitTraversal.java b/Leecode/src/main/java/com/markilue/leecode/tree/StackUnitTraversal.java new file mode 100644 index 0000000..72fe515 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/StackUnitTraversal.java @@ -0,0 +1,170 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-20 11:13 + * @Description: + * TODO stack栈法(一种迭代法)来统一解决前中后序遍历:使用空指针标记法来统一前中后遍历的迭代法 + * @Version: 1.0 + */ +public class StackUnitTraversal { + + @Test + public void test(){ + + TreeNode root = new TreeNode(5); + TreeNode TreeNode4 = new TreeNode(4); + TreeNode TreeNode6 = new TreeNode(6); + TreeNode TreeNode1 = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + root.setRight(TreeNode6); + root.setLeft(TreeNode4); + TreeNode4.setLeft(TreeNode1); + TreeNode4.setRight(TreeNode2); + + + System.out.println(preorderTraversal(root)); + } + + /* + *空指针标记法的中序遍历 + * @param root + * @return + */ + public List inorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + + //使用栈记录需要遍历的root + Stack stack = new Stack<>(); + if (root != null) { + stack.push(root); + } + + //栈中数据:[6,5,null,2,4,null,1,null] + while (stack.size() > 0) { + TreeNode node = stack.peek(); + + if(node!=null){ + //将该节点弹出,避免重复操作,下面再将右、中、左节点添加到栈中 + stack.pop(); + //添加右节点(空节点不入栈) + if(node.right!=null){ + stack.push(node.right); + } + + //添加中节点 + stack.push(node); + //中指针访问过,但没有处理,添加空指针节点作为标记 + stack.push(null); + //添加左节点(空节点不入栈) + if(node.left!=null){ + stack.push(node.left); + } + }else { + //只有遇到空节点的时候,才将下一个节点放入结果集 + stack.pop();//将空指针弹出 + node = stack.pop(); //重新取出栈中元素 + result.add(node.val); + } + } + return result; + } + + /* + *空指针标记法的前序遍历 + * @param root + * @return + */ + public List preorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + + //使用栈记录需要遍历的root + Stack stack = new Stack<>(); + if (root != null) { + stack.push(root); + } + + //栈中数据:[6,4,5,null] + //栈中数据:[6,2,1,4,null] + while (stack.size() > 0) { + TreeNode node = stack.peek(); + + if(node!=null){ + //将该节点弹出,避免重复操作,下面再将右、中、左节点添加到栈中 + stack.pop(); + //添加右节点(空节点不入栈) + if(node.right!=null){ + stack.push(node.right); + } + //添加左节点(空节点不入栈) + if(node.left!=null){ + stack.push(node.left); + } + //添加中节点 + stack.push(node); + //中指针访问过,但没有处理,添加空指针节点作为标记 + stack.push(null); + }else { + //只有遇到空节点的时候,才将下一个节点放入结果集 + stack.pop();//将空指针弹出 + node = stack.pop(); //重新取出栈中元素 + result.add(node.val); + } + } + return result; + } + + /* + *空指针标记法的后序遍历 + * @param root + * @return + */ + public List postorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + + //使用栈记录需要遍历的root + Stack stack = new Stack<>(); + if (root != null) { + stack.push(root); + } + + //栈中数据:[5,null,6,4,null,2,1,null] + while (stack.size() > 0) { + TreeNode node = stack.peek(); + + if(node!=null){ + //将该节点弹出,避免重复操作,下面再将右、中、左节点添加到栈中 + stack.pop(); + //添加中节点 + stack.push(node); + //中指针访问过,但没有处理,添加空指针节点作为标记 + stack.push(null); + //添加右节点(空节点不入栈) + if(node.right!=null){ + stack.push(node.right); + } + //添加左节点(空节点不入栈) + if(node.left!=null){ + stack.push(node.left); + } + + }else { + //只有遇到空节点的时候,才将下一个节点放入结果集 + stack.pop();//将空指针弹出 + node = stack.pop(); //重新取出栈中元素 + result.add(node.val); + } + } + return result; + } + + +} From 4b73b4cb5951914f6b3ebdbac301f5b22f2db16c Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Tue, 20 Sep 2022 18:19:06 +0800 Subject: [PATCH 26/38] =?UTF-8?q?=E5=A4=9A=E6=80=81=E3=80=81=E7=B1=BB?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E3=80=81=E5=AE=9E=E4=BE=8B=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E5=AD=A6=E4=B9=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java_learning/mutiType/InitTest.java | 120 ++++++++++++++++++ .../java_learning/mutiType/StaticTest.java | 46 +++++++ .../mutiType/clinitAndInitTest.java | 75 +++++++++++ 3 files changed, 241 insertions(+) create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/mutiType/InitTest.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/mutiType/StaticTest.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/mutiType/clinitAndInitTest.java diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/mutiType/InitTest.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/mutiType/InitTest.java new file mode 100644 index 0000000..519a9c8 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/mutiType/InitTest.java @@ -0,0 +1,120 @@ +package com.markilue.java_learning.mutiType; + +import org.junit.Test; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.mutiType + * @Author: dingjiawen + * @CreateTime: 2022-09-20 17:35 + * @Description: + * TODO 测试实例初始化 + * 1)初始化顺序: + * (1)super()或super(实参列表) 这里选择哪个,看原来构造器首行是哪句,没写,默认就是super() + * (2)非静态实例变量的显示赋值语句 + * (3)非静态代码块 + * (4)对应构造器中的代码 + * 特别说明:其中(2)和(3)是按顺序合并的,(1)一定在最前面(4)一定在最后面 + * 2)执行特点: + * 1.创建对象时,才会执行, + * 2.调用哪个构造器,就是指定它对应的实例初始化方法 + * 3.创建子类对象时,父类对应的实例初始化会被先执行,执行父类哪个实例初始化方法,看用super()还是super(实参列表) + * 3)非静态代码块和构造器: + * 1.从某种程度上来看,非静态代码块是对构造器的补充,非静态代码块总是在构造器执行之前执行。 + * 与构造器不同的是,非静态代码块是一段固定执行的代码,它不能接收任何参数。 + * 因此非静态代码块对同一个类的所有对象所进行的初始化处理完全相同。 + * 基于这个原因,不难发现非静态代码块的基本用法:如果有一段初始化处理代码对所有对象完全相同,且无须接收任何参数,就可以把这段初始化处理代码提取到非静态代码块中。 + * 2.即如果每个构造器中有相同的初始化代码,且这些初始化代码无须接收参数,就可以把它们放在非静态代码块中定义。 + * 通过把多个构造器中相同代码提取到非静态代码块中定义,能更好地提高初始代码的复用,提高整个应用的可维护性。 + * @Version: 1.0 + */ +public class InitTest { + + + //测试子父类继承,方法有重写时,初始化顺序 + @Test + public void test(){ + + Son s1 = new Son(); + System.out.println("-----------------------------"); + Son s2 = new Son("atguigu"); + + /* + 运行结果: + Son:getNumber() //子类重写getNumber()方法,那么创建子类的对象,就是调用子类的getNumber()方法,因为当前对象this是子类的对象。 + Father(1) + Son:getNumber() + Father(2) + Father()无参构造 + Son:getNumber() + Son(1) + Son:getNumber() + Son(2) + Son():无参构造 + ----------------------------- + Son:getNumber() + Father(1) + Son:getNumber() + Father(2) + Father(info)有参构造 + Son:getNumber() + Son(1) + Son:getNumber() + Son(2) + Son(info):有参构造 + */ + + + + } + + private class Father{ + private int a = getNumber(); + private String info; + { + System.out.println("Father(1)"); + } + Father(){ + System.out.println("Father()无参构造"); + } + Father(String info){ + this.info = info; + System.out.println("Father(info)有参构造"); + } + private int b = getNumber(); + { + System.out.println("Father(2)"); + } + + public int getNumber(){ + System.out.println("Father:getNumber()"); + return 1; + } + } + private class Son extends Father { + private int a = getNumber(); + { + System.out.println("Son(1)"); + } + private int b = getNumber(); + { + System.out.println("Son(2)"); + } + public Son(){ + System.out.println("Son():无参构造"); + } + public Son(String info){ + super(info); + System.out.println("Son(info):有参构造"); + } + public int getNumber(){ + System.out.println("Son:getNumber()"); + return 1; + } + } + + + + +} + diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/mutiType/StaticTest.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/mutiType/StaticTest.java new file mode 100644 index 0000000..7e799b0 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/mutiType/StaticTest.java @@ -0,0 +1,46 @@ +package com.markilue.java_learning.mutiType; + +import org.junit.Test; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.mutiType + * @Author: dingjiawen + * @CreateTime: 2022-09-20 16:50 + * @Description: TODO 测试多态的特性: + * 1)属性没有多态 + * 2)静态方法没有多态性 + * 1.静态方法不能被重写 + * 2.调用静态方法最好使用“类名.” + * @Version: 1.0 + */ +public class StaticTest { + + //测试静态方法没有多态性 + @Test + public void test() { + Father f = new Son(); + f.test();//只看编译时类型 =>father + } + + //测试属性没有多态性 + @Test + public void test1() { + Father f = new Son(); + System.out.println(f.x);//只看编译时类型 =>1 + } +} + +class Father { + int x=1; + public static void test() { + System.out.println("father"); + } +} + +class Son extends Father { + int x=2; + public static void test() { + System.out.println("son"); + } +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/mutiType/clinitAndInitTest.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/mutiType/clinitAndInitTest.java new file mode 100644 index 0000000..f66b8f3 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/mutiType/clinitAndInitTest.java @@ -0,0 +1,75 @@ +package com.markilue.java_learning.mutiType; + +import org.junit.Test; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.mutiType + * @Author: dingjiawen + * @CreateTime: 2022-09-20 17:43 + * @Description: + * TODO 测试类初始化和实例初始化: + * 1)类初始化肯定优先于实例初始化。 + * 2)类初始化只做一次。 + * 3)实例初始化是每次创建对象都要进行。 + * + * @Version: 1.0 + */ +public class clinitAndInitTest { + + public static void main(String[] args) { + Son s1 = new Son(); + System.out.println("----------------------------"); + Son s2 = new Son(); + + /* + 运行结果: + Father:static + Son:static + Father:not_static + Father()无参构造 + Son:not_static + Son()无参构造 + ---------------------------- + Father:not_static + Father()无参构造 + Son:not_static + Son()无参构造 + */ + + + } + + @Test + public void test(){ + + + + } + +// private class Father{ +// static{ +// System.out.println("Father:static"); +// } +// { +// System.out.println("Father:not_static"); +// } +// Father(){ +// System.out.println("Father()无参构造"); +// } +// } +// private class Son extends Father{ +// static{ +// System.out.println("Son:static"); +// } +// { +// System.out.println("Son:not_static"); +// } +// Son(){ +// System.out.println("Son()无参构造"); +// } +// } + + + +} From b812f6384d793d26fc859fc3e50c2d9c67aa635f Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Wed, 21 Sep 2022 12:59:31 +0800 Subject: [PATCH 27/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/markilue/leecode/test/test.java | 44 +++ .../com/markilue/leecode/tree/InvertTree.java | 126 ++++++++ .../markilue/leecode/tree/IsSymmetric.java | 277 ++++++++++++++++++ 3 files changed, 447 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/test/test.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/InvertTree.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/IsSymmetric.java diff --git a/Leecode/src/main/java/com/markilue/leecode/test/test.java b/Leecode/src/main/java/com/markilue/leecode/test/test.java new file mode 100644 index 0000000..7ed5b07 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/test/test.java @@ -0,0 +1,44 @@ +package com.markilue.leecode.test; + +import com.markilue.leecode.tree.TreeNode; +import org.junit.Test; + +import java.util.ArrayList; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.test + * @Author: dingjiawen + * @CreateTime: 2022-09-21 11:32 + * @Description: TODO + * @Version: 1.0 + */ +public class test { + + + //测试ArrayList的index是否发生变化 + @Test + public void test(){ +// ArrayList treeNodes1 = new ArrayList<>(); +// for (int i = 0; i < 4; i++) { +// treeNodes1.add(i); +// } +// for (int i = 0; i < 4; i++) { +// System.out.println(treeNodes1.remove(i)); +// +// System.out.println(treeNodes1.remove(4 - i));//java.lang.IndexOutOfBoundsException: Index: 4, Size: 3 +// System.out.println("======================="); +// } + } + + //测试null和null是否相等 + @Test + public void test1(){ + + String s1=null; + String s2=null; + + System.out.println(s1==s2); + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/InvertTree.java b/Leecode/src/main/java/com/markilue/leecode/tree/InvertTree.java new file mode 100644 index 0000000..768ae4e --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/InvertTree.java @@ -0,0 +1,126 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-21 10:15 + * @Description: + * TODO 力扣226题:翻转二叉树: + * 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 + + * @Version: 1.0 + */ +public class InvertTree { + + + @Test + public void test(){ + + TreeNode root = new TreeNode(4); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(7); + TreeNode TreeNode4 = new TreeNode(1); + TreeNode TreeNode5 = new TreeNode(3); + TreeNode TreeNode6 = new TreeNode(6); + TreeNode TreeNode7 = new TreeNode(9); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode7); + TreeNode3.setLeft(TreeNode6); + + System.out.println(invertTree1(root)); + + } + + + @Test + public void test1(){ + + TreeNode root = new TreeNode(2); +// TreeNode TreeNode2 = new TreeNode(1); +// TreeNode TreeNode3 = new TreeNode(3); +// TreeNode TreeNode4 = new TreeNode(1); +// TreeNode TreeNode5 = new TreeNode(3); +// TreeNode TreeNode6 = new TreeNode(6); +// TreeNode TreeNode7 = new TreeNode(9); + +// root.setRight(TreeNode3); +// root.setLeft(TreeNode2); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setRight(TreeNode7); +// TreeNode3.setLeft(TreeNode6); + + System.out.println(invertTree(null)); + + } + + /** + * 自己的思路:使用一个队列记录节点;每次将poll出的节点的左右对调 + * 速度超过100%,内存超过20.6% + * @param root + * @return + */ + public TreeNode invertTree(TreeNode root) { + + Queue treeNodes = new LinkedList<>(); + + if(root==null){ + return root; + } + treeNodes.offer(root); + + while (!treeNodes.isEmpty()){ + TreeNode node = treeNodes.poll(); + + TreeNode left=node.left; + node.left=node.right; + node.right=left; + + if(node.left!=null){ + treeNodes.offer(node.left); + } + if(node.right!=null){ + treeNodes.offer(node.right); + } + } + + return root; + + } + + /** + * 自己的思路(递归法): + * 速度超过100%,内存超过83.53% + * 本质上可以看做是前序遍历 + * @param root + * @return + */ + public TreeNode invertTree1(TreeNode root) { + + + if(root==null){ + return root; + } + + //交换左右 + TreeNode left=root.left; + root.left=root.right; + root.right=left; + //递归 + invertTree1(root.left); + invertTree1(root.right); + + return root; + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/IsSymmetric.java b/Leecode/src/main/java/com/markilue/leecode/tree/IsSymmetric.java new file mode 100644 index 0000000..6dd2993 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/IsSymmetric.java @@ -0,0 +1,277 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedList; +import java.util.Queue; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-21 10:44 + * @Description: TODO 力扣101题 对称二叉树: + * 给你一个二叉树的根节点 root , 检查它是否轴对称。 + * @Version: 1.0 + */ +public class IsSymmetric { + + @Test + public void test() { + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(2); + TreeNode TreeNode4 = new TreeNode(3); + TreeNode TreeNode5 = new TreeNode(4); + TreeNode TreeNode6 = new TreeNode(4); + TreeNode TreeNode7 = new TreeNode(3); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode7); + TreeNode3.setLeft(TreeNode6); + + System.out.println(isSymmetric2(root)); + } + + @Test + public void test1() { + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(2); + TreeNode TreeNode4 = new TreeNode(3); +// TreeNode TreeNode5 = new TreeNode(4); +// TreeNode TreeNode6 = new TreeNode(4); + TreeNode TreeNode7 = new TreeNode(3); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); +// TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode4); + TreeNode3.setLeft(TreeNode7); +// TreeNode3.setLeft(TreeNode6); + + System.out.println(isSymmetric3(root)); + } + + + /** + * 自己的思路:这里可以节点之前层序遍历的思路->每次循环队列里只放那一层的节点,通过for循环判断是否对称 + * 速度击败21.44%,内存击败38.97% + * + * @param root + * @return + */ + public boolean isSymmetric(TreeNode root) { + + if (root == null) { + return false; + } + + Deque treeNodes = new LinkedList<>(); + + if (root.left != null) { + treeNodes.addFirst(root.left); + } + + if (root.right != null) { + treeNodes.addLast(root.right); + } + + while (!treeNodes.isEmpty()) { + int size = treeNodes.size(); + + if (size % 2 != 0) { + return false; + } + Deque treeNodeTemp = new LinkedList<>(); + for (int i = 0; i < size / 2; i++) { + TreeNode first = treeNodes.removeFirst(); + TreeNode last = treeNodes.removeLast(); + if (first.val != last.val) { + return false; + } + boolean flag = false; + boolean flag1 = false; + + if (first.right != null) { + treeNodeTemp.addFirst(first.right); + flag1 = true; + } + + if (first.left != null) { + treeNodeTemp.addFirst(first.left); + flag = true; + } + + if (last.left != null) { + if (!flag1) { + return false; + } else { + treeNodeTemp.addLast(last.left); + } + } else { + if (flag1) { + return false; + } + } + + if (last.right != null) { + if (!flag) { + return false; + } else { + treeNodeTemp.addLast(last.right); + } + } else { + if (flag) { + return false; + } + } + + } + treeNodes = treeNodeTemp; + } + + return true; + + + } + + + /** + * 自己的思路改进版:减少null值判断 + * 速度击败21.44%,内存击败25.90% + * + * @param root + * @return + */ + public boolean isSymmetric1(TreeNode root) { + + if (root == null) { + return false; + } + + Deque treeNodes = new LinkedList<>(); + + treeNodes.addFirst(root.left); + treeNodes.addLast(root.right); + + + while (!treeNodes.isEmpty()) { + int size = treeNodes.size(); + + if (size % 2 != 0) { + return false; + } + Deque treeNodeTemp = new LinkedList<>(); + for (int i = 0; i < size / 2; i++) { + TreeNode first = treeNodes.removeFirst(); + TreeNode last = treeNodes.removeLast(); + + if (first != null && last != null) { + if (first.val != last.val) { + return false; + } + treeNodeTemp.addFirst(first.right); + treeNodeTemp.addFirst(first.left); + treeNodeTemp.addLast(last.left); + treeNodeTemp.addLast(last.right); + } else if (first == null && last == null) { + continue; + } else { + return false; + } + } + treeNodes = treeNodeTemp; + } + + return true; + + + } + + + /** + * 代码随想录思路递归版: + * 速度击败100%,内存击败57.51% + * + * @param root + * @return + */ + public boolean isSymmetric2(TreeNode root) { + + if (root == null) { + return false; + } + return compare(root.left, root.right); + } + + + public boolean compare(TreeNode left, TreeNode right) { + + if (left == null && right == null) { + return true; + } else if (left != null && right == null) { + return false; + } else if (left == null && right != null) { + return false; + } else if (left != null && right != null) { + if (left.val != right.val) { + return false; + } + } + + //如果左右相等,递归比较下面的 + boolean f1 = compare(left.left, right.right); + boolean f2 = compare(left.right, right.left); + + return f1 && f2; + + } + + /** + * 代码随想录思路迭代版:自己的思路改进——>没必要使用双端队列,只需要每次成对取出来就行了 + * 速度击败21.44%,内存击败83.51% + * + * @param root + * @return + */ + public boolean isSymmetric3(TreeNode root) { + + if (root == null) { + return true; + } + + Queue treeNodes = new LinkedList<>(); + + treeNodes.offer(root.left); + treeNodes.offer(root.right); + + + while (!treeNodes.isEmpty()) { + + TreeNode first = treeNodes.poll(); + TreeNode last = treeNodes.poll(); + + if (first != null && last != null) { + if (first.val != last.val) { + return false; + } + treeNodes.offer(first.right); + treeNodes.offer(last.left); + treeNodes.offer(first.left); + treeNodes.offer(last.right); + } else if (first == null && last == null) { + continue; + } else { + return false; + } + } + + return true; + } +} From 39fc3ed9a8ddc1aa4139831617efb7e4f4750e68 Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Thu, 22 Sep 2022 13:19:38 +0800 Subject: [PATCH 28/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/markilue/leecode/tree/MaxDepth.java | 214 ++++++++++++++++++ .../com/markilue/leecode/tree/MinDepth.java | 179 +++++++++++++++ 2 files changed, 393 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/MaxDepth.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/MinDepth.java diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/MaxDepth.java b/Leecode/src/main/java/com/markilue/leecode/tree/MaxDepth.java new file mode 100644 index 0000000..7edad50 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/MaxDepth.java @@ -0,0 +1,214 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-22 10:23 + * @Description: TODO 力扣104题:二叉树的最大深度: + * 给定一个二叉树,找出其最大深度。 + * 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 + * 说明: 叶子节点是指没有子节点的节点。 + * @Version: 1.0 + */ +public class MaxDepth { + + @Test + public void test() { + + TreeNode root = new TreeNode(3); + TreeNode TreeNode2 = new TreeNode(9); + TreeNode TreeNode3 = new TreeNode(20); +// TreeNode TreeNode4 = new TreeNode(4); +// TreeNode TreeNode5 = new TreeNode(5); + TreeNode TreeNode6 = new TreeNode(15); + TreeNode TreeNode7 = new TreeNode(7); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode7); + TreeNode3.setLeft(TreeNode6); + + System.out.println(maxDepth(root)); + + } + + @Test + public void test1() { + + TreeNode root = new TreeNode(3); + TreeNode TreeNode2 = new TreeNode(9); + TreeNode TreeNode3 = new TreeNode(20); +// TreeNode TreeNode4 = new TreeNode(4); +// TreeNode TreeNode5 = new TreeNode(5); + TreeNode TreeNode6 = new TreeNode(15); + TreeNode TreeNode7 = new TreeNode(7); + +// root.setRight(TreeNode3); +// root.setLeft(TreeNode2); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setRight(TreeNode7); +// TreeNode3.setLeft(TreeNode6); + + System.out.println(maxDepth(root)); + + } + + + @Test + public void test2(){ + TreeNode root = new TreeNode(4); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(6); + TreeNode TreeNode4 = new TreeNode(1); + TreeNode TreeNode5 = new TreeNode(3); + TreeNode TreeNode6 = new TreeNode(5); + + root.setLeft(TreeNode2); + root.setRight(TreeNode3); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + TreeNode3.setLeft(TreeNode6); + + int integers = maxDepth2(root); + + System.out.println(integers); + + } + + + + /** + * 自己思路递归法,传递当前深度,然后比较左右子树的深度 + * 速度击败100%,内存击败39.53% + * @param root + * @return + */ + public int maxDepth(TreeNode root) { + + return deep(root,0); + + } + + public int deep(TreeNode root, int depth) { + if (root == null) { + return depth; + } + depth += 1; + int leftDepth = deep(root.left, depth); + int rightDepth = deep(root.right, depth); + + return leftDepth > rightDepth ? leftDepth : rightDepth; + + + } + + + /** + * 不传深度的版本 + * @param root + * @return + */ + public int deep1(TreeNode root) { + if (root == null) { + return 0; + } + + int leftDepth = deep1(root.left); + int rightDepth = deep1(root.right); + + return (leftDepth > rightDepth ? leftDepth : rightDepth)+1; + + + } + + + /** + * 自己思路迭代法:可以使用栈的前序遍历或者Morris遍历来解决,这里尝试使用Morris遍历 + * TODO 尚且有问题,Morris前序遍历写出来了,但是不知道depth在何时加,感觉很乱,不知何时用temp何时用depth + * + * @param root + * @return + */ + public int maxDepth1(TreeNode root) { + + if(root==null){ + return 0; + } + int depth=1; + TreeNode node1=root; + TreeNode node2=null; + + while (node1!=null){ + node2=node1.left; + int tempDepth=depth; + if(node2!=null){ + //找到回到node1的节点 + while (node2.right!=null&&node2.right!=node1){ + node2=node2.right; + } + + //判断上面是从什么条件出来的 + if(node2.right==null){ + //从第一个条件出来的 + + node2.right=node1; + //放心将node1左移 + node1=node1.left; + depth+=1; + }else { + //node2已经遍历过了 + node2.right=null; + } + }else { + //左边遍历完了,往右移 + node1=node1.right; + } + + + + } + + return depth; + + } + + /** + * 自己思路迭代法:可以使用层序遍历 + * 速度击败19.47% 内存击败85.16% + * @param root + * @return + */ + public int maxDepth2(TreeNode root) { + + if(root==null){ + return 0; + } + + int depth=0; + Queue queue = new LinkedList<>(); + queue.offer(root); + + while (queue.size()>0){ + int size=queue.size(); + depth+=1; + for (int i = 0; i < size; i++) { + TreeNode poll = queue.poll(); + if(poll.left!=null)queue.offer(poll.left); + if(poll.right!= null)queue.offer(poll.right); + } + } + return depth; + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/MinDepth.java b/Leecode/src/main/java/com/markilue/leecode/tree/MinDepth.java new file mode 100644 index 0000000..0d880d3 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/MinDepth.java @@ -0,0 +1,179 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-22 11:28 + * @Description: TODO 力扣111题 二叉树的最小深度问题: + * 给定一个二叉树,找出其最小深度。 + * 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 + * 说明:叶子节点是指没有子节点的节点。 + * 注意:深度是从根节点到最近叶子结点的最短路径上的节点数量。左右孩子都为空的节点才是叶子结点 + * @Version: 1.0 + */ +public class MinDepth { + + @Test + public void test() { + + TreeNode root = new TreeNode(3); + TreeNode TreeNode2 = new TreeNode(9); + TreeNode TreeNode3 = new TreeNode(20); +// TreeNode TreeNode4 = new TreeNode(4); +// TreeNode TreeNode5 = new TreeNode(5); + TreeNode TreeNode6 = new TreeNode(15); + TreeNode TreeNode7 = new TreeNode(7); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode7); + TreeNode3.setLeft(TreeNode6); + + System.out.println(minDepth1(root)); + + } + + @Test + public void test1() { + + TreeNode root = new TreeNode(3); + TreeNode TreeNode2 = new TreeNode(9); + TreeNode TreeNode3 = new TreeNode(20); +// TreeNode TreeNode4 = new TreeNode(4); +// TreeNode TreeNode5 = new TreeNode(5); + TreeNode TreeNode6 = new TreeNode(15); + TreeNode TreeNode7 = new TreeNode(7); + +// root.setRight(TreeNode3); +// root.setLeft(TreeNode2); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setRight(TreeNode7); +// TreeNode3.setLeft(TreeNode6); + + System.out.println(minDepth1(root)); + + } + + @Test + public void test2() { + + TreeNode root = new TreeNode(2); + TreeNode TreeNode2 = new TreeNode(3); + TreeNode TreeNode3 = new TreeNode(4); + TreeNode TreeNode4 = new TreeNode(5); + TreeNode TreeNode5 = new TreeNode(6); +// TreeNode TreeNode6 = new TreeNode(15); +// TreeNode TreeNode7 = new TreeNode(7); + +// root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode3); + TreeNode3.setLeft(TreeNode4); + TreeNode4.setLeft(TreeNode5); +// TreeNode5.setLeft(TreeNode7); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setRight(TreeNode7); +// TreeNode3.setLeft(TreeNode7); + + System.out.println(minDepth(root)); + + } + + + /** + * 自己思路递归法:由于必须是叶子节点才算完,所以需要将出来的条件变为判断当前节点是否还有子节点 + * 速度击败66.79%,内存击败69.22% + * @param root + * @return + */ + public int minDepth(TreeNode root) { + + if (root == null) { + return 0; + } + + return deep1(root); + + } + + public int deep(TreeNode node) { + if (node.left == null && node.right == null) { + return 1; + } + + int deep1=Integer.MAX_VALUE; + int deep2=Integer.MAX_VALUE; + if(node.left!=null){ + deep1 = deep(node.left); + } + if(node.right!=null){ + deep2 = deep(node.right); + } + + + return (deep1 < deep2 ? deep1 : deep2) + 1; + + } + + /** + * 改进版:不需要全部遍历完,找到第一个叶子结点就可以return了 + * 似乎没有改进:速度超过66.5%,内存超过37.25% + * @param node + * @return + */ + public int deep1(TreeNode node) { + if (node.left != null && node.right != null) { + return Math.min(deep(node.left),deep(node.right))+1; + }else if(node.right != null){ + return deep(node.right)+1; + }else if(node.left != null){ + return deep(node.left)+1; + }else { + return 1; + } + } + + /** + * 自己思路层序遍历: + * 速度击败66.79%,内存击败69.22% + * @param root + * @return + */ + public int minDepth1(TreeNode root) { + + if (root == null) { + return 0; + } + + Queue treeNodes = new LinkedList<>(); + int depth=0; + + treeNodes.offer(root); + while (!treeNodes.isEmpty()){ + int size = treeNodes.size(); + depth+=1; + + for (int i = 0; i < size; i++) { + TreeNode poll = treeNodes.poll(); + //层序遍历,找到的叶子结点一定是第一个叶子结点 + if(poll.left==null&&poll.right==null){ + return depth; + } + if(poll.left!=null)treeNodes.offer(poll.left); + if(poll.right!=null)treeNodes.offer(poll.right); + } + } + + + return depth; + } +} From 3efc52a16bd7389730fe898d1f53d1851824a020 Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Thu, 22 Sep 2022 19:12:10 +0800 Subject: [PATCH 29/38] =?UTF-8?q?=E5=86=85=E9=83=A8=E7=B1=BB=E3=80=81?= =?UTF-8?q?=E6=9E=9A=E4=B8=BE=E3=80=81=E6=B3=A8=E8=A7=A3=E5=AD=A6=E4=B9=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotationTest/AnnotationTest.java | 96 +++++++++ .../java_learning/enumTest/enumTest.java | 101 +++++++++ .../innerclass/StaticInnerClass.java | 57 +++++ .../innerclass/UnStaticInnerClass.java | 114 ++++++++++ .../innerclass/partInnerClass.java | 61 ++++++ .../interfaceTest/InterfaceTest.java | 199 ++++++++++++++++++ .../java_learning/interfaceTest/Problem.java | 80 +++++++ 7 files changed, 708 insertions(+) create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/annotationTest/AnnotationTest.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/enumTest/enumTest.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/StaticInnerClass.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/UnStaticInnerClass.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/partInnerClass.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/interfaceTest/InterfaceTest.java create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/interfaceTest/Problem.java diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/annotationTest/AnnotationTest.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/annotationTest/AnnotationTest.java new file mode 100644 index 0000000..c7b0a15 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/annotationTest/AnnotationTest.java @@ -0,0 +1,96 @@ +package com.markilue.java_learning.annotationTest; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.annotationTest + * @Author: dingjiawen + * @CreateTime: 2022-09-22 18:58 + * @Description: + * TODO 测试注解: + * 1)一个完整的注解有三个部分: + * 1.注解的声明:就如同类、方法、变量等一样,需要先声明后使用 + * 2.注解的使用:用于注解在包、类、方法、属性、构造、局部变量等上面的10个位置中一个或多个位置 + * 3.注解的读取:有一段专门用来读取这些使用的注解,然后根据注解信息作出相应的处理,这段程序称为注解处理流程,这也是注解区别与普通注释最大的不同。 + * 2)系统预定义的三个最基本的注解: + * 1、@Override: + * 用于检测被修饰的方法为有效的重写方法,如果不是,则报编译错误! + * 只能标记在方法上 + * 它会被编译器程序读取。 + * 2.@Deprecated: + * 用于表示被标记的数据已经过时,不建议使用。 + * 可以用于修饰 属性、方法、构造、类、包、局部变量、参数。 + * 它会被编译器程序读取。 + * 3.@SuppressWarnings: + * 抑制编译警告。 + * 可以用于修饰类、属性、方法、构造、局部变量、参数 + * 它会被编译器程序读取。 + * @Version: 1.0 + */ +public class AnnotationTest { + + @SuppressWarnings({"unused","rawtypes", "unchecked"}) + @Test + public void test(){ + + int i; + //可以发现:这里没有声明List类型,仍然没有报错 + List list = new ArrayList(); + list.add(""); + list.add(123); + list.add(""); + + Father f = new Son(); + f.show(); + f.methodOl(); + } + + +} + + +class Father{ + @Deprecated + public void show() { + + } + public void methodOl() { + System.out.println("Father Method"); + } + public void print1n(){ + System.out.println("Father Method"); + } + public int sum(int... nums){ + int sum = 0; + for (int i = 0; i < nums.length; i++) { + sum += nums[i]; + } + return sum; + } +} + +class Son extends Father{ + +/* @Override + public void method01() { + System.out.println("Son Method"); + } + + @Override + public void println(){ + System.out.println("Father Method"); + } + + @Override + public long sum(int[] nums){ + int sum = 0; + for (int i = 0; i < nums.length; i++) { + sum += nums[i]; + } + return sum; + }*/ +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/enumTest/enumTest.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/enumTest/enumTest.java new file mode 100644 index 0000000..b63bd3b --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/enumTest/enumTest.java @@ -0,0 +1,101 @@ +package com.markilue.java_learning.enumTest; + +import org.junit.Test; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.enumTest + * @Author: dingjiawen + * @CreateTime: 2022-09-22 18:43 + * @Description: + * TODO 测试枚举类: + * 1)枚举类的要求和特点: + * 1.枚举类的常量对象列表必须在枚举类的首行,因为是常量,所以建议大写。 + * 2.如果常量对象列表后面没有其他代码,那么“;”可以省略,否则不可以省略“;”。 + * 3.编译器给枚举类默认提供的是private的无参构造,如果枚举类需要的是无参构造,就不需要声明,写常量对象列表时也不用加参数。 + * 4.如果枚举类需要的是有参构造,需要手动定义private的有参构造,调用有参构造的方法就是在常量对象名后面加(实参列表)就可以。 + * 5.枚举类默认继承的是java.lang.Enum类,因此不能再继承其他的类型。 + * 6.JDK1.5之后switch,提供支持枚举类型,case后面可以写枚举常量名。 + * 2)枚举类的常用方法: + * 1.toString(): 默认返回的是常量名(对象名),可以继续手动重写该方法! + * 2.name():返回的是常量名(对象名) 【很少使用】 + * 3.ordinal():返回常量的次序号,默认从0开始 + * 4.values():返回该枚举类的所有的常量对象,返回类型是当前枚举的数组类型,是一个静态方法 + * 5.valueOf(String name):根据枚举常量对象名称获取枚举对象 + * 3)枚举类也是类,可以实现接口,可以同时实现多个接口。可以统一实现,也可以用匿名内部类的形式,单独给某个常量对象实现抽象方法。 + * @Version: 1.0 + */ +public class enumTest { + + //枚举类常用方法测试 + @Test + public void test(){ + Season[] values = Season.values(); + System.out.println(Season.SPRING.equals(1) ); //false + System.out.println(values[1].ordinal()); //1 + for (int i = 0; i < values.length; i++) { + switch(values[i]){ + case SPRING: + System.out.println(values[i]+":春暖花开,万物复苏"); //SPRING:春暖花开,万物复苏 + break; + case SUMMER: + System.out.println(values[i]+":百花争艳,郁郁葱葱"); + break; + case AUTUMN: + System.out.println(values[i]+":菊桂飘香,百树凋零"); + break; + case WINTER: + System.out.println(values[i]+":梅花独开,大地一色"); + break; + } + } + } + + + @Test + public void test1(){ + Season[] values = Season.values(); + System.out.println(Season.SPRING.equals(1) ); //false + System.out.println(values[1].ordinal()); //1 + for (int i = 0; i < values.length; i++) { + switch(values[i]){ + case SPRING: + System.out.println(values[i]+":春暖花开,万物复苏"); //SPRING:春暖花开,万物复苏 + break; + case SUMMER: + System.out.println(values[i]+":百花争艳,郁郁葱葱"); + break; + case AUTUMN: + System.out.println(values[i]+":菊桂飘香,百树凋零"); + break; + case WINTER: + System.out.println(values[i]+":梅花独开,大地一色"); + break; + } + } + } +} + + +enum Season{ + SPRING,SUMMER,AUTUMN,WINTER +} + + +//枚举类实现抽象方法测试 +interface Windiness{ + void wind(); +} +enum Season1 implements Windiness{ + SPRING,SUMMER(){ + @Override + public void wind() { + System.out.println("刮台风"); + } + },AUTUMN,WINTER; + + @Override + public void wind() { + System.out.println("刮风"); + } +} \ No newline at end of file diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/StaticInnerClass.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/StaticInnerClass.java new file mode 100644 index 0000000..80f54e0 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/StaticInnerClass.java @@ -0,0 +1,57 @@ +package com.markilue.java_learning.innerclass; + +import org.junit.Test; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.innerclass + * @Author: dingjiawen + * @CreateTime: 2022-09-22 17:12 + * @Description: + * TODO 测试静态内部类: + * 1)和外部类一样,它只是定义在外部类中的另一个完整的类结构 + * 1.可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关 + * 2.可以在静态内部类中声明属性、方法、构造器等结构,包括静态成员 + * 3.可以使用abstract修饰,因此它也可以被其他类继承 + * 4.可以使用final修饰,表示不能被继承 + * 5.编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和$符号。 + * 2)和外部类不同的是,它可以允许四种权限修饰符:public,protected,缺省,private + * 1.外部类只允许public或缺省的 + * 3)只可以在静态内部类中使用外部类的静态成员,哪怕是私有的 + * 1.在静态内部类中不能使用外部类的非静态成员哦 + * 4)在外部类的外面不需要通过外部类的对象就可以创建静态内部类的对象 + * + * TODO + * 值得注意的是:其实严格的讲(在James Gosling等人编著的《The Java Language Specification》)静态内部类不是内部类,而是类似于C++的嵌套类的概念, + * 外部类仅仅是静态内部类的一种命名空间的限定名形式而已。所以接口中的内部类通常都不叫内部类,因为接口中的内部成员都是隐式是静态的。例如:Map.Entry。 + * @Version: 1.0 + */ +public class StaticInnerClass { + + @Test + public void test(){ + Outer2.Inner in= new Outer2.Inner(); //4) + in.inMethod(); //非静态方法可以通过new了对象以后使用 + + Outer2.Inner.inTest(); //静态方法可以直接使用 + } + + + +} + + +class Outer2{ + private static int a = 1; + private int b = 2; + protected static class Inner{ + static int d = 4;//可以 + void inMethod(){ + System.out.println("out.a = " + a); +// System.out.println("out.b = " + b);//错误的 3) + } + static void inTest(){ + System.out.println("out.a = " + a); + } + } +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/UnStaticInnerClass.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/UnStaticInnerClass.java new file mode 100644 index 0000000..05f4318 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/UnStaticInnerClass.java @@ -0,0 +1,114 @@ +package com.markilue.java_learning.innerclass; + +import org.junit.Test; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.innerclass + * @Author: dingjiawen + * @CreateTime: 2022-09-22 16:49 + * @Description: + * TODO 测试非静态内部类: + * 1)和外部类一样,它只是定义在外部类中的另一个完整的类结构 + * 1.可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关 + * 2.可以在非静态内部类中声明属性、方法、构造器等结构,但是**不允许声明静态成员**,但是可以继承父类的静态成员,而且可以声明静态常量。 + * 3.可以使用abstract修饰,因此它也可以被其他类继承 + * 4.可以使用final修饰,表示不能被继承 + * 5.编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和$符号。 + * 2)和外部类不同的是,它可以允许四种权限修饰符:public,protected,缺省,private + * 1.外部类只允许public或缺省的 + * 3)还可以在非静态内部类中使用外部类的所有成员,哪怕是私有的 + * 4)在外部类的静态成员中不可以使用非静态内部类哦 + * 1.就如同静态方法中不能访问本类的非静态成员变量和非静态方法一样 + * 5)在外部类的外面必须通过外部类的对象才能创建非静态内部类的对象 + * 1.因此在非静态内部类的方法中有两个this对象,一个是外部类的this对象,一个是内部类的this对象 + * @Version: 1.0 + */ +public class UnStaticInnerClass { + + + @Test + public void test(){ + Outer out = new Outer(); + Outer.Inner in= out.new Inner(); //第五点5) + in.inMethod(); + + Outer.Inner inner = out.getInner(); + inner.inMethod(); + } +} + +class Father{ + protected static int c = 3; +} +class Outer{ + private static int a = 1; + private int b = 2; + protected class Inner extends Father{ + // static int d = 4;//错误 1)的第2点 + int b = 5; + void inMethod(){ + System.out.println("out.a = " + a); //3) + System.out.println("out.b = " + Outer.this.b); + System.out.println("in.b = " + b); + System.out.println("father.c = " + c); + } + } + + public static void outMethod(){ +// Inner in = new Inner();//错误的 //4) + } + public Inner getInner(){ + return new Inner(); + } +} + +//简单面试题 +class Test1{ + public Test1(){ + Inner s1 = new Inner(); + s1.a = 10; + Inner s2 = new Inner(); + s2.a = 20; + Test1.Inner s3 = new Test1.Inner(); + System.out.println(s3.a); + } + class Inner{ + public int a = 5; + } + public static void main(String[] args) { + Test1 t = new Test1(); + Inner r = t.new Inner(); + System.out.println(r.a); //5 5 + } +} + + +//高难面试题 +class TestInner{ + + public static void main(String[] args){ + Outer1.Inner in = new Sub(); + in.method();//输出 hello inner + } + +} + +class Outer1 { + abstract class Inner{ + abstract void method(); + } +} +class Sub extends Outer1.Inner{ //注意这里是Outer1.Inner + //不写这个构造方法,上面的Outer1.Inner会报错 + static Outer1 out = new Outer1(); + Sub(){ + out.super(); + } + + @Override + void method() { + System.out.println("hello inner"); + } + +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/partInnerClass.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/partInnerClass.java new file mode 100644 index 0000000..907e908 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/partInnerClass.java @@ -0,0 +1,61 @@ +package com.markilue.java_learning.innerclass; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.innerclass + * @Author: dingjiawen + * @CreateTime: 2022-09-22 18:03 + * @Description: + * TODO 测试局部内部类: + * 1)和外部类一样,它只是定义在外部类的`某个方法`中的另一个完整的类结构 + * 1.可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关 + * 2.可以在局部内部类中声明属性、方法、构造器等结构,但不包括静态成员,除非是从父类继承的或静态常量 + * 3.可以使用abstract修饰,因此它也可以被同一个方法的在它后面的其他内部类继承 + * 4.可以使用final修饰,表示不能被继承 + * 5.编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名、$符号、编号。 + * 这里有编号是因为同一个外部类中,不同的方法中存在相同名称的局部内部类 + * 2)和成员内部类不同的是,它前面不能有权限修饰符等 + * 3)局部内部类如同局部变量一样,有作用域 + * 4)局部内部类中使用能访问外部类的静态还是非静态的成员,取决于所在的方法 + * 5)局部内部类中还可以使用所在方法的局部常量,即用final声明的局部变量 + * 1.JDK1.8之后,如果某个局部变量在局部内部类中被使用了,自动加final + * 2.为什么一定要使用final? 因为如果c不是final的,那么method方法执行完,method的栈空间就释放了,那么c也就消失了,如果方法返回值中包含这个类的这个值则无法取到 + * @Version: 1.0 + */ +public class partInnerClass { +} + + +class Outer3{ + private static int a = 1; + private int b = 2; + + public static void outMethod(){ + final int c = 3; //5) + class Inner{ //2) + public void inMethod(){ + System.out.println("out.a = " + a); +// System.out.println("out.b = " + b);//错误的,因为outMethod是静态的 //4) + System.out.println("out.local.c = " + c); + } + } + + Inner in = new Inner(); + in.inMethod(); + } + + public void outTest(){ + final int c = 3; + class Inner{ //5) + public void inMethod(){ + System.out.println("out.a = " + a); + System.out.println("out.b = " + b);//可以,因为outTest是飞静态的 + System.out.println("method.c = " + c); + } + } + + Inner in = new Inner(); + in.inMethod(); + } + +} diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/interfaceTest/InterfaceTest.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/interfaceTest/InterfaceTest.java new file mode 100644 index 0000000..0038837 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/interfaceTest/InterfaceTest.java @@ -0,0 +1,199 @@ +package com.markilue.java_learning.interfaceTest; + +import org.junit.Test; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.interfaceTest + * @Author: dingjiawen + * @CreateTime: 2022-09-22 15:28 + * @Description: + * TODO 测试java中的接口: + * 1)那么接口的内部主要就是 封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法(JDK 9)。 + * 2)接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次。 + * 3)当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的抽象方法重名,子类就近选择执行父类的成员方法。参见ABCD + * 4)当一个类同时实现了多个接口,而多个接口中包含方法签名相同的默认方法时,必须要作出选择(可以重写 也可以选择一个继承)。参见EFGH + * 5)一个接口能继承另一个或者多个接口,接口的继承也使用 `extends` 关键字,子接口继承父接口的方法。 + * 1.子接口重写默认方法时,default关键字可以保留。 + * 2.子类重写默认方法时,default关键字不可以保留。 + * 6)接口中其他成员特点: + * 1.接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用public static final修饰。 + * 2.接口中,没有构造方法,不能创建对象。 + * 3.接口中,没有静态代码块。 + * 7)接口类型的变量与实现类的对象之间,也可以构成多态引用。通过接口类型的变量调用方法,最终执行的是你new的实现类对象实现的方法体。 + * 8)常用接口:java.lang.Comparable、java.util.Comparator、java.lang.Cloneable: + * 1.java.lang.Comparable:实现这个接口的类需要实现compareTo(Object obj)方法 从而实现与另一个对象的比较; + * 如果当前比obj大,则返回一个正整数;等于返回0;小于返回负整数 + * 2.java.util.Comparator:实现这个接口的类需要实现compare(Object o1,Object o2)方法 当我们修改不了源码,又希望这类对象能做比较的时候使用; + * 如果当前比obj大,则返回一个正整数;等于返回0;小于返回负整数 + * 3.java.lang.Cloneable:实现这个接口的类需要实现clone()方法,可以实现造一个和当前对象各种属性值一模一样的对象。当然地址肯定不同。 + * @Version: 1.0 + */ +public class InterfaceTest { + + + //测试第三点3) + @Test + public void test(){ + C c = new C(); + c.methodA(); + + B b = new B(); + b.methodA(); + /* + 打印结果: + DDDDDDDDDDDD + BBBBBBBBBBBB + */ + } + + //测试第七点7) + @Test + public void test1(){ + A c = new C(); + c.methodA(); + + A b = new B(); + b.methodA(); + /* + 打印结果: + DDDDDDDDDDDD + BBBBBBBBBBBB + */ + } + + //测试第八点8) + @Test + public void test2() throws CloneNotSupportedException { + Teacher src = new Teacher(1,"柴老师"); + Object clone = src.clone(); + System.out.println(clone); + System.out.println(src == clone); + System.out.println(src.equals(clone)); + + System.out.println(new Object().getClass()); + System.out.println(clone.getClass()); + /* + 结果: + Teacher [id=1, name=柴老师] + false + true + + class java.lang.Object + class com.markilue.java_learning.interfaceTest.Teacher + */ + } + +} + +interface A { + public default void methodA(){ + System.out.println("AAAAAAAAAAAA"); + } +} + +class D { + public void methodA(){ + System.out.println("DDDDDDDDDDDD"); + } +} + +class C extends D implements A { + // 未重写methodA方法 +} +class B extends D implements A{ + //当然也可以选择重写 + public void methodA(){ + System.out.println("BBBBBBBBBBBB"); + } +} + + +interface E{ + public default void d(){ + System.out.println("今晚7点-8点陪我吃饭看电影"); + } +} + +interface F{ + public default void d(){ + System.out.println("今晚7点-8点陪我逛街吃饭"); + } +} + +//选择保留其中一个,通过“接口名.super.方法名"的方法选择保留哪个接口的默认方法。 +class G implements E,F{ + + @Override + public void d() { + E.super.d(); + } + +} + +//选择自己完全重写: +class H implements E,F{ + @Override + public void d() { + System.out.println("自己待着"); + } +} + +class Teacher implements Cloneable{ + private int id; + private String name; + public Teacher(int id, String name) { + super(); + this.id = id; + this.name = name; + } + public Teacher() { + super(); + } + public int getId() { + return id; + } + public void setId(int id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + @Override + public String toString() { + return "Teacher [id=" + id + ", name=" + name + "]"; + } + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + id; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Teacher other = (Teacher) obj; + if (id != other.id) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } +} \ No newline at end of file diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/interfaceTest/Problem.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/interfaceTest/Problem.java new file mode 100644 index 0000000..c2c1117 --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/interfaceTest/Problem.java @@ -0,0 +1,80 @@ +package com.markilue.java_learning.interfaceTest; + +import org.junit.Test; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.interfaceTest + * @Author: dingjiawen + * @CreateTime: 2022-09-22 16:07 + * @Description: + * TODO 接口常见面试题排错 + * 1)第一题参见ZXS类 + * @Version: 1.0 + */ +public class Problem { + + +} + +interface Z{ + int x=0; +} + +class X{ + int x=1; +} + +class S extends X implements Z{ + public void px(){ +// System.out.println(x); + } + + public static void main(String[] args) { + new S().px(); + //这里直接报错了: com.markilue.java_learning.interfaceTest.X 中的变量 x 和 com.markilue.java_learning.interfaceTest.Z 中的变量 x 都匹配 + } + +} + +interface Playable{ + void play(); +} + +interface Bounceable{ + void play(); +} + +interface Rollable extends Playable,Bounceable{ + Ball ball=new Ball("PingPang"); +} + +class Ball implements Rollable{ + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Ball(String name) { + this.name = name; + } + + public Ball() { + } + + @Override + public void play() { + Ball football = new Ball("football"); + System.out.println(ball.getName()); + } + + public static void main(String[] args) { + new Ball().play();//PingPang + + } +} From 28da35a5f8caf1399da747aa8dbf50a1abb7b1a0 Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Fri, 23 Sep 2022 13:29:51 +0800 Subject: [PATCH 30/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/markilue/leecode/test/test.java | 8 +- .../leecode/tree/BinaryTreePaths.java | 174 ++++++++++++++++++ .../com/markilue/leecode/tree/IsBalance.java | 133 +++++++++++++ 3 files changed, 312 insertions(+), 3 deletions(-) create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/BinaryTreePaths.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/IsBalance.java diff --git a/Leecode/src/main/java/com/markilue/leecode/test/test.java b/Leecode/src/main/java/com/markilue/leecode/test/test.java index 7ed5b07..b1e34e2 100644 --- a/Leecode/src/main/java/com/markilue/leecode/test/test.java +++ b/Leecode/src/main/java/com/markilue/leecode/test/test.java @@ -35,10 +35,12 @@ public class test { @Test public void test1(){ - String s1=null; - String s2=null; + String s1="1"; + String s2="2"; - System.out.println(s1==s2); + s1=s1+2; + + System.out.println(s1); } } diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/BinaryTreePaths.java b/Leecode/src/main/java/com/markilue/leecode/tree/BinaryTreePaths.java new file mode 100644 index 0000000..303a8de --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/BinaryTreePaths.java @@ -0,0 +1,174 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-23 11:48 + * @Description: TODO 力扣257题 二叉树的所有路径: + * 给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。 + * 叶子节点 是指没有子节点的节点。 + * @Version: 1.0 + */ +public class BinaryTreePaths { + + @Test + public void test() { + TreeNode root = new TreeNode(3); + TreeNode TreeNode2 = new TreeNode(9); + TreeNode TreeNode3 = new TreeNode(20); +// TreeNode TreeNode4 = new TreeNode(4); +// TreeNode TreeNode5 = new TreeNode(5); + TreeNode TreeNode6 = new TreeNode(15); + TreeNode TreeNode7 = new TreeNode(7); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode7); + TreeNode3.setLeft(TreeNode6); + + System.out.println(binaryTreePaths1(root)); + + } + + + /** + * 本人递归法: 本质上算是广度优先算法 + * 可以发现官方代码之所以简洁是因为他把当时path记录了下来,就不需要一直通过遍历去加上对应的节点 + * 速度超过49.92%,内存超过34% + * @param root + * @return + */ + public List binaryTreePaths(TreeNode root) { + + List result1 = new ArrayList<>(); + if (root == null) { + return new ArrayList<>(); + } + result1.add(new StringBuilder().append(root.val).append("->")); + path(root, result1); + List result = new ArrayList<>(); + for (int i = 0; i < result1.size(); i++) { + String s = result1.get(i).toString(); + result.add(s.substring(0,s.length()-2)); + } + + return result; + } + + //这里使用StringBuilder,因为他快是因为他适用于同一个string不可变字符串的时候,这里每一个只添加一次 + //这里处理node的左右节点,而不是处理他本身,因为涉及到要不要新new上一个List + public void path(TreeNode node, List result) { + if (node.left == null && node.right == null) { + return; + } else if (node.left != null && node.right != null) { + List temp=new ArrayList<>(); + for (StringBuilder s : result) { + temp.add(new StringBuilder().append(s)); + s .append(node.left.val) .append("->"); + } + path(node.left, result); + for (StringBuilder s : temp) { + s.append(node.right.val) .append("->"); + } + path(node.right, temp); + result.addAll(temp); + } else if (node.left != null) { + for (StringBuilder s : result) { + s .append(node.left.val) .append("->"); + } + path(node.left, result); + } else { + for (StringBuilder s : result) { + s .append(node.right.val) .append("->"); + } + path(node.right, result); + } + + + } + + + /** + * 官方递归法: 本质上是深度优先算法 ->前序遍历 + * 速度超过99.98%,内存超过58.81% + * @param root + * @return + */ + public List binaryTreePaths1(TreeNode root) { + + List result = new ArrayList<>(); + constructPaths(root,"",result); + return result; + + } + + //这里使用StringBuilder,因为他快是因为他适用于同一个string不可变字符串的时候,这里每一个只添加一次 + //这里处理node的左右节点,而不是处理他本身,因为涉及到要不要新new上一个List + public void constructPaths(TreeNode node,String path, List result) { + + if(node!=null){ + StringBuilder pathDS = new StringBuilder(path); + pathDS.append(node.val); + //遍历到了叶子结点,可以把结果加入 + if(node.left==null&&node.right==null){ + result.add(pathDS.toString()); + }else{ + //不是叶子节点,需要继续遍历 + pathDS.append("->"); + constructPaths(node.left,pathDS.toString(),result); + constructPaths(node.right,pathDS.toString(),result); + } + } + } + + + /** + * 官方广度优先算法 + * @param root + * @return + */ + public List binaryTreePaths2(TreeNode root) { + List paths = new ArrayList(); + if (root == null) { + return paths; + } + Queue nodeQueue = new LinkedList(); + Queue pathQueue = new LinkedList(); + + nodeQueue.offer(root); + pathQueue.offer(Integer.toString(root.val)); + + //node和path同步offer和poll保证两边一定是相对应的 + while (!nodeQueue.isEmpty()) { + TreeNode node = nodeQueue.poll(); + String path = pathQueue.poll(); + + if (node.left == null && node.right == null) { + paths.add(path); + } else { + if (node.left != null) { + nodeQueue.offer(node.left); + pathQueue.offer(new StringBuffer(path).append("->").append(node.left.val).toString()); + } + + if (node.right != null) { + nodeQueue.offer(node.right); + pathQueue.offer(new StringBuffer(path).append("->").append(node.right.val).toString()); + } + } + } + return paths; + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/IsBalance.java b/Leecode/src/main/java/com/markilue/leecode/tree/IsBalance.java new file mode 100644 index 0000000..b037f60 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/IsBalance.java @@ -0,0 +1,133 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-23 09:59 + * @Description: TODO 力扣110题 平衡二叉树: + * 给定一个二叉树,判断它是否是高度平衡的二叉树。 + * 本题中,一棵高度平衡二叉树定义为: + * 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 + * @Version: 1.0 + */ +public class IsBalance { + + + @Test + public void test() { + TreeNode root = new TreeNode(3); + TreeNode TreeNode2 = new TreeNode(9); + TreeNode TreeNode3 = new TreeNode(20); +// TreeNode TreeNode4 = new TreeNode(4); +// TreeNode TreeNode5 = new TreeNode(5); + TreeNode TreeNode6 = new TreeNode(15); + TreeNode TreeNode7 = new TreeNode(7); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode7); + TreeNode3.setLeft(TreeNode6); + + System.out.println(isBalanced(root)); + + } + + @Test + public void test1() { + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(2); + TreeNode TreeNode4 = new TreeNode(3); + TreeNode TreeNode5 = new TreeNode(3); + TreeNode TreeNode6 = new TreeNode(4); + TreeNode TreeNode7 = new TreeNode(4); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + TreeNode4.setRight(TreeNode7); + TreeNode4.setLeft(TreeNode6); + + System.out.println(isBalanced(root)); + + } + + /** + * 自己的思路递归法:本质上就是判断两个子树之间的高度差的绝对值不超过1,因此求出两个高度即可 + * 本质上,我们又想知道其下面左右子树是否平衡,又想知道他的深度,因此这个使用一个List第一个元素存放,这里类似于拿空间换时间 =>只用遍历一次 + * 速度击败5.68%,内存击败5% + * TODO 从代码随想录的递归法可以看出: + * 实际上,其实我们只是有的时候想知道高度(左右两边都是平衡二叉树时), + * 其他时候如果他不是平衡二叉树了,高度就不重要了,所以只需要用一个特殊标记标记他是否还是平衡二叉树就可以将两者逻辑合并即变成了代码随想录的思路 + * + * @param root + * @return + */ + public boolean isBalanced(TreeNode root) { + + return (boolean) balance(root).get(0); + + } + + + public List balance(TreeNode root) { + if (root == null) { + return new ArrayList(Arrays.asList(true, 0)); + } + List left = balance(root.left); + List right = balance(root.right); + + boolean flag1 = (boolean) left.get(0); + boolean flag2 = (boolean) right.get(0); + + int depth1 = (int) left.get(1); + int depth2 = (int) right.get(1); + + if (flag1 && flag2 && Math.abs(depth1 - depth2) <= 1) { + return new ArrayList(Arrays.asList(flag1, Math.max(depth1, depth2) + 1)); + } else { + //但凡有一个false,深度就不重要了 + return new ArrayList(Arrays.asList(false, 0)); + } + + } + + + /** + * 代码随想录递归法:本质上是求高度,而不是深度 + * 速度超过100%,内存超过79.93% + * @param root + * @return + */ + public boolean isBalanced1(TreeNode root) { + + return deep(root) == -1 ? false : true; + + } + + public int deep(TreeNode root) { + if (root == null) { + return 0; + } + int left = deep(root.left); + if (left == -1) return -1; + int right = deep(root.right); + if (right == -1) return -1; + return Math.abs(left - right) > 1 ? -1 : (Math.max(left, right)) + 1; + + } + + + + +} From e1f2920261a4b22c6967da79cd1de2a8c948236f Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Fri, 23 Sep 2022 16:51:54 +0800 Subject: [PATCH 31/38] =?UTF-8?q?collection=E7=9A=84=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E9=A2=98=E5=AD=A6=E4=B9=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java_learning/collection/Problem.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/Problem.java diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/Problem.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/Problem.java new file mode 100644 index 0000000..7be3d3e --- /dev/null +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/collection/Problem.java @@ -0,0 +1,35 @@ +package com.markilue.java_learning.collection; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + * @BelongsProject: java_learning + * @BelongsPackage: com.markilue.java_learning.collection + * @Author: dingjiawen + * @CreateTime: 2022-09-23 16:38 + * @Description: + * TODO 面试题中的一些集合类题 + * @Version: 1.0 + */ +public class Problem { + + + @Test + public void test(){ + //注意这里可以不指定泛型不报错,但是不能加上<>了。不然会报错 + List list1=new ArrayList(); + list1.add(0); + List list2=list1; + System.out.println(list1.get(0) instanceof Integer); //true + System.out.println(list2.get(0) instanceof Integer); //true + System.out.println(list1.get(0).getClass()); //class java.lang.Integer + System.out.println(list1.get(0).getClass().getName()); //java.lang.Integer + Class aClass = list1.get(0).getClass(); + String name = list1.get(0).getClass().getName(); + } + + +} From d6b00cd3b8663b10e45cad136da48e2140d0b66d Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Fri, 23 Sep 2022 18:22:05 +0800 Subject: [PATCH 32/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/markilue/leecode/tree/HasPathSum.java | 153 +++++++++++++++++ .../com/markilue/leecode/tree/PathSum.java | 161 ++++++++++++++++++ 2 files changed, 314 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/HasPathSum.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/PathSum.java diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/HasPathSum.java b/Leecode/src/main/java/com/markilue/leecode/tree/HasPathSum.java new file mode 100644 index 0000000..937151e --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/HasPathSum.java @@ -0,0 +1,153 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.Stack; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-23 16:54 + * @Description: + * TODO 力扣112题 路径总和: + * 给你二叉树的根节点root 和一个表示目标和的整数targetSum 。 + * 判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和targetSum 。 + * 如果存在,返回 true ;否则,返回 false 。 + *

+ * 叶子节点 是指没有子节点的节点。 + * @Version: 1.0 + */ +public class HasPathSum { + + @Test + public void test() { + TreeNode root = new TreeNode(5); + TreeNode TreeNode2 = new TreeNode(4); + TreeNode TreeNode3 = new TreeNode(8); + TreeNode TreeNode4 = new TreeNode(11); + TreeNode TreeNode5 = new TreeNode(13); + TreeNode TreeNode6 = new TreeNode(4); + TreeNode TreeNode7 = new TreeNode(7); + TreeNode TreeNode8 = new TreeNode(2); + TreeNode TreeNode9 = new TreeNode(1); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode4); + TreeNode3.setLeft(TreeNode5); + TreeNode3.setRight(TreeNode6); + TreeNode4.setLeft(TreeNode7); + TreeNode4.setRight(TreeNode8); + TreeNode6.setRight(TreeNode9); + + System.out.println(hasPathSum(root, 22)); + } + + @Test + public void test1() { + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); +// TreeNode TreeNode3 = new TreeNode(8); +// TreeNode TreeNode4 = new TreeNode(11); +// TreeNode TreeNode5 = new TreeNode(13); +// TreeNode TreeNode6 = new TreeNode(4); +// TreeNode TreeNode7 = new TreeNode(7); +// TreeNode TreeNode8 = new TreeNode(2); +// TreeNode TreeNode9 = new TreeNode(1); + +// root.setRight(TreeNode3); + root.setLeft(TreeNode2); +// TreeNode2.setLeft(TreeNode4); +// TreeNode3.setLeft(TreeNode5); +// TreeNode3.setRight(TreeNode6); +// TreeNode4.setLeft(TreeNode7); +// TreeNode4.setRight(TreeNode8); +// TreeNode6.setRight(TreeNode9); + + System.out.println(hasPathSum1(root, 1)); + } + + /** + * 自己思路递归法: + * 速度击败100%,内存击败59.98% + */ + public boolean hasPathSum(TreeNode root, int targetSum) { + if (root == null) { + return false; + } + + return sum(root, 0, targetSum); + + } + + public boolean sum(TreeNode node, int sum, int targetSum) { + sum += node.val; + if (node.left == null && node.right == null) { + return sum == targetSum; + } + boolean left = false; + boolean right = false; + if (node.left != null) { + left = sum(node.left, sum, targetSum); + } + if (node.right != null) { + right = sum(node.right, sum, targetSum); + } + return left || right; + } + + /** + * 自己思路迭代法: + * 速度击败6.58%,内存击败54.85% + */ + public boolean hasPathSum1(TreeNode root, int targetSum) { + + if (root == null) { + return false; + } + Stack treeNodes = new Stack<>(); + Stack treeSums = new Stack<>(); + treeNodes.push(root); + treeSums.push(0); + while (!treeNodes.empty()) { + TreeNode node = treeNodes.pop(); + int sum = treeSums.pop(); + sum += node.val; + if (node.left == null && node.right == null) { + if(sum==targetSum){ + return true; + } + }else { + //注意这里不能把treeSums.push(sum);放外面,因为可能要放两次 + if(node.left!=null){ + treeNodes.push(node.left); + treeSums.push(sum); + } + if(node.right!=null){ + treeNodes.push(node.right); + treeSums.push(sum); + } + } + + } + + + return false; + + } + + /** + * 代码随想录思路递归法:极简版 + * 速度击败100%,内存击败59.98% + */ + public boolean hasPathSum2(TreeNode root, int targetSum) { + if (root == null) { + return false; + } + if(root.left==null&&root.right==null&&targetSum==0)return true; + return hasPathSum2(root.left,targetSum- root.val)||hasPathSum2(root.right,targetSum- root.val); + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/PathSum.java b/Leecode/src/main/java/com/markilue/leecode/tree/PathSum.java new file mode 100644 index 0000000..f58d50a --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/PathSum.java @@ -0,0 +1,161 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.*; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-23 17:44 + * @Description: + * TODO 力扣113题 路径总和II: + * 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 + * @Version: 1.0 + */ +public class PathSum { + + + @Test + public void test(){ + TreeNode root = new TreeNode(5); + TreeNode TreeNode2 = new TreeNode(4); + TreeNode TreeNode3 = new TreeNode(8); + TreeNode TreeNode4 = new TreeNode(11); + TreeNode TreeNode5 = new TreeNode(13); + TreeNode TreeNode6 = new TreeNode(4); + TreeNode TreeNode7 = new TreeNode(7); + TreeNode TreeNode8 = new TreeNode(2); + TreeNode TreeNode9 = new TreeNode(1); + TreeNode TreeNode10 = new TreeNode(5); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode4); + TreeNode3.setLeft(TreeNode5); + TreeNode3.setRight(TreeNode6); + TreeNode4.setLeft(TreeNode7); + TreeNode4.setRight(TreeNode8); + TreeNode6.setRight(TreeNode9); + TreeNode6.setLeft(TreeNode10); + + System.out.println(pathSum(root, 22)); + } + + @Test + public void test1() { + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); +// TreeNode TreeNode3 = new TreeNode(8); +// TreeNode TreeNode4 = new TreeNode(11); +// TreeNode TreeNode5 = new TreeNode(13); +// TreeNode TreeNode6 = new TreeNode(4); +// TreeNode TreeNode7 = new TreeNode(7); +// TreeNode TreeNode8 = new TreeNode(2); +// TreeNode TreeNode9 = new TreeNode(1); + +// root.setRight(TreeNode3); + root.setLeft(TreeNode2); +// TreeNode2.setLeft(TreeNode4); +// TreeNode3.setLeft(TreeNode5); +// TreeNode3.setRight(TreeNode6); +// TreeNode4.setLeft(TreeNode7); +// TreeNode4.setRight(TreeNode8); +// TreeNode6.setRight(TreeNode9); + + System.out.println(pathSum(root, 0)); + } + + /** + * 自己思路递归法:以空间换时间 实际上是深度优先算法 + * 速度击败99.98%,内存击败30.39% + * @param root + * @param targetSum + * @return + */ + public List> pathSum(TreeNode root, int targetSum) { + if(root==null){ + return new ArrayList<>(); + } + List> result = new ArrayList<>(); + path(root,targetSum,0,new ArrayList<>(),result); + return result; + + } + + + public void path(TreeNode node,int targetSum,int sum,List list,List> result){ + sum+=node.val; + list.add(node.val); + if(node.left==null&&node.right==null&&sum==targetSum){ + //换一个list,避免修改这一个 + List result1 = new ArrayList<>(); + result1.addAll(list); + result.add(result1); + return; + } + if(node.left!=null){ + path(node.left,targetSum,sum,list,result); + list.remove(list.size()-1); + } + if(node.right!=null){ + path(node.right,targetSum,sum,list,result); + list.remove(list.size()-1); + } + + } + + + + + //官方广度优先算法:核心是通过map记录他的爹是谁,方便后续回溯 + List> ret = new LinkedList>(); + Map map = new HashMap(); + + public List> pathSum1(TreeNode root, int targetSum) { + if (root == null) { + return ret; + } + + Queue queueNode = new LinkedList(); + Queue queueSum = new LinkedList(); + queueNode.offer(root); + queueSum.offer(0); + + while (!queueNode.isEmpty()) { + TreeNode node = queueNode.poll(); + int rec = queueSum.poll() + node.val; + + if (node.left == null && node.right == null) { + if (rec == targetSum) { + getPath(node); + } + } else { + if (node.left != null) { + map.put(node.left, node); + queueNode.offer(node.left); + queueSum.offer(rec); + } + if (node.right != null) { + map.put(node.right, node); + queueNode.offer(node.right); + queueSum.offer(rec); + } + } + } + + return ret; + } + + public void getPath(TreeNode node) { + List temp = new LinkedList(); + while (node != null) { + temp.add(node.val); + node = map.get(node); + } + Collections.reverse(temp); + ret.add(new LinkedList(temp)); + } + +} From 0b8049f1763551649651c43f6b49597d786db384 Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Sun, 25 Sep 2022 17:09:25 +0800 Subject: [PATCH 33/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/markilue/leecode/tree/BuildTree.java | 276 ++++++++++++++++++ .../markilue/leecode/tree/BuildTreeII.java | 132 +++++++++ 2 files changed, 408 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/BuildTree.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/BuildTreeII.java diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/BuildTree.java b/Leecode/src/main/java/com/markilue/leecode/tree/BuildTree.java new file mode 100644 index 0000000..8f9c5e5 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/BuildTree.java @@ -0,0 +1,276 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.*; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-25 09:58 + * @Description: TODO 力扣106题 从中序与后序遍历序列构造二叉树: + * 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗二叉树。 + * @Version: 1.0 + */ +public class BuildTree { + + + @Test + public void test(){ + int[] inorder = {9, 3, 15, 20, 7}, postorder = {9, 15, 7, 20, 3}; + TreeNode root = buildTree(inorder, postorder); + + System.out.println(levelOrder(root)); + + } + + @Test + public void test1(){ + int[] inorder = {2,1}, postorder = {2,1}; + TreeNode root = buildTree(inorder, postorder); + + System.out.println(levelOrder(root)); + + } + + @Test + public void test2(){ + int[] inorder = {15,9,10,3,20,5,7,8,4}, postorder = {15,10,9,5,4,8,7,20,3}; + TreeNode root = buildTree2(inorder, postorder); + + System.out.println(levelOrder(root)); + + } + + /** + * 对于这题本人没有任何思路,代码随想录思路:本质上就是寻找中间节点来划分左右树,而后序遍历的最后一个节点一定是中间节点: + * TODO 以后序数组的最后一个元素作为切割点,先切割中序数组,然后根据中序数组,反过来切割后序数组。一层一层切下去,每次后序数组额最后一个元素就是节点元素 + * 递归法: + * 速度超过5.22%,内存超过5.01% + * @param inorder + * @param postorder + * @return + */ + public TreeNode buildTree(int[] inorder, int[] postorder) { + + TreeNode root = new TreeNode(); + + if (inorder.length == 0) { + return root; + } + build1(inorder, postorder, root); + return root; + + } + + public void build(int[] inorder, int[] postorder, TreeNode node) { + + node.val = postorder[postorder.length - 1]; + int length=postorder.length; + + if (length == 1) { + return; + } + + //分别分割左右节点的inorder和postorder + int[] newIn1 = new int[length]; + int[] newPost1 = new int[length]; + + int[] newIn2 = new int[length]; + int[] newPost2 = new int[length]; + + int size = 0; + boolean flag = true; + for (int i = 0,j=0; i < length; i++) { + if(node.val==inorder[i]){ + flag=false; + continue; + } + if (flag) { + newIn1[i] = inorder[i]; + newPost1[i]=postorder[i]; + size+=1; + }else { + //这里-1因为root节点需要被跳过,但是post不用 + newIn2[j] = inorder[i]; + newPost2[j]=postorder[i-1]; + j++; + } + } + //这里需要判断是否大于0再做递归 + if(size>0){ + newIn1 = Arrays.copyOf(newIn1, size); + newPost1=Arrays.copyOf(newPost1,size); + node.left=new TreeNode(); + build(newIn1,newPost1,node.left); + } + + if(length-size-1>0){ + newIn2=Arrays.copyOf(newIn2,length-size-1); + newPost2=Arrays.copyOf(newPost2,length-size-1); + node.right=new TreeNode(); + build(newIn2,newPost2,node.right); + } + } + + //可以改进,只需要找到索引避免一直复制,速度击败9.2%,内存击败5.01% + public void build1(int[] inorder, int[] postorder, TreeNode node) { + + node.val = postorder[postorder.length - 1]; + int length=postorder.length; + + if (length == 1) { + return; + } + + //分别分割左右节点的inorder和postorder + int size = 0; + for (; size < length; size++) { + if(inorder[size]==node.val){ + break; + } + } + //这里需要判断是否大于0再做递归 + if(size>0){ + node.left=new TreeNode(); + //copyOfRange是左闭右开 + build(Arrays.copyOfRange(inorder,0, size),Arrays.copyOfRange(postorder,0,size),node.left); + } + + if(length-size-1>0){ + node.right=new TreeNode(); + build(Arrays.copyOfRange(inorder,size+1,length),Arrays.copyOfRange(postorder,size,length-1),node.right); + } + } + + + + int post_idx; + int[] postorder; + int[] inorder; + Map idx_map = new HashMap(); + + /** + * 官方的递归法,只用传索引,不传一个数组,避免了数组的一直赋值操作,加快进度 + * 速度超过99.46%。内存超过34.84% + * @param inorder + * @param postorder + * @return + */ + public TreeNode buildTree1(int[] inorder, int[] postorder) { + this.postorder = postorder; + this.inorder = inorder; + // 从后序遍历的最后一个元素开始 + post_idx = postorder.length - 1; + + // 建立(元素,下标)键值对的哈希表 + int idx = 0; + for (Integer val : inorder) { + idx_map.put(val, idx++); + } + + return helper(0, inorder.length - 1); + } + + public TreeNode helper(int in_left, int in_right) { + // 如果这里没有节点构造二叉树了,就结束 + if (in_left > in_right) { + return null; + } + + // 选择 post_idx 位置的元素作为当前子树根节点 + int root_val = postorder[post_idx]; + TreeNode root = new TreeNode(root_val); + + // 根据 root 所在位置分成左右两棵子树 + int index = idx_map.get(root_val); + + // 下标减一 + post_idx--; + // 构造右子树 + root.right = helper(index + 1, in_right); + // 构造左子树 + root.left = helper(in_left, index - 1); + return root; + } + + + /** + * 官方迭代法: + * 1)我们用一个栈和一个指针辅助进行二叉树的构造。初始时栈中存放了根节点(后序遍历的最后一个节点),指针指向中序遍历的最后一个节点; + * 2)我们依次枚举后序遍历中除了第一个节点以外的每个节点。如果 index 恰好指向栈顶节点, + * 那么我们不断地弹出栈顶节点并向左移动 index,并将当前节点作为最后一个弹出的节点的左儿子; + * 如果 index 和栈顶节点不同,我们将当前节点作为栈顶节点的右儿子; + * 3)无论是哪一种情况,我们最后都将当前的节点入栈。 + * + * 最后得到的二叉树即为答案。 + * + * @param inorder + * @param postorder + * @return + */ + public TreeNode buildTree2(int[] inorder, int[] postorder) { + if (postorder == null || postorder.length == 0) { + return null; + } + TreeNode root = new TreeNode(postorder[postorder.length - 1]); + Deque stack = new LinkedList(); + stack.push(root); + int inorderIndex = inorder.length - 1; + for (int i = postorder.length - 2; i >= 0; i--) { + int postorderVal = postorder[i]; + TreeNode node = stack.peek(); + //前面的如果不等,那么就是其右节点 + if (node.val != inorder[inorderIndex]) { + node.right = new TreeNode(postorderVal); + stack.push(node.right); + } else { + //右节点处理完毕,处理其左节点;如果出栈就证明遇上了需要处理的左节点 + while (!stack.isEmpty() && stack.peek().val == inorder[inorderIndex]) { + //同步处理stack和inorder + node = stack.pop(); + inorderIndex--; + } + node.left = new TreeNode(postorderVal); + stack.push(node.left); + } + } + return root; + } + + + + + + public List> levelOrder(TreeNode root) { + + List> result = new ArrayList<>(); + + //使用队列完成 + Deque deque = new LinkedList(); + + if (root != null) { + deque.addLast(root); + } + while (deque.size() > 0) { + List mid = new ArrayList<>(); + + int size = deque.size(); + + //注意这里必须使用size,而不是deque.size,因为deque的size一直在发生变化 + for (int i = 0; i < size; i++) { + TreeNode poll = deque.poll(); + mid.add(poll.val); + if (poll.left != null) deque.offer(poll.left); + if (poll.right != null) deque.offer(poll.right); + } + result.add(mid); + } + return result; + + } + + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/BuildTreeII.java b/Leecode/src/main/java/com/markilue/leecode/tree/BuildTreeII.java new file mode 100644 index 0000000..166a003 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/BuildTreeII.java @@ -0,0 +1,132 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.*; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-25 12:45 + * @Description: TODO 力扣105题 从前序与中序遍历序列构造二叉树: + * 给定两个整数数组preorder 和 inorder,其中preorder 是二叉树的先序遍历, inorder是同一棵树的中序遍历,请构造二叉树并返回其根节点。 + * @Version: 1.0 + */ +public class BuildTreeII { + + @Test + public void test() { + int[] preorder = {3, 9, 20, 15, 7}, inorder = {9, 3, 15, 20, 7}; + TreeNode node = buildTree(preorder, inorder); + + System.out.println(levelOrder(node)); + } + + + /** + * 核心其实一致,即中序遍历可以确定左右节点,前后序遍历可以确定根节点;因此根据前后序一直找根节点即可 + * 这里运用递归法: + * 速度超过99.46%,内存超过60.36% + * + * @param preorder + * @param inorder + * @return + */ + int[] preorder; + // + Map map = new HashMap(); + int wanted=0; + + public TreeNode buildTree(int[] preorder, int[] inorder) { + this.preorder = preorder; + for (int i = 0; i < inorder.length; i++) { + map.put(inorder[i], i); + } + + return build(0, inorder.length-1); + } + + public TreeNode build(int leftIndex, int rightIndex) { + + if(leftIndex>rightIndex){ + return null; + } + TreeNode node = new TreeNode(preorder[wanted]); + Integer index = map.get(preorder[wanted++]); + node.left=build(leftIndex,index-1); + node.right=build(index+1,rightIndex); + + return node; + } + + + /** + * 官方迭代法: + * 1)我们用一个栈和一个指针辅助进行二叉树的构造。初始时栈中存放了根节点(前序遍历的第一个节点),指针指向中序遍历的第一个节点; + * 2)我们依次枚举前序遍历中除了第一个节点以外的每个节点。 + * 如果 index 恰好指向栈顶节点,那么我们不断地弹出栈顶节点并向右移动 index,并将当前节点作为最后一个弹出的节点的右儿子; + * 如果 index 和栈顶节点不同,我们将当前节点作为栈顶节点的左儿子; + * 3)无论是哪一种情况,我们最后都将当前的节点入栈。 + * + * @param preorder + * @param inorder + * @return + */ + public TreeNode buildTree1(int[] preorder, int[] inorder) { + if (preorder == null || preorder.length == 0) { + return null; + } + TreeNode root = new TreeNode(preorder[0]); + Deque stack = new LinkedList(); + stack.push(root); + int inorderIndex = 0; + for (int i = 1; i < preorder.length; i++) { + int preorderVal = preorder[i]; + TreeNode node = stack.peek(); + if (node.val != inorder[inorderIndex]) { + node.left = new TreeNode(preorderVal); + stack.push(node.left); + } else { + while (!stack.isEmpty() && stack.peek().val == inorder[inorderIndex]) { + node = stack.pop(); + inorderIndex++; + } + node.right = new TreeNode(preorderVal); + stack.push(node.right); + } + } + return root; + } + + + + public List> levelOrder(TreeNode root) { + + List> result = new ArrayList<>(); + + //使用队列完成 + Deque deque = new LinkedList(); + + if (root != null) { + deque.addLast(root); + } + while (deque.size() > 0) { + List mid = new ArrayList<>(); + + int size = deque.size(); + + //注意这里必须使用size,而不是deque.size,因为deque的size一直在发生变化 + for (int i = 0; i < size; i++) { + TreeNode poll = deque.poll(); + mid.add(poll.val); + if (poll.left != null) deque.offer(poll.left); + if (poll.right != null) deque.offer(poll.right); + } + result.add(mid); + } + return result; + + } + +} From 2bb7fa65b8f6f8b1f0771a59641fead211136264 Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Mon, 26 Sep 2022 15:02:18 +0800 Subject: [PATCH 34/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/markilue/leecode/tree/IsValidBST.java | 221 ++++++++++++++++ .../com/markilue/leecode/tree/MergeTrees.java | 237 ++++++++++++++++++ .../com/markilue/leecode/tree/SearchBST.java | 97 +++++++ 3 files changed, 555 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/IsValidBST.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/MergeTrees.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/SearchBST.java diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/IsValidBST.java b/Leecode/src/main/java/com/markilue/leecode/tree/IsValidBST.java new file mode 100644 index 0000000..352330b --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/IsValidBST.java @@ -0,0 +1,221 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.Stack; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-26 11:06 + * @Description: TODO 力扣98题 验证二叉搜索树: + * 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。 + * 有效 二叉搜索树定义如下: + * 1.节点的左子树只包含 小于 当前节点的数。 + * 2.节点的右子树只包含 大于 当前节点的数。 + * 3.所有左子树和右子树自身必须也是二叉搜索树。 + * @Version: 1.0 + */ +public class IsValidBST { + + @Test + public void test() { + TreeNode root = new TreeNode(2); + TreeNode TreeNode2 = new TreeNode(1); + TreeNode TreeNode3 = new TreeNode(3); +// TreeNode TreeNode4 = new TreeNode(5); + + + TreeNode TreeNode5 = new TreeNode(5); + TreeNode TreeNode6 = new TreeNode(1); + TreeNode TreeNode7 = new TreeNode(4); + TreeNode TreeNode8 = new TreeNode(3); + TreeNode TreeNode9 = new TreeNode(6); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); +// TreeNode2.setLeft(TreeNode4); + + + TreeNode5.setLeft(TreeNode6); + TreeNode5.setRight(TreeNode7); + TreeNode7.setLeft(TreeNode8); + TreeNode7.setRight(TreeNode9); + + System.out.println(isValidBST1(root)); + System.out.println(isValidBST1(TreeNode5)); + } + + @Test + public void test1() { + TreeNode root = new TreeNode(0); +// TreeNode TreeNode2 = new TreeNode(-1); + TreeNode TreeNode3 = new TreeNode(1); +// TreeNode TreeNode4 = new TreeNode(5); + + + root.setRight(TreeNode3); +// root.setLeft(TreeNode3); +// TreeNode2.setLeft(TreeNode4); + + + System.out.println(isValidBST1(root)); + + } + + @Test + public void test2() { + TreeNode root = new TreeNode(5); + TreeNode TreeNode2 = new TreeNode(4); + TreeNode TreeNode3 = new TreeNode(6); + TreeNode TreeNode4 = new TreeNode(3); + TreeNode TreeNode5 = new TreeNode(7); + + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode3.setLeft(TreeNode4); + TreeNode3.setRight(TreeNode5); + + + System.out.println(isValidBST1(root)); + + } + + @Test + public void test3() { + TreeNode root = new TreeNode(-2147483648); + TreeNode TreeNode2 = new TreeNode(4); + TreeNode TreeNode3 = new TreeNode(2147483647); + TreeNode TreeNode4 = new TreeNode(3); + TreeNode TreeNode5 = new TreeNode(7); + + + root.setRight(TreeNode3); +// root.setLeft(TreeNode2); +// TreeNode3.setLeft(TreeNode4); +// TreeNode3.setRight(TreeNode5); + + + System.out.println(isValidBST(root)); + + } + + @Test + public void test4() { + TreeNode root = new TreeNode(3); + TreeNode TreeNode2 = new TreeNode(1); + TreeNode TreeNode3 = new TreeNode(5); + TreeNode TreeNode4 = new TreeNode(0); + TreeNode TreeNode5 = new TreeNode(2); + TreeNode TreeNode6 = new TreeNode(4); + TreeNode TreeNode7 = new TreeNode(6); + + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + TreeNode3.setLeft(TreeNode6); + TreeNode3.setRight(TreeNode7); + + + System.out.println(isValidBST1(root)); + + } + + /** + * 递归法 + * 速度超过100%,内存超过67.95% + * + * @param root + * @return + */ + public boolean isValidBST(TreeNode root) { + return isValid(root, Long.MIN_VALUE, Long.MAX_VALUE); + } + + + //limit即一个数的节点一定大于他左节点的右节点,小于他右节点的左节点 + public boolean isValid(TreeNode root, Long leftLimit, Long rightLimit) { + + //第一个条件是为了第一次root等于null的情况,理论上不会 + if (root.left == null && root.right == null) return true; + + boolean flag1 = false; + if (root.left == null) { + flag1 = true; + } else { + if (root.val > root.left.val && root.left.val > leftLimit) { + flag1 = isValid(root.left, leftLimit, Long.valueOf(root.val)); + } + } + //快速返回 + if (!flag1) { + return false; + } + boolean flag2 = false; + if (root.right == null) { + flag2 = true; + } else { + if (root.val < root.right.val && root.right.val < rightLimit) { + flag2 = isValid(root.right, Long.valueOf(root.val), rightLimit); + } + } + return flag2; + } + + + /** + * 代码随想录递归法 + * 速度超过100%,内存超过67.95% + * + * @param root + * @return + */ + TreeNode pre = null;//记录前一个节点 + public boolean isValidBST2(TreeNode root) { + if (root == null) return true; + boolean left = isValidBST2(root.left); + + if (pre != null && pre.val >= root.val) { + return false; + } + pre = root; //记录前一个节点 + boolean right = isValidBST2(root.right); + return left && right; + } + + + /** + * 迭代法:由于左边节点和右边节点的界限不相同,因此不能使用层序遍历,这里使用中序遍历 + * 速度超过19.02%,内存超过11.02% + * + * @param root + * @return + */ + public boolean isValidBST1(TreeNode root) { + if (root == null) { + return false; + } + + Stack stack = new Stack<>(); + + TreeNode pre = null;//记录前一个节点 + TreeNode cur = root; +// + while (!stack.isEmpty() || cur != null) { + if (cur != null) { + stack.push(cur); + cur=cur.left; + } else { + cur = stack.pop(); + if (pre != null && cur.val <= pre.val) return false; //这里是1)将左子节点小于本节点 2)本节点的右子节点的所有节点都大于本节点 这两个逻辑统一:通过记录前一个指针来完成,这个操作似乎只能通过中序遍历来完成 + pre = cur;//保存访问的前一个节点 + cur = cur.right; + } + } + return true; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/MergeTrees.java b/Leecode/src/main/java/com/markilue/leecode/tree/MergeTrees.java new file mode 100644 index 0000000..8230948 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/MergeTrees.java @@ -0,0 +1,237 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.*; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-26 09:14 + * @Description: TODO 力扣617题 合并二叉树: + * 1)给你两棵二叉树: root1 和 root2 。 + * 2)想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。 + * 你需要将这两棵树合并成一棵新二叉树。 + * 合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值; + * 否则,不为 null 的节点将直接作为新二叉树的节点。 + * 3)返回合并后的二叉树。 + * @Version: 1.0 + */ +public class MergeTrees { + + @Test + public void test() { + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(3); + TreeNode TreeNode3 = new TreeNode(2); + TreeNode TreeNode4 = new TreeNode(5); + + + TreeNode TreeNode5 = new TreeNode(2); + TreeNode TreeNode6 = new TreeNode(1); + TreeNode TreeNode7 = new TreeNode(3); + TreeNode TreeNode8 = new TreeNode(4); + TreeNode TreeNode9 = new TreeNode(7); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode4); + + + TreeNode5.setLeft(TreeNode6); + TreeNode5.setRight(TreeNode7); + TreeNode6.setRight(TreeNode8); + TreeNode7.setRight(TreeNode9); + + System.out.println(preorderTraversal2(mergeTrees2(root, TreeNode5))); //3 4 5 4 5 7 + } + + + /** + * 自己递归法: + * 速度击败100%,内存击败96.05% + * 本质上是深度优先算法 + * @param root1 + * @param root2 + * @return + */ + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + + if (root1 == null) { + return root2; + } else { + if (root2 != null) { + root1.val = root1.val + root2.val; + root1.left = mergeTrees(root1.left, root2.left); + root1.right = mergeTrees(root1.right, root2.right); + } + return root1; + } + + } + + + /** + * 自己迭代法:前序层序应该都可以 + * 速度击败11.89%,内存击败27.67% + * + * @param root1 + * @param root2 + * @return + */ + public TreeNode mergeTrees1(TreeNode root1, TreeNode root2) { + + if (root1 == null) { + return root2; + } + if (root2 == null) { + return root1; + } + + //存放root1节点 + Stack treeNodes1 = new Stack<>(); + //存放root2节点 + Stack treeNodes2 = new Stack<>(); + + treeNodes1.push(root1); + treeNodes2.push(root2); + + + while (!treeNodes1.empty() || !treeNodes2.empty()) { + TreeNode node1 = treeNodes1.pop(); + TreeNode node2 = treeNodes2.pop(); + + if (node2 == null) { + continue; + } + + node1.val += node2.val; + + if (node1.left != null) { + treeNodes1.push(node1.left); + treeNodes2.push(node2.left); + } else { + node1.left = node2.left; + } + + if (node1.right != null) { + treeNodes1.push(node1.right); + treeNodes2.push(node2.right); + } else { + node1.right = node2.right; + } + + + } + + return root1; + + + } + + /** + * 自己迭代法:改进版,使用一个stack + * 速度击败11.89%,内存击败81.44% + * 本质上是广度优先算法 + * @param root1 + * @param root2 + * @return + */ + public TreeNode mergeTrees2(TreeNode root1, TreeNode root2) { + + if (root1 == null) { + return root2; + } + //只要root1不等于null即可,root2等于0的逻辑在后面也可以判断了 + + + //存放root1节点 + Queue deque = new LinkedList(); + + deque.offer(root1); + deque.offer(root2); + + while (!deque.isEmpty()) { + TreeNode node1 = deque.poll(); + TreeNode node2 = deque.poll(); + + if (node2 == null) { + continue; + } + + node1.val += node2.val; + + if (node1.left != null) { + deque.offer(node1.left); + deque.offer(node2.left); + } else { + node1.left = node2.left; + } + + if (node1.right != null) { + deque.offer(node1.right); + deque.offer(node2.right); + } else { + node1.right = node2.right; + } + } + + return root1; + } + + + /** + * Morris 遍历:将空间复杂度降到O(1) + * Morris 遍历的核心思想是利用树的大量空闲指针,实现空间开销的极限缩减。其前序遍历规则总结如下: + *

+ * 1.新建临时节点,令该节点为 root; + * 2.如果当前节点的左子节点为空,将当前节点加入答案,并遍历当前节点的右子节点; + * 3.如果当前节点的左子节点不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点: + * 如果前驱节点的右子节点为空,将前驱节点的右子节点设置为当前节点。然后将当前节点加入答案,并将前驱节点的右子节点更新为当前节点。当前节点更新为当前节点的左子节点。 + * 如果前驱节点的右子节点为当前节点,将它的右子节点重新设为空。当前节点更新为当前节点的右子节点。 + * 4.重复步骤 2 和步骤 3,直到遍历结束。 + *

+ * TODO 核心理念是如何回到root节点的: + * 1)传统方法使用stack去回到root + * 2)这种方法利用叶子结点闲置的右指针,因为回到root的前提是左边的遍历完了,那么遍历完了之前的一个节点一定是叶子节点,可以提前找到这个叶子结点,将其右指针置为root,就可以回到root了 + * + * @param root + * @return + */ + public List preorderTraversal2(TreeNode root) { + List res = new ArrayList(); + if (root == null) { + return res; + } + + TreeNode p1 = root, p2 = null; + + while (p1 != null) { + p2 = p1.left; + if (p2 != null) { + //通过这个循环找到回到root的最后一个节点,第二个条件是判断是否遍历过这个节点 + while (p2.right != null && p2.right != p1) { + p2 = p2.right; + } + //从第一个条件出来的,证明这个节点没遍历过且是回到root前的最后一个节点 + if (p2.right == null) { + res.add(p1.val); + //让下次得以回到之前遍历的节点 + p2.right = p1; + //找到了回来的节点,放心的将root左移 + p1 = p1.left; + continue; + } else { + //从第二个条件出来的,证明这个节点遍历过了,那么就把他的右边置空 + p2.right = null; + } + } else { + //左边遍历完了 + res.add(p1.val); + } + p1 = p1.right; + } + return res; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/SearchBST.java b/Leecode/src/main/java/com/markilue/leecode/tree/SearchBST.java new file mode 100644 index 0000000..11fa7cb --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/SearchBST.java @@ -0,0 +1,97 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-26 10:31 + * @Description: TODO 力扣700题 二叉搜索树中的搜索: + * 给定二叉搜索树(BST)的根节点root和一个整数值val。 + * 你需要在 BST 中找到节点值等于val的节点。 返回以该节点为根的子树。 如果节点不存在,则返回null。 + * @Version: 1.0 + */ +public class SearchBST { + + @Test + public void test() { + TreeNode root = new TreeNode(4); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(7); + TreeNode TreeNode4 = new TreeNode(1); + TreeNode TreeNode5 = new TreeNode(3); + + +// TreeNode TreeNode5 = new TreeNode(2); +// TreeNode TreeNode6 = new TreeNode(1); +// TreeNode TreeNode7 = new TreeNode(3); +// TreeNode TreeNode8 = new TreeNode(4); +// TreeNode TreeNode9 = new TreeNode(7); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + +// +// TreeNode5.setLeft(TreeNode6); +// TreeNode5.setRight(TreeNode7); +// TreeNode6.setRight(TreeNode8); +// TreeNode7.setRight(TreeNode9); + + System.out.println(searchBST(root, 2)); + } + + + /** + * 自己递归法: + * 速度超过100%,内存超过94.85% + * + * @param root + * @param val + * @return + */ + public TreeNode searchBST(TreeNode root, int val) { + if (root == null) { + return null; + } + if (root.val > val) { + return searchBST(root.left, val); + } else if (root.val < val) { + return searchBST(root.right, val); + } else { + return root; + } + + } + + + /** + * 自己迭代法: + * 速度超过100%,内存超过25.48% + * + * @param root + * @param val + * @return + */ + public TreeNode searchBST1(TreeNode root, int val) { + if (root == null) { + return null; + } + TreeNode node = root; + + while (node != null) { + if (node.val > val) { + node = node.left; + } else if (node.val < val) { + node = node.right; + } else { + return node; + } + } + return node; + + + } +} From 16865a08b645fe036762db8545dedfa96d986754 Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Mon, 26 Sep 2022 19:13:17 +0800 Subject: [PATCH 35/38] =?UTF-8?q?java=E5=9F=BA=E7=A1=80=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E9=9D=A2=E8=AF=95=E9=A2=98=E5=AD=A6=E4=B9=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java_learning/enumTest/enumTest.java | 1 + .../innerclass/StaticInnerClass.java | 5 +++ .../markilue/java_learning/string/Equal.java | 39 ++++++++++++------- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/enumTest/enumTest.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/enumTest/enumTest.java index b63bd3b..401f698 100644 --- a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/enumTest/enumTest.java +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/enumTest/enumTest.java @@ -16,6 +16,7 @@ import org.junit.Test; * 4.如果枚举类需要的是有参构造,需要手动定义private的有参构造,调用有参构造的方法就是在常量对象名后面加(实参列表)就可以。 * 5.枚举类默认继承的是java.lang.Enum类,因此不能再继承其他的类型。 * 6.JDK1.5之后switch,提供支持枚举类型,case后面可以写枚举常量名。 + * 7.enumeration是线程安全的 * 2)枚举类的常用方法: * 1.toString(): 默认返回的是常量名(对象名),可以继续手动重写该方法! * 2.name():返回的是常量名(对象名) 【很少使用】 diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/StaticInnerClass.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/StaticInnerClass.java index 80f54e0..551ca0c 100644 --- a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/StaticInnerClass.java +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/innerclass/StaticInnerClass.java @@ -28,6 +28,11 @@ import org.junit.Test; */ public class StaticInnerClass { + static boolean Paddy; + public static void main(String args[]){ + System.out.println(Paddy); + } + @Test public void test(){ Outer2.Inner in= new Outer2.Inner(); //4) diff --git a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/string/Equal.java b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/string/Equal.java index f3c7d36..5ef5a46 100644 --- a/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/string/Equal.java +++ b/Big_data_example/java_learning/src/main/java/com/markilue/java_learning/string/Equal.java @@ -7,18 +7,17 @@ import org.junit.Test; * @BelongsPackage: com.markilue.java_learning.string * @Author: dingjiawen * @CreateTime: 2022-09-13 18:45 - * @Description: - * TODO 解释string中的==和equal方法,以及string的intern()方法: - * 1)String类型不是基本类型,其构造方法有String s=“”;new String()/new String("")/new String(char[] a)等 - * 2)String由于其不是基本类型,因此使用构造方法new String(“abc”)创建对象,其对象会放在堆中(对象引用放在栈里),"abc"存放在对象的value数组中(源码可知) - * 3)使用String s=“abc”创建的String,由于“abc”是一个不可变常量(在常量池中只会维护一份,并且可以共享),因此"abc"会存在常量池中,s的对象引用也是指向常量池 - * 4) String调用的equal()方法,本身是调用了Object类的equal()方法比较内存,但是String类重写了equal()方法,变成了比较值 - * 4.1)String的intern()方法就是将string放入常量池中,并返回他的索引,如果在常量池中则直接返回他的索引 - * 5)关于拼接和存储问题: - * (1)常量+常量:结果是常量池 - * (2)常量与变量 或 变量与变量:结果是堆 - * (3)拼接后调用intern方法:结果在常量池 - * (4)在初始化时使用String s=new String("abc")+new String("def")进行拼接时,不会马上解析,只有当这个字面量s被调用或者abcdef被调用时,采用创建对应的String实例 + * @Description: TODO 解释string中的==和equal方法,以及string的intern()方法: + * 1)String类型不是基本类型,其构造方法有String s=“”;new String()/new String("")/new String(char[] a)等 + * 2)String由于其不是基本类型,因此使用构造方法new String(“abc”)创建对象,其对象会放在堆中(对象引用放在栈里),"abc"存放在对象的value数组中(源码可知) + * 3)使用String s=“abc”创建的String,由于“abc”是一个不可变常量(在常量池中只会维护一份,并且可以共享),因此"abc"会存在常量池中,s的对象引用也是指向常量池 + * 4) String调用的equal()方法,本身是调用了Object类的equal()方法比较内存,但是String类重写了equal()方法,变成了比较值 + * 4.1)String的intern()方法就是将string放入常量池中,并返回他的索引,如果在常量池中则直接返回他的索引 + * 5)关于拼接和存储问题: + * (1)常量+常量:结果是常量池 + * (2)常量与变量 或 变量与变量:结果是堆 + * (3)拼接后调用intern方法:结果在常量池 + * (4)在初始化时使用String s=new String("abc")+new String("def")进行拼接时,不会马上解析,只有当这个字面量s被调用或者abcdef被调用时,采用创建对应的String实例 * @Version: 1.0 */ public class Equal { @@ -103,10 +102,24 @@ public class Equal { //参考5)的第4点 String s1 = new String("mark") + new String("ilue"); //这一步会将mark和ilue放入常量池中 s1.intern(); //这里拼接的字符串markilue被调用,将markilue放入常量池中,这时才返回markilue索引给s1 - String s2=new StringBuilder("marki").append("lue").toString(); //这里将marki和lue放入常量池中,然后在toString中被调用,所以创建markilue的String对象(存放在堆中),然后返回这个堆索引 + String s2 = new StringBuilder("marki").append("lue").toString(); //这里将marki和lue放入常量池中,然后在toString中被调用,所以创建markilue的String对象(存放在堆中),然后返回这个堆索引 System.out.println(s1 == s2);//false 这里一个是返回的在堆对象中的索引,一个是返回的在常量池中的索引,因此不相等 System.out.println(s1 == s2.intern());//true 这里调用intern()方法后获取到了在常量池中的索引,因此两者相等 } + + //面试题 + private static final String MESSAGE = "taobao"; + @Test + public void test08() { + String a = "tao" + "bao"; + String b = "tao"; + String c = "bao"; + System.out.println(a == MESSAGE); //true + System.out.println((b + c) == MESSAGE); //false + + } + + } From f07804340e136e2d0f306fdf23aa67b2c2f7ae27 Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Tue, 27 Sep 2022 12:32:13 +0800 Subject: [PATCH 36/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/markilue/leecode/tree/FindMode.java | 254 ++++++++++++++++++ .../leecode/tree/GetMinimumDifference.java | 235 ++++++++++++++++ 2 files changed, 489 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/FindMode.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/GetMinimumDifference.java diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/FindMode.java b/Leecode/src/main/java/com/markilue/leecode/tree/FindMode.java new file mode 100644 index 0000000..714598b --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/FindMode.java @@ -0,0 +1,254 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import javax.transaction.TransactionRequiredException; +import java.util.*; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-27 10:58 + * @Description: TODO 力扣501题 二叉搜索树中的众数: + * 给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。 + * 如果树中有不止一个众数,可以按 任意顺序 返回。 + * 假定 BST 满足如下定义: + * 结点左子树中所含节点的值 小于等于 当前节点的值 + * 结点右子树中所含节点的值 大于等于 当前节点的值 + * 左子树和右子树都是二叉搜索树 + * @Version: 1.0 + */ +public class FindMode { + + + @Test + public void test() { + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(2); +// TreeNode TreeNode4 = new TreeNode(4); +// TreeNode TreeNode5 = new TreeNode(5); +// TreeNode TreeNode6 = new TreeNode(15); +// TreeNode TreeNode7 = new TreeNode(7); + + root.setRight(TreeNode2); + TreeNode2.setLeft(TreeNode3); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setRight(TreeNode7); +// TreeNode3.setLeft(TreeNode6); + + System.out.println(Arrays.toString(findMode(root))); + + } + + + // PriorityQueue queue = new PriorityQueue(new Comparator() { +// +// @Override +// public int compare(int[] o1, int[] o2) { +// //int[val,count] +// return o1[1] != o2[1] ? o1[1] - o2[1] : o1[0] - o2[0]; +// +// } +// }); + + //这里使用ArrayList因为不想自己动态扩容 + List list = new ArrayList(); + TreeNode pre = null; + int count = 1; + + /** + * 思路:利用二叉树的特点中序遍历是有序数组来解决 :中序遍历+记录前指针: + * 有两种思路储存val,count:这里使用第二种 + * 1)map + * 2)PriorityQueue() + * 递归法 + * 速度击败100%,内存击败86.8% + * @param root + * @return + */ + public int[] findMode(TreeNode root) { + find(root); + if(list.isEmpty()){ + return new int[]{pre.val}; + } + if (count > list.get(0)[1]) { + list.clear(); + list.add(new int[]{pre.val, count}); + } else if (count == list.get(0)[1]) { + list.add(new int[]{pre.val, count}); + } + int[] result = new int[list.size()]; + for (int i = 0; i < list.size(); i++) { + result[i] = list.get(i)[0]; + } + + return result; + + } + + /** + * 递归法 + * + * @param node + */ + public void find(TreeNode node) { + if (node == null) { + return; + } + find(node.left); + if (pre != null) { + if (pre.val == node.val) { + count++; + } else { + if (list.isEmpty()) { + list.add(new int[]{pre.val, count}); + + } else { + if (count > list.get(0)[1]) { + list.clear(); + list.add(new int[]{pre.val, count}); + } else if (count == list.get(0)[1]) { + list.add(new int[]{pre.val, count}); + + } + + } + count = 1; + } + } + pre = node; + find(node.right); + } + + + + int base, count1, maxCount; + List answer = new ArrayList(); + /** + * 思路:利用二叉树的特点中序遍历是有序数组来解决 :中序遍历+记录前指针: + * 有两种思路储存val,count:这里使用第二种 + * 1)map + * 2)PriorityQueue() + * 迭代法:Morris遍历 + * 速度击败100%,内存击败86.8% + * @param root + * @return + */ + public int[] findMode1(TreeNode root) { + + TreeNode cur = root, pre = null; + while (cur != null) { + if (cur.left == null) { + update(cur.val); + cur = cur.right; + continue; + } + pre = cur.left; + while (pre.right != null && pre.right != cur) { + pre = pre.right; + } + if (pre.right == null) { + pre.right = cur; + cur = cur.left; + } else { + pre.right = null; + update(cur.val); + cur = cur.right; + } + } + int[] mode = new int[answer.size()]; + for (int i = 0; i < answer.size(); ++i) { + mode[i] = answer.get(i); + } + return mode; + + } + public void update(int x) { + if (x == base) { + ++count1; + } else { + count1 = 1; + base = x; + } + //这里效率有点低,因为每次count1+1之后都得放进去之类的操作,可以采用递归法上述思路进行更新,好处是出来之后不需要再做判断 + if (count1 == maxCount) { + answer.add(base); + } + if (count1 > maxCount) { + maxCount = count1; + answer.clear(); + answer.add(base); + } + } + + + /** + * 思路:利用二叉树的特点中序遍历是有序数组来解决 :中序遍历+记录前指针: + * 有两种思路储存val,count:这里使用第二种 + * 1)map + * 2)PriorityQueue() + * 自己迭代法: + * 速度击败29.45%,内存击败76.39% + * @param root + * @return + */ + public int[] findMode2(TreeNode root) { + + ArrayList list = new ArrayList<>(); + + int count=1; + int maxCount=count; + Stack stack = new Stack<>(); + TreeNode pre=null; + + while (!stack.isEmpty()||root!=null){ + if(root!=null){ + stack.push(root); + root=root.left; + }else { + root=stack.pop(); + if (pre != null) { + if (pre.val == root.val) { + count++; + } else { + if (list.isEmpty()) { + list.add(pre.val); + maxCount=count; + } else { + if (count > maxCount) { + list.clear(); + list.add(pre.val); + maxCount=count; + } else if (count == maxCount) { + list.add(pre.val); + } + } + count = 1; + } + } + pre = root; + root=root.right; + } + } + + + if(list.isEmpty()){ + return new int[]{pre.val}; + } + if (count > maxCount) { + list.clear(); + list.add(pre.val); + } else if (count == maxCount) { + list.add(pre.val); + } + int[] result = new int[list.size()]; + for (int i = 0; i < list.size(); i++) { + result[i] = list.get(i); + } + return result; + } + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/GetMinimumDifference.java b/Leecode/src/main/java/com/markilue/leecode/tree/GetMinimumDifference.java new file mode 100644 index 0000000..eec3896 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/GetMinimumDifference.java @@ -0,0 +1,235 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.Stack; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-27 09:21 + * @Description: TODO Leecode530题 二叉搜索树的最小绝对差: + * 给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。 + * 差值是一个正数,其数值等于两值之差的绝对值。 + * @Version: 1.0 + */ +public class GetMinimumDifference { + + @Test + public void test() { + TreeNode root = new TreeNode(4); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(6); + TreeNode TreeNode4 = new TreeNode(1); + TreeNode TreeNode5 = new TreeNode(3); +// TreeNode TreeNode6 = new TreeNode(15); +// TreeNode TreeNode7 = new TreeNode(7); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); +// TreeNode3.setRight(TreeNode7); +// TreeNode3.setLeft(TreeNode6); + + System.out.println(getMinimumDifference(root)); + + } + + @Test + public void test1() { + TreeNode root = new TreeNode(1); +// TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(3); +// TreeNode TreeNode4 = new TreeNode(1); +// TreeNode TreeNode5 = new TreeNode(3); + TreeNode TreeNode6 = new TreeNode(2); +// TreeNode TreeNode7 = new TreeNode(7); + + root.setRight(TreeNode3); +// root.setLeft(TreeNode2); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setRight(TreeNode7); + TreeNode3.setLeft(TreeNode6); + + System.out.println(getMinimumDifference1(root)); + + } + + + int result = Integer.MAX_VALUE; + /** + * 思路:某个节点的最小差值一定出现在该节点的左节点的最右节点或者右节点的最左节点两个之一 + * 递归法: + * 速度击败100%,内存击败45.7% + * + * @param root + * @return + */ + public int getMinimumDifference(TreeNode root) { + if (root == null || (root.left == null && root.right == null)) { + return result; + } + if (result == 1) { + return result; + } + //寻找左节点的最右节点 + TreeNode node = root.left; + int left = Integer.MAX_VALUE; + if (node != null) { + while (node.right != null) { + node = node.right; + } + left = root.val - node.val; + } + + //寻找左节点的最右节点 + TreeNode node1 = root.right; + int right = Integer.MAX_VALUE; + if (node1 != null) { + while (node1 != null && node1.left != null) { + node1 = node1.left; + } + right = node1.val - root.val; + } + + int flag = left < right ? left : right; + result = result < flag ? result : flag; + getMinimumDifference(root.left); + getMinimumDifference(root.right); + return result; + } + + /** + * 思路:某个节点的最小差值一定出现在该节点的左节点的最右节点或者右节点的最左节点两个之一 + * 迭代法: + * 速度击败18.64%,内存击败98.39% + * + * @param root + * @return + */ + public int getMinimumDifference1(TreeNode root) { + if (root == null || (root.left == null && root.right == null)) { + return 0; + } + int result = Integer.MAX_VALUE; + + Stack treeNodes = new Stack<>(); + + while (!treeNodes.isEmpty() || root != null) { + if (result == 1) { + break; + } + if (root != null) { + treeNodes.push(root); + root = root.left; + } else { + root = treeNodes.pop(); + //添加找最小差节点逻辑: + + //寻找左节点的最右节点 + TreeNode node = root.left; + int left = Integer.MAX_VALUE; + if (node != null) { + while (node.right != null) { + node = node.right; + } + left = root.val - node.val; + } + + //寻找左节点的最右节点 + TreeNode node1 = root.right; + int right = Integer.MAX_VALUE; + if (node1 != null) { + while (node1 != null && node1.left != null) { + node1 = node1.left; + } + right = node1.val - root.val; + } + + int flag = left < right ? left : right; + result = result < flag ? result : flag; + + //右移 + root = root.right; + } + } + + return result; + } + + /** + * 思路:二叉搜索树的中序遍历就是一个有序数组,只需要记录前一个节点,用当前节点减去现在节点即可 + * 递归法: + * 速度击败18.64%,内存击败98.39% + * + * @param root + * @return + */ + TreeNode pre = null; + int ans = Integer.MAX_VALUE; + + public int getMinimumDifference2(TreeNode root) { + get(root); + return ans; + } + + public void get(TreeNode root) { + if (root == null) { + return; + } + //左 + get(root.left); + //中 + if (pre != null) { + ans = Math.min(root.val - pre.val, ans); + } + //记录当前 + pre=root; + //右 + get(root.right); + } + + + /** + * 代码随想录迭代法: + * 速度超过18.64%,内存超过49.37% + * @param root + * @return + */ + public int getMinimumDifference3(TreeNode root) { + if (root == null || (root.left == null && root.right == null)) { + return 0; + } + int result = Integer.MAX_VALUE; + TreeNode pre=null; + + Stack treeNodes = new Stack<>(); + + while (!treeNodes.isEmpty() || root != null) { + if (result == 1) { + break; + } + if (root != null) { + treeNodes.push(root); + root = root.left; + } else { + root = treeNodes.pop(); + //添加找最小差节点逻辑: + if(pre!=null){ + result=Math.min(result,root.val-pre.val); + } + //记录前指针 + pre=root; + + //右移 + root = root.right; + } + } + + return result; + } + +} From 2266507c27ef8514e8dcd5e03cb2120531c67f77 Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Fri, 7 Oct 2022 12:45:29 +0800 Subject: [PATCH 37/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../markilue/leecode/tree/InsertIntoBST.java | 187 ++++++++++++++++ .../leecode/tree/LowestCommonAncestor.java | 208 ++++++++++++++++++ .../leecode/tree/LowestCommonAncestorII.java | 92 ++++++++ 3 files changed, 487 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/InsertIntoBST.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestor.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestorII.java diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/InsertIntoBST.java b/Leecode/src/main/java/com/markilue/leecode/tree/InsertIntoBST.java new file mode 100644 index 0000000..25c4384 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/InsertIntoBST.java @@ -0,0 +1,187 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-10-07 12:08 + * @Description: + * TODO leecode 701题 二叉搜索树中的插入操作: + * 给定二叉搜索树(BST)的根节点root和要插入树中的值value,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。 + * 注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。 + * + * @Version: 1.0 + */ +public class InsertIntoBST { + + @Test + public void test(){ + TreeNode root = new TreeNode(4); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(7); + TreeNode TreeNode4 = new TreeNode(1); + TreeNode TreeNode5 = new TreeNode(3); +// TreeNode TreeNode6 = new TreeNode(0); +// TreeNode TreeNode7 = new TreeNode(8); +// TreeNode TreeNode8 = new TreeNode(7); +// TreeNode TreeNode9 = new TreeNode(4); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); +// TreeNode3.setRight(TreeNode7); +// TreeNode3.setLeft(TreeNode6); +// TreeNode5.setLeft(TreeNode8); +// TreeNode5.setRight(TreeNode9); + + System.out.println(inorderTraversal4(insertIntoBST2(root,5))); + } + + + /** + * 递归法:找到叶子结点即可将val加入 + * 速度击败100%,内存击败5.13% + * @param root + * @param val + * @return + */ + public TreeNode insertIntoBST(TreeNode root, int val) { + if(root==null) return new TreeNode(val); + if(root.val>val){ + root.left=insertIntoBST(root.left,val); + }else { + root.right=insertIntoBST(root.right,val); + } + return root; + } + + + /** + * 代码随想录无返回值递归法:仍然是找到叶子结点即可加入,利用一个parent节点记录之前的节点 + * @param root + * @param val + */ + TreeNode parent=null; + public void insert(TreeNode root, int val) { + if(root==null){ + TreeNode node = new TreeNode(val); + if(parent.val>val){ + parent.left=node; + }else { + parent.right=node; + } + return; + + } + parent=root; + if(root.val>val){ + insertIntoBST(root.left,val); + }else { + insertIntoBST(root.right,val); + } + } + + public TreeNode insertIntoBST1(TreeNode root, int val) { + if(root==null) return new TreeNode(val); + insert(root,val); + return root; + } + + + /** + * 迭代法: + * 速度击败100% 内存击败12.67% + * @param root + * @param val + * @return + */ + public TreeNode insertIntoBST2(TreeNode root, int val) { + if(root==null) return new TreeNode(val); + + TreeNode last=null; + + TreeNode temp=root; + + while (temp!=null){ + last=temp; + if(temp.val>val){ + temp=temp.left; + }else { + temp=temp.right; + } + } + + if(last.val>val){ + last.left=new TreeNode(val); + }else { + last.right=new TreeNode(val); + } + + return root; + } + + + + + + /** + * 自己尝试Morris中序遍历 + * 速度超过100%,内存超过81.82% + * @param root + */ + public static List inorderTraversal4(TreeNode root) { + + List list1 = new ArrayList(); + + TreeNode node1 = root; + TreeNode node2 = null; + + while (node1 != null) { + node2 = node1.left; + + //判断左边还有没有值 + if(node2!=null){ + //首先找到遍历node1之前的最后一个节点 + while (node2.right != null && node2.right != node1) { + node2 = node2.right; + } + + //判断是从哪个条件出来的 + if (node2.right == null) { + //如果是从第一个条件出来的,那么就是没有遍历过得节点 + + //将这个节点的右边定为node1方便以后回来,找到node1 + node2.right = node1; + //node1已经可以回溯,放心将node1左移 + node1 = node1.left; + continue; + } else { + //如果是从第二个条件出来的,那么就是遍历过的节点 + + //那么他的左边一定是遍历完了,这时将node的值加入结果 + list1.add(node1.val); + //左边遍历完了,往右移 + node1 = node1.right; + } + }else { + //左边没值了 + list1.add(node1.val); + node1=node1.right; + + } + + + } + + + return list1; + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestor.java b/Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestor.java new file mode 100644 index 0000000..8847c3c --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestor.java @@ -0,0 +1,208 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-10-07 09:30 + * @Description: TODO 力扣236题 二叉树的最近公共祖先: + * 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 + * 百度百科中最近公共祖先的定义为: + * “对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” + * @Version: 1.0 + */ +public class LowestCommonAncestor { + + @Test + public void test() { + TreeNode root = new TreeNode(3); + TreeNode TreeNode2 = new TreeNode(5); + TreeNode TreeNode3 = new TreeNode(1); + TreeNode TreeNode4 = new TreeNode(6); + TreeNode TreeNode5 = new TreeNode(2); + TreeNode TreeNode6 = new TreeNode(0); + TreeNode TreeNode7 = new TreeNode(8); + TreeNode TreeNode8 = new TreeNode(7); + TreeNode TreeNode9 = new TreeNode(4); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode7); + TreeNode3.setLeft(TreeNode6); + TreeNode5.setLeft(TreeNode8); + TreeNode5.setRight(TreeNode9); + + System.out.println(lowestCommonAncestor1(root, TreeNode2, TreeNode3).val); + + } + + @Test + public void test1() { + TreeNode root = new TreeNode(3); + TreeNode TreeNode2 = new TreeNode(5); + TreeNode TreeNode3 = new TreeNode(1); + TreeNode TreeNode4 = new TreeNode(6); + TreeNode TreeNode5 = new TreeNode(2); + TreeNode TreeNode6 = new TreeNode(0); + TreeNode TreeNode7 = new TreeNode(8); + TreeNode TreeNode8 = new TreeNode(7); + TreeNode TreeNode9 = new TreeNode(4); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode7); + TreeNode3.setLeft(TreeNode6); + TreeNode5.setLeft(TreeNode8); + TreeNode5.setRight(TreeNode9); + + System.out.println(lowestCommonAncestor1(root, TreeNode2, TreeNode9).val); + + } + + + /** + * 本人思路:递归法:用一个boolean值记录是否找到了p,q如果找到了就可以返回当前叶子节点 + * 速度超过5.09%,内存超过38.12% + * 慢之处在于即使找到了还需要继续遍历,因为本人这种方式是自顶向下遍历的方式,找到的不一定是最近公共祖先,只能通过不断遍历的方式确定 + * + * @param root + * @param p + * @param q + * @return + */ + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + find(root, p, q); + return result; + } + + + TreeNode result = null; + boolean flag = false; + + public boolean find(TreeNode root, TreeNode p, TreeNode q) { + if (root == null) { + return false; + } + + //记录两个树值是否找到 + boolean flagp = false; + boolean flagq = false; + + + if (p != null) { + if (root.val == p.val) { + flagp = true; + } else { + //这里只找p + flagp = find(root.left, p, null) || find(root.right, p, null); + } + } + + if (q != null) { + if (root.val == q.val) { + flagq = true; + } else { + flagq = find(root.left, null, q) || find(root.right, null, q); + } + } + + + if (flagp && flagq) { + result = root; + find(root.left, p, q); + find(root.right, p, q); +// flag = true; + } + + + return flagp || flagq; + + + } + + + /** + * 代码随想录思路:递归法:最近节点->如果能自底向上查找就好了,因此可以使用回溯,回溯的过程就是自底向上,二叉树的后续遍历就符合回溯过程,先处理的一定是叶子结点 + * 速度超过100%,内存超过28.79% + *

+ * 递归三部曲: + * 1)确定递归函数返回值和参数:TreeNode 找到了就返回这个节点 + * 2)确定终止条件:找到p或q或者空节点就返回 + * 3)确定单层递归逻辑:通过递归函数确定该节点是不是公共节点 + * + * + * @param root + * @param p + * @param q + * @return + */ + public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) { + //这里之所以可以直接等于就返回,是因为后边还有判断right边有没有,如果right边没有,那么一定是在left边的子树上,这里默认两个子树一定存在。 + if (root == p || root == q || root == null) return root; + + TreeNode left = lowestCommonAncestor1(root.left, p, q); + TreeNode right = lowestCommonAncestor1(root.right, p, q); + + //如果left和right都有值,那么证明当前节点就是最近 + //反之如果任意没有值就返回另一边 + if(left!=null&&right!=null){ + return root; + }else if(left==null){ + return right; + }else { + return left; + } + } + + + + Map parent = new HashMap(); + Set visited = new HashSet(); + + public void dfs(TreeNode root) { + if (root.left != null) { + parent.put(root.left.val, root); + dfs(root.left); + } + if (root.right != null) { + parent.put(root.right.val, root); + dfs(root.right); + } + } + + /** + * 官方另一种解法:利用map记录父节点,q不断回溯来寻找最近节点 + * @param root + * @param p + * @param q + * @return + */ + public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) { + dfs(root); + while (p != null) { + visited.add(p.val); + p = parent.get(p.val); + } + while (q != null) { + if (visited.contains(q.val)) { + return q; + } + q = parent.get(q.val); + } + return null; + } + + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestorII.java b/Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestorII.java new file mode 100644 index 0000000..b6be9fb --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestorII.java @@ -0,0 +1,92 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-10-07 11:29 + * @Description: TODO leecode 235题 二叉搜索树的最近公共祖先: + * 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 + * 百度百科中最近公共祖先的定义为: + * “对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” + * @Version: 1.0 + */ +public class LowestCommonAncestorII { + + @Test + public void test(){ + TreeNode root = new TreeNode(6); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(8); + TreeNode TreeNode4 = new TreeNode(0); + TreeNode TreeNode5 = new TreeNode(4); + TreeNode TreeNode6 = new TreeNode(7); + TreeNode TreeNode7 = new TreeNode(9); + TreeNode TreeNode8 = new TreeNode(3); + TreeNode TreeNode9 = new TreeNode(5); + + root.setRight(TreeNode3); + root.setLeft(TreeNode2); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode7); + TreeNode3.setLeft(TreeNode6); + TreeNode5.setLeft(TreeNode8); + TreeNode5.setRight(TreeNode9); + + System.out.println(lowestCommonAncestor(root, TreeNode2, TreeNode3).val); + System.out.println(lowestCommonAncestor(root, TreeNode2, TreeNode5).val); + } + + + /** + * 二叉搜索树的特性:root节点比左边大,右边小 + * 速度击败36.19%,内存击败82.68% + * @param root + * @param p + * @param q + * @return + */ + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + + + if (root == null ) return root; + if(root.val>p.val&&root.val>q.val){ + return lowestCommonAncestor(root.left, p, q); + } + + if(root.val ancestor.val && q.val > ancestor.val) { + ancestor = ancestor.right; + } else { + break; + } + } + return ancestor; + } + + + + +} From 1028801e7640ebab1c20c1bab36da97141d8c097 Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Sat, 8 Oct 2022 14:28:53 +0800 Subject: [PATCH 38/38] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../markilue/leecode/tree/DeleteNodeII.java | 254 ++++++++++++++++++ .../com/markilue/leecode/tree/TrimBST.java | 130 +++++++++ 2 files changed, 384 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/DeleteNodeII.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/TrimBST.java diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNodeII.java b/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNodeII.java new file mode 100644 index 0000000..52fe779 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNodeII.java @@ -0,0 +1,254 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.List; + +import static com.markilue.leecode.tree.InorderTraversal.inorderTraversal1; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-10-08 09:22 + * @Description: TODO leecode 450题 删除二叉搜索树中的节点: + * 给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的key对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。 + * 一般来说,删除节点可分为两个步骤: + * 1)首先找到需要删除的节点; + * 2)如果找到了,删除它。 + * @Version: 1.0 + */ +public class DeleteNodeII { + + @Test + public void test(){ + TreeNode root = new TreeNode(4); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(6); + TreeNode TreeNode4 = new TreeNode(1); + TreeNode TreeNode5 = new TreeNode(3); + TreeNode TreeNode6 = new TreeNode(5); + + root.setLeft(TreeNode2); + root.setRight(TreeNode3); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + TreeNode3.setLeft(TreeNode6); + + deleteNode1(root, 5); + + List integers = inorderTraversal1(root); + + System.out.println(integers); + } + + + @Test + public void test1(){ + TreeNode root = new TreeNode(5); + TreeNode TreeNode2 = new TreeNode(3); + TreeNode TreeNode3 = new TreeNode(6); + TreeNode TreeNode4 = new TreeNode(2); + TreeNode TreeNode5 = new TreeNode(4); + TreeNode TreeNode6 = new TreeNode(7); + + root.setLeft(TreeNode2); + root.setRight(TreeNode3); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode6); + + deleteNode1(root, 3); + + List integers = inorderTraversal1(root); + + System.out.println(integers); + } + + + /** + * 迭代法:找到该节点,然后找到该节点的右子节点的最左节点将其替换,在删除其最左节点 + * 参考官方迭代法的简洁写法,可以发现官方是使用了child节点记录需要删除的子节点,使得代码统一,同时也避免了两重if + * 速度击败100%,内存击败78.04% + * @param root + * @param key + * @return + */ + public TreeNode deleteNode(TreeNode root, int key) { + + //后面的逻辑中包含了这个 +// if (root == null) { +// return null; +// } + + //TODO 寻找该节点 + TreeNode temp = root; + TreeNode father=null; + while (temp != null && temp.val != key) { + father=temp; + if (temp.val > key) { + temp = temp.left; + } else { + temp = temp.right; + } + } + + //TODO 判断是什么条件出来的 + //这里是没找到 + if(temp==null){ + return root; + } + + TreeNode change=temp; //记录需要改变的这个节点 + + //有两个子节点的情况 + if (temp.right!=null){ + father=temp; + temp=temp.right; + + //寻找该右子节点的最左节点 + while (temp.left!=null){ + father=temp; + temp=temp.left; + } + change.val=temp.val; //将最左节点的值赋值给需要改变的节点,接下来删除最左节点 + change=temp; + } + + //删除的是根节点 + if(father==null){ + if(temp.left!=null){ + return temp.left; + } + return null; + } + + + //TODO 处理单节点的情况 + + //继续删除temp节点,这里要判断他有没有左节点,如果有则是从temp.right!=null出来的 + if(temp.left!=null){ + if(father.left==temp){ + father.left=temp.left; + }else { + father.right=temp.left; + } + } + + + + //继续删除temp节点,这里要判断他有没有有节点,如果有则是进入过temp.right!=null出来的 + if (temp.right!=null){ + if(father.left==temp){ + father.left=temp.right; + }else { + father.right=temp.right; + } + } + + //处理叶子节点的情况 + if(temp.left==null&&temp.right==null){ + if(father.left==temp){ + father.left=null; + }else { + father.right=null; + } + } + + return root; + + + } + + + /** + * 递归法:找到该节点,然后找到该节点的右子节点的最左节点将其替换,在删除其最左节点 + * + * 速度击败100%,内存击败19.68% + * @param root + * @param key + * @return + */ + public TreeNode deleteNode1(TreeNode root, int key) { + + if(root==null)return null; + + if(root.valkey){ + root.left=deleteNode1(root.left,key); + return root; + }else { + TreeNode result=root; + TreeNode father=null; + //需要删除的节点 + if(root.right!=null){ + father=root; + TreeNode temp=root.right; + while (temp.left!=null){ + father=temp; + temp=temp.left; + } + root.val=temp.val; + root=temp; + } + TreeNode child=null; + if(root.left!=null)child= root.left; + if(root.right!=null)child= root.right; + if(father==null) return child; + else if(father.left==root)father.left=child; + else father.right=child; + + return result; + } + + } + + + /** + * 官方递归法: + * @param root + * @param key + * @return + */ + public TreeNode deleteNode2(TreeNode root, int key) { + if (root == null) { + return null; + } + if (root.val > key) { + root.left = deleteNode(root.left, key); + return root; + } + if (root.val < key) { + root.right = deleteNode(root.right, key); + return root; + } + if (root.val == key) { + if (root.left == null && root.right == null) { + return null; + } + if (root.right == null) { + return root.left; + } + if (root.left == null) { + return root.right; + } + TreeNode successor = root.right; + while (successor.left != null) { + successor = successor.left; + } + + //这里删除节点,然后将删完的好节点付给successor并返回(是否可以直接将root的值变为successor的值?) + root.right = deleteNode(root.right, successor.val); + successor.right = root.right; + successor.left = root.left; + return successor; + } + return root; + } + + + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/TrimBST.java b/Leecode/src/main/java/com/markilue/leecode/tree/TrimBST.java new file mode 100644 index 0000000..b9c24e1 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/TrimBST.java @@ -0,0 +1,130 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Stack; + +import static com.markilue.leecode.tree.InorderTraversal.inorderTraversal1; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-10-08 11:45 + * @Description: TODO 力扣669题 修剪二叉搜索树: + * 给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。 + * 修剪树 不应该改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在唯一的答案。 + * 所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。 + * @Version: 1.0 + */ +public class TrimBST { + + @Test + public void test() { + TreeNode root = new TreeNode(3); + TreeNode TreeNode2 = new TreeNode(0); + TreeNode TreeNode3 = new TreeNode(4); + TreeNode TreeNode4 = new TreeNode(2); + TreeNode TreeNode5 = new TreeNode(1); +// TreeNode TreeNode6 = new TreeNode(7); + + root.setLeft(TreeNode2); + root.setRight(TreeNode3); + TreeNode2.setRight(TreeNode4); + TreeNode4.setLeft(TreeNode5); +// TreeNode3.setRight(TreeNode6); + + TreeNode node = trimBST2(root, 1, 3); + + List integers = inorderTraversal1(node); + + System.out.println(integers); + } + + /** + * 初步思路:使用deleteNode一个一个删除 + * + * @param root + * @param low + * @param high + * @return + */ + public TreeNode trimBST(TreeNode root, int low, int high) { + for (int i = low; i < high; i++) { + DeleteNodeII deleteNodeII = new DeleteNodeII(); + root = deleteNodeII.deleteNode(root, i); + } + return root; + } + + + + /** + * 进阶思路:代码随想录递归法 + * 利用二叉搜索树的特性实现快速删除:找到low,将low.right直接代替low;找到high,将high.left直接代替high + * 其他时候比他小就返回修完右边的值,比他大就返回修完左边的值 + * 速度击败100% 内存击败18.83% + * @param root + * @param low + * @param high + * @return + */ + public TreeNode trimBST2(TreeNode root, int low, int high) { + if (root == null) return null; + if (root.val < low) return trimBST2(root.right, low, high); + if (root.val > high) return trimBST2(root.left, low, high); + root.left = trimBST2(root.left, low, high); + root.right = trimBST2(root.right, low, high); + return root; + } + + + /** + * 进阶思路:代码随想录迭代法 + * 利用二叉搜索树的特性实现快速删除:先找到第一个在区间内的数,以此为根基,分别处理其左节点和右节点,左节点往右移;右节点往左移 + * 其他时候比他小就返回修完右边的值,比他大就返回修完左边的值 + * 速度击败100% 内存击败38.55% + * @param root + * @param low + * @param high + * @return + */ + public TreeNode trimBST3(TreeNode root, int low, int high) { + if(root==null)return null; + + //处理头结点,让root移动到一个在区间内的数 + while (root!=null&&(root.valhigh)){ + if(root.valhigh){ + cur.right=cur.right.left; + } + //处理完毕,安心将cur右移,继续判断其左节点会不会超过 + cur=cur.right; + //这里不需要判断左节点,因为root在区间内,那么右子树最小也就是root,所以不会超过其左界 + } + + //全部处理完毕,安心返回root + return root; + } +}