├── image ├── WechatIMG2430.jpeg └── 931551357495_.pic.jpg ├── src └── main │ └── java │ └── com │ └── algorithm │ └── study │ └── demo │ ├── base │ ├── IPerson.java │ ├── AppleMobile.java │ ├── Mobile.java │ ├── YellowPerson.java │ ├── IphoneXMobile.java │ ├── HuaweiMobile.java │ └── MainTest.java │ ├── thread │ ├── ThreadTest.java │ ├── SleepUtils.java │ ├── Daemon.java │ ├── Profiler.java │ ├── Join.java │ ├── DeadlockTest.java │ ├── CountTask.java │ ├── Mutex.java │ ├── Piped.java │ └── TestTryLock.java │ ├── reflect │ ├── Service.java │ ├── ServiceImpl.java │ ├── CGlibServiceImpl.java │ ├── PerformanceMonitor.java │ ├── Test.java │ ├── CGlibProxyFactory.java │ └── ServiceHandler.java │ ├── java8 │ ├── ApplePredicate.java │ ├── BufferedReaderProcessor.java │ ├── hello3.java │ ├── StreamDemo.java │ ├── Apple.java │ ├── Hello2.java │ ├── Hello.java │ ├── FunctionTest.java │ ├── Hello4.java │ └── Hello5.java │ ├── mode │ ├── templates │ │ ├── TemplateInterface.java │ │ ├── SubClassOne.java │ │ ├── SubClassTwo.java │ │ └── TemplateAbstractClass.java │ ├── factory │ │ ├── Human.java │ │ ├── AbstractHumanFactory.java │ │ ├── BlackHuman.java │ │ ├── WhiteHuman.java │ │ └── HumanFactory.java │ ├── proxy │ │ ├── IGamePlayer.java │ │ ├── MainTest.java │ │ ├── GamePlayer.java │ │ └── GamePlayerProxy.java │ ├── strategy │ │ ├── MemberStrategy.java │ │ ├── PrimaryMemberStrategy.java │ │ ├── IntermediateMemberStrategy.java │ │ └── Price.java │ ├── decorator │ │ ├── CondimentDecorator.java │ │ ├── Beverage.java │ │ ├── Client.java │ │ ├── HouseBlend.java │ │ ├── Mocha.java │ │ └── Milk.java │ ├── singleton │ │ ├── Singleton.java │ │ ├── SingletonTest2.java │ │ ├── EnumSingleton.java │ │ ├── SingletonTest1.java │ │ └── SingletonTest3.java │ └── TestMode.java │ ├── nio │ ├── SelectorTest.java │ ├── FileChannelTest.java │ ├── ChannelTest.java │ └── SocketChannelTest.java │ ├── datastructure │ ├── linear │ │ ├── ListNode.java │ │ ├── MyArrayList.java │ │ └── Solution.java │ ├── stack │ │ ├── LinkStack.java │ │ └── ArrayStack.java │ ├── queue │ │ ├── LinkQueue.java │ │ └── SqQueue.java │ ├── heap │ │ ├── MidNumCount.java │ │ ├── Heap.java │ │ └── TopkCount.java │ └── graph │ │ └── Mgraph.java │ ├── testng │ └── Test.java │ ├── enums │ ├── Calculator.java │ ├── MainTest.java │ └── Operator.java │ ├── algorithm │ ├── greedyalgorithm │ │ ├── MoneyBusi.java │ │ └── Solutions.java │ ├── MainDemo.java │ ├── TanxinSolution.java │ ├── leetcode │ │ ├── Solution12.java │ │ ├── Solution11.java │ │ ├── Solution20.java │ │ ├── Solution5.java │ │ ├── Solution13.java │ │ ├── Solution22.java │ │ ├── Solution17.java │ │ ├── Solution26.java │ │ ├── Solution15.java │ │ ├── Solution24.java │ │ ├── Solution10.java │ │ ├── Solution6.java │ │ ├── Solution9.java │ │ ├── Solution14.java │ │ ├── Solution4.java │ │ ├── Solution25.java │ │ ├── Solution16.java │ │ ├── Solution2.java │ │ ├── Solution3.java │ │ ├── Solution27.java │ │ ├── Solution7.java │ │ ├── Solution8.java │ │ ├── Solution18.java │ │ ├── Solution.java │ │ ├── Solution23.java │ │ ├── Solution19.java │ │ └── Solution21.java │ ├── huffman │ │ ├── StrProc.java │ │ ├── TestHuffmanCode.java │ │ └── DataOutputStreamHuffman.java │ ├── Jianzhi01.java │ ├── ArraySolution.java │ ├── dynamicprogramming │ │ └── demo1.java │ ├── Solution.java │ └── StringSolution.java │ ├── OptionalTest.java │ ├── jvm │ ├── HeapOOM.java │ └── StackSOF.java │ ├── model │ └── User.java │ ├── atomic │ ├── AtomicIntegerArrayTest.java │ ├── AtomicIntegerTest.java │ ├── AtomicReferenceTest.java │ ├── AtomicIntegerFieldUpdaterTest.java │ └── AtomicStampedReferenceDemo.java │ ├── leetcode │ └── Solution.java │ ├── MainTest1.java │ ├── LRUCache │ ├── LRULinkedMap.java │ ├── LRULinked.java │ └── LRUCache.java │ ├── concurrent │ ├── SemaphoreTest.java │ ├── JoinCountDownLatchTest.java │ ├── BankWaterService.java │ ├── CyclicBarrierTest.java │ └── CallableDemo.java │ ├── guava │ └── MainTest.java │ ├── util │ ├── DateUtils.java │ ├── Paging.java │ └── ZipUtil.java │ ├── jike │ └── Linked_6.java │ └── string │ └── TestString.java ├── MD ├── Linux.md ├── Reference.md └── String.MD ├── .gitignore └── pom.xml /image/WechatIMG2430.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/randian666/algorithm-study/HEAD/image/WechatIMG2430.jpeg -------------------------------------------------------------------------------- /image/931551357495_.pic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/randian666/algorithm-study/HEAD/image/931551357495_.pic.jpg -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/base/IPerson.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.base; 2 | 3 | public interface IPerson { 4 | void eat(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/base/AppleMobile.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.base; 2 | 3 | public abstract class AppleMobile extends Mobile{ 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/thread/ThreadTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.thread; 2 | 3 | public class ThreadTest { 4 | public static void main(String[] args) { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/reflect/Service.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.reflect; 2 | 3 | /** 4 | * Created by liuxun on 2017/7/17. 5 | */ 6 | public interface Service { 7 | public void service(String arg); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/java8/ApplePredicate.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.java8; 2 | 3 | /** 4 | * Created by liuxun on 2017/7/10. 5 | */ 6 | public interface ApplePredicate { 7 | public boolean test(Apple apple); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/base/Mobile.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.base; 2 | 3 | public abstract class Mobile { 4 | public abstract void call(); 5 | 6 | void show(){ 7 | System.out.println("show"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/base/YellowPerson.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.base; 2 | 3 | public class YellowPerson implements IPerson { 4 | @Override 5 | public void eat() { 6 | System.out.println("kuaizi eat"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/base/IphoneXMobile.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.base; 2 | 3 | public class IphoneXMobile extends AppleMobile { 4 | @Override 5 | public void call() { 6 | System.out.println("iphonex call"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/templates/TemplateInterface.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.templates; 2 | 3 | /** 4 | * 模板方法接口 5 | * Created by liuxun on 2017/7/14. 6 | */ 7 | public interface TemplateInterface { 8 | void execute(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/factory/Human.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.factory; 2 | 3 | /** 4 | * 人类 5 | * Created by liuxun on 2017/7/14. 6 | */ 7 | public interface Human { 8 | void getColor();//人有不同的颜色 9 | void talk(); //人会说话 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/proxy/IGamePlayer.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.proxy; 2 | 3 | /** 4 | * 游戏者接口 5 | */ 6 | public interface IGamePlayer { 7 | void login(String userName,String password); 8 | void killBoss(); 9 | void upgrade(); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/strategy/MemberStrategy.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.strategy; 2 | 3 | /** 4 | * 计算图书价格-行为 5 | * Created by LiuXun on 2017/7/13. 6 | */ 7 | public interface MemberStrategy { 8 | public double calcPrice(double bookePrice); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/nio/SelectorTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.nio; 2 | 3 | /** 4 | * @author liuxun 5 | * @version V1.0 6 | * @Description: Nio Selector 7 | * @date 2017/12/5 8 | */ 9 | public class SelectorTest { 10 | public static void main(String[] args) { 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/decorator/CondimentDecorator.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.decorator; 2 | 3 | /** 4 | * 装饰类 5 | * @Author: liuxun 6 | * @CreateDate: 2019/2/7 下午5:15 7 | * @Version: 1.0 8 | */ 9 | public abstract class CondimentDecorator extends Beverage { 10 | public abstract String getDescription(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/reflect/ServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.reflect; 2 | 3 | /** 4 | * Created by liuxun on 2017/7/17. 5 | */ 6 | public class ServiceImpl implements Service{ 7 | @Override 8 | public void service(String arg) { 9 | System.out.println("service is called...arg : "+arg); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/factory/AbstractHumanFactory.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.factory; 2 | 3 | /** 4 | * 工厂抽象接口 5 | * Created by liuxun on 2017/7/14. 6 | */ 7 | public abstract class AbstractHumanFactory { 8 | public abstract T createHuman(Class clazz);//注意这里T必须是Human的实现类才行,因为要造Human嘛 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/reflect/CGlibServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.reflect; 2 | 3 | /** 4 | * @author liuxun 5 | * @version V1.0 6 | * @Description: 没有实现接口的类 7 | * @date 2017/12/4 8 | */ 9 | public class CGlibServiceImpl { 10 | public void excute(){ 11 | System.out.println("开始执行没有实现接口的类的方法..."); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/base/HuaweiMobile.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.base; 2 | 3 | public class HuaweiMobile extends Mobile{ 4 | 5 | @Override 6 | public void call() { 7 | System.out.println("huawei call"); 8 | } 9 | @Override 10 | public void show(){ 11 | System.out.println("niubi show"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/datastructure/linear/ListNode.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.datastructure.linear; 2 | 3 | /** 4 | * 链表数据结构 5 | * @Author: liuxun 6 | * @CreateDate: 2019/2/12 下午3:43 7 | * @Version: 1.0 8 | */ 9 | public class ListNode { 10 | int val; 11 | ListNode next; 12 | public ListNode(int val){ 13 | this.val=val; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/testng/Test.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.testng; 2 | 3 | import com.algorithm.study.demo.thread.SleepUtils; 4 | 5 | public class Test { 6 | 7 | @org.testng.annotations.Test(threadPoolSize = 10, invocationCount = 10000) 8 | public void testJsf(){ 9 | System.out.println("asdklfjalskfdj"+Thread.currentThread().getName()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/enums/Calculator.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.enums; 2 | 3 | /** 4 | * @author xun2.liu 5 | * @title: Calculator 6 | * @projectName algorithm-study 7 | * @description: TODO 8 | * @date 2020/1/7 14:51 9 | */ 10 | public class Calculator{ 11 | 12 | public int apply(int a, int b,Operator operator) { 13 | return operator.apply(a,b); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/java8/BufferedReaderProcessor.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.java8; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | 6 | /** 7 | * BufferedReader函数式接口 8 | * Created by liuxun on 2017/7/11. 9 | */ 10 | @FunctionalInterface 11 | public interface BufferedReaderProcessor { 12 | String process(BufferedReader buff)throws IOException; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/decorator/Beverage.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.decorator; 2 | 3 | /** 4 | * @Author: liuxun 5 | * @CreateDate: 2019/2/7 下午5:13 6 | * @Version: 1.0 7 | */ 8 | public abstract class Beverage { 9 | protected String description=""; 10 | public String getDescription(){ 11 | return description; 12 | } 13 | public abstract double cost(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/strategy/PrimaryMemberStrategy.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.strategy; 2 | 3 | /** 4 | * 初级会员价格--策略 5 | * Created by LiuXun on 2017/7/13. 6 | */ 7 | public class PrimaryMemberStrategy implements MemberStrategy { 8 | public double calcPrice(double bookePrice) { 9 | System.out.println("初级会员价格为:"+bookePrice); 10 | return bookePrice; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/strategy/IntermediateMemberStrategy.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.strategy; 2 | 3 | /** 4 | * 中级会员价格-策略 5 | * Created by LiuXun on 2017/7/13. 6 | */ 7 | public class IntermediateMemberStrategy implements MemberStrategy { 8 | public double calcPrice(double bookePrice) { 9 | System.out.println("中级会员价格为:"+bookePrice); 10 | return bookePrice; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/factory/BlackHuman.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.factory; 2 | 3 | /** 4 | * Created by liuxun on 2017/7/14. 5 | */ 6 | public class BlackHuman implements Human { 7 | @Override 8 | public void getColor() { 9 | System.out.println("Black"); 10 | } 11 | 12 | @Override 13 | public void talk() { 14 | System.out.println("Black man talk"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/thread/SleepUtils.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.thread; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | /** 6 | * Created by liuxun on 2017/6/15. 7 | */ 8 | public class SleepUtils { 9 | public static final void second(long seconds) { 10 | try { 11 | TimeUnit.SECONDS.sleep(seconds); 12 | } catch (InterruptedException e) { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/decorator/Client.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.decorator; 2 | 3 | /** 4 | * @Author: liuxun 5 | * @CreateDate: 2019/2/7 下午5:24 6 | * @Version: 1.0 7 | */ 8 | public class Client { 9 | public static void main(String[] args) { 10 | Beverage beverage=new Milk(new Mocha(new HouseBlend())); 11 | System.out.println(beverage.getDescription()+",cost:"+beverage.cost()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/decorator/HouseBlend.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.decorator; 2 | 3 | /** 4 | * 具体的实现类 5 | * @Author: liuxun 6 | * @CreateDate: 2019/2/7 下午5:13 7 | * @Version: 1.0 8 | */ 9 | public class HouseBlend extends Beverage { 10 | public HouseBlend(){ 11 | description="House Bleand coffee"; 12 | } 13 | @Override 14 | public double cost() { 15 | return 4; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/factory/WhiteHuman.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.factory; 2 | 3 | /** 4 | * 白种人 5 | * Created by liuxun on 2017/7/14. 6 | */ 7 | public class WhiteHuman implements Human { 8 | @Override 9 | public void getColor() { 10 | System.out.println("White"); 11 | } 12 | 13 | @Override 14 | public void talk() { 15 | System.out.println("White man talk"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/reflect/PerformanceMonitor.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.reflect; 2 | 3 | /** 4 | * 我们想在执行Service的service方法的前后加入PerformanceMonitor的begin和end 5 | * Created by liuxun on 2017/7/17. 6 | */ 7 | public class PerformanceMonitor { 8 | public static void begin(){ 9 | System.out.println("监控开始..."); 10 | } 11 | 12 | public static void end(){ 13 | System.out.println("监控结束..."); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/proxy/MainTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.proxy; 2 | 3 | public class MainTest { 4 | public static void main(String[] args) { 5 | /** 6 | * 为其他对象提供一种代理以控制对这个对象的访问 7 | * 8 | */ 9 | IGamePlayer gamePlayer=new GamePlayer("刘勋"); 10 | GamePlayerProxy proxy=new GamePlayerProxy(gamePlayer); 11 | proxy.login("liuxun","xxxxx"); 12 | proxy.killBoss(); 13 | proxy.upgrade(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/templates/SubClassOne.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.templates; 2 | 3 | /** 4 | * 基本方法的具体实现 5 | * Created by liuxun on 2017/7/14. 6 | */ 7 | public class SubClassOne extends TemplateAbstractClass{ 8 | 9 | @Override 10 | public void preDoSomething() { 11 | System.out.println("SubClassOne do preDoSomething"); 12 | } 13 | 14 | @Override 15 | public void afterDoSomething() { 16 | System.out.println("SubClassOne do afterDoSomething"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/templates/SubClassTwo.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.templates; 2 | 3 | /** 4 | * 基本方法的具体实现 5 | * Created by liuxun on 2017/7/14. 6 | */ 7 | public class SubClassTwo extends TemplateAbstractClass{ 8 | 9 | @Override 10 | public void preDoSomething() { 11 | System.out.println("SubClassTwo do preDoSomething"); 12 | } 13 | 14 | @Override 15 | public void afterDoSomething() { 16 | System.out.println("SubClassTwo do afterDoSomething"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/factory/HumanFactory.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.factory; 2 | 3 | /** 4 | * 工厂抽象实现 5 | * Created by liuxun on 2017/7/14. 6 | */ 7 | public class HumanFactory { 8 | public static T createHuman(Class clazz) { 9 | Human human=null; 10 | try { 11 | human=(Human)Class.forName(clazz.getName()).newInstance(); 12 | } catch (Exception e) { 13 | System.out.println("没有该人类"); 14 | } 15 | return (T)human; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/greedyalgorithm/MoneyBusi.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.greedyalgorithm; 2 | 3 | import lombok.*; 4 | 5 | /** 6 | * @title: MoneyBusi 7 | * @projectName algorithm-study 8 | * @description: 零钱支付 9 | * @date 2019/11/14 17:19 10 | */ 11 | @Getter 12 | @Setter 13 | @ToString 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | public class MoneyBusi { 17 | /** 面值 */ 18 | private String value; 19 | 20 | /** 张数 */ 21 | private int num; 22 | 23 | /** 金额 */ 24 | private int memory; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/enums/MainTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.enums; 2 | 3 | import java.text.ParseException; 4 | 5 | /** 6 | * @author xun2.liu 7 | * @title: MainTest 8 | * @projectName algorithm-study 9 | * @description: 枚举类解决IF ESLE问题 10 | * @date 2019/12/13 16:32 11 | */ 12 | public class MainTest{ 13 | public static void main(String[] args) throws ParseException { 14 | Calculator calculator=new Calculator(); 15 | int result=calculator.apply(2,4,Operator.ADD); 16 | System.out.println(result); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/OptionalTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo; 2 | 3 | import com.algorithm.study.demo.string.TestString; 4 | 5 | import java.math.BigDecimal; 6 | import java.text.NumberFormat; 7 | import java.util.Optional; 8 | 9 | /** 10 | * @title: OptionalTest 11 | * @projectName algorithm-study 12 | * @description: TODO 13 | * @date 2019/8/21 10:10 14 | */ 15 | public class OptionalTest { 16 | public static void main(String[] args) { 17 | for (int i = 5; i > 0; i--) { 18 | System.out.println(i); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/strategy/Price.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.strategy; 2 | 3 | /** 4 | * 价格类-锦囊 5 | * Created by LiuXun on 2017/7/13. 6 | */ 7 | public class Price { 8 | private MemberStrategy memberStrategy; 9 | 10 | public Price(MemberStrategy memberStrategy){ 11 | this.memberStrategy=memberStrategy; 12 | } 13 | /** 14 | * 计算图书的价格 15 | * @param booksPrice 图书的原价 16 | * @return 计算出打折后的价格 17 | */ 18 | public double quote(double booksPrice){ 19 | return this.memberStrategy.calcPrice(booksPrice); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/decorator/Mocha.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.decorator; 2 | 3 | /** 4 | * @Author: liuxun 5 | * @CreateDate: 2019/2/7 下午5:17 6 | * @Version: 1.0 7 | */ 8 | public class Mocha extends CondimentDecorator { 9 | private Beverage beverage; 10 | public Mocha(Beverage beverage){ 11 | this.beverage=beverage; 12 | } 13 | @Override 14 | public double cost() { 15 | return 1+beverage.cost(); 16 | } 17 | 18 | @Override 19 | public String getDescription() { 20 | return beverage.getDescription()+",with Mocha"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/decorator/Milk.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.decorator; 2 | 3 | /** 4 | * 具体装饰类- 5 | * @Author: liuxun 6 | * @CreateDate: 2019/2/7 下午5:15 7 | * @Version: 1.0 8 | */ 9 | public class Milk extends CondimentDecorator{ 10 | protected Beverage beverage; 11 | public Milk(Beverage beverage){ 12 | this.beverage=beverage; 13 | } 14 | 15 | @Override 16 | public String getDescription() { 17 | return beverage.getDescription()+",with milk"; 18 | } 19 | 20 | @Override 21 | public double cost() { 22 | return 2+beverage.cost(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/base/MainTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.base; 2 | 3 | public class MainTest { 4 | private static final String msgg="123"; 5 | public static void main(String[] args) { 6 | MainTest mo=new MainTest(); 7 | Mobile mobile=new IphoneXMobile(); 8 | mobile.call(); 9 | mobile.show(); 10 | 11 | System.out.println(mobile); 12 | Mobile mobile2=new HuaweiMobile(); 13 | mobile2.call(); 14 | mobile2.show(); 15 | 16 | System.out.println(mobile); 17 | 18 | 19 | IPerson per = new YellowPerson(); 20 | per.eat(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/proxy/GamePlayer.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.proxy; 2 | 3 | /** 4 | * 游戏者 5 | */ 6 | public class GamePlayer implements IGamePlayer{ 7 | private String name; 8 | 9 | public GamePlayer(String name) { 10 | this.name = name; 11 | } 12 | 13 | public void login(String userName, String password) { 14 | System.out.println(name+"开始登录,用户名为:"+userName+",密码为:"+password); 15 | } 16 | 17 | public void killBoss() { 18 | System.out.println(name+"开始杀怪"); 19 | } 20 | 21 | public void upgrade() { 22 | System.out.println(name+"开始升级"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/proxy/GamePlayerProxy.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.proxy; 2 | 3 | /** 4 | * 游戏代练者 5 | */ 6 | public class GamePlayerProxy implements IGamePlayer{ 7 | private IGamePlayer iGamePlayer; 8 | public GamePlayerProxy(IGamePlayer iGamePlayer) { 9 | this.iGamePlayer=iGamePlayer; 10 | } 11 | 12 | public void login(String userName, String password) { 13 | iGamePlayer.login(userName,password); 14 | } 15 | 16 | public void killBoss() { 17 | iGamePlayer.killBoss(); 18 | } 19 | 20 | public void upgrade() { 21 | iGamePlayer.upgrade(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/jvm/HeapOOM.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.jvm; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @author liuxun 8 | * @version V1.0 9 | * @Description: VM Args: -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails -XX:HeapDumpPath=E:\ 10 | * @date 2017/11/28 11 | */ 12 | public class HeapOOM { 13 | /** 14 | * Java堆溢出实例 15 | * @param args 16 | */ 17 | public static void main(String[] args) { 18 | List list=new ArrayList<>(); 19 | while (true){ 20 | list.add(new HeapOOM()); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/model/User.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.model; 2 | 3 | /** 4 | * Created by liuxun on 2017/5/22. 5 | */ 6 | public class User { 7 | private int id; 8 | private String name; 9 | public User(){ 10 | } 11 | public User(int id,String name){ 12 | this.id=id; 13 | this.name=name; 14 | } 15 | public int getId() { 16 | return id; 17 | } 18 | 19 | public void setId(int id) { 20 | this.id = id; 21 | } 22 | 23 | public String getName() { 24 | return name; 25 | } 26 | 27 | public void setName(String name) { 28 | this.name = name; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/templates/TemplateAbstractClass.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.templates; 2 | 3 | /** 4 | * 模板方法抽象类 5 | * Created by liuxun on 2017/7/14. 6 | */ 7 | public abstract class TemplateAbstractClass implements TemplateInterface{ 8 | /** 9 | * 模板方法 10 | * 为了防止恶意的操作,一般模板方法都加上final关键字,不允许被覆写 11 | * 一般是一个具体方法,也就是一个框架,实现对基本方法的调度,完成固定的逻辑。 12 | */ 13 | @Override 14 | public final void execute() { 15 | preDoSomething(); 16 | afterDoSomething(); 17 | 18 | } 19 | //基本方法 20 | protected abstract void preDoSomething(); 21 | //基本方法 22 | protected abstract void afterDoSomething(); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/atomic/AtomicIntegerArrayTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.atomic; 2 | 3 | import java.util.concurrent.atomic.AtomicIntegerArray; 4 | 5 | /** 6 | * Created by liuxun on 2017/6/27. 7 | */ 8 | public class AtomicIntegerArrayTest { 9 | static int[] value = new int[] { 1,2 }; 10 | static AtomicIntegerArray array=new AtomicIntegerArray(value); 11 | 12 | public static void main(String[] args) { 13 | array.addAndGet(0,1); 14 | System.out.println(array.get(0)); 15 | //需要注意的是,数组value通过构造方法传递进去,然后AtomicIntegerArray会将当前数组 16 | //复制一份,所以当AtomicIntegerArray对内部的数组元素进行修改时,不会影响传入的数组。 17 | System.out.println(value[0]); 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/jvm/StackSOF.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.jvm; 2 | 3 | /** 4 | * @author liuxun 5 | * @version V1.0 6 | * @Description: VM Args:-verbose:gc -Xss128k -XX:+PrintGCDetails 7 | * @date 2017/11/28 8 | */ 9 | public class StackSOF { 10 | private int stackLength=1; 11 | public void stackLeak(){ 12 | stackLength++; 13 | stackLeak(); 14 | } 15 | public static void main(String[] args) throws Exception { 16 | StackSOF sof=new StackSOF(); 17 | try { 18 | sof.stackLeak(); 19 | } catch (Exception e) { 20 | System.out.println("stack length:"+sof.stackLength); 21 | throw e; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/thread/Daemon.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.thread; 2 | 3 | /** 4 | * Created by liuxun on 2017/6/15. 5 | */ 6 | public class Daemon { 7 | public static void main(String[] args) { 8 | Thread thread = new Thread(new DaemonRunner(), "DaemonRunner"); 9 | thread.setDaemon(true); 10 | thread.start(); 11 | } 12 | static class DaemonRunner implements Runnable { 13 | public void run() { 14 | try { 15 | System.out.println("running beging"); 16 | SleepUtils.second(10); 17 | } finally { 18 | System.out.println("DaemonThread finally run."); 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /MD/Linux.md: -------------------------------------------------------------------------------- 1 | ### 用一行命令输出正在运行的java进程 2 | jps 用法 参数说明
3 | -q:只输出进程 ID 4 | -m:输出传入 main 方法的参数 5 | -l:输出完全的包名,应用主类名,jar的完全路径名 6 | -v:输出jvm参数 7 | -V:输出通过flag文件传递到JVM中的参数 8 | 9 | ### 查找Cpu过高查找方法 10 | - 第一步,找到占用cpu最高的一个线程 11 | 方法一:top -p [pid] 12 | 方法二:ps -mo spid,lwp,stime,time,%cpu -p [pid] 13 | 方法三:直接top,然后shift+h 14 | - 第二步,将其转化成16进制。假使我们得到的线程号为n,接下来将它转成16进制,记为spid 15 | 方法一:echo "obase=64;n"|bc 16 | 方法二:printf 0x%x n 17 | - 下一步,执行jstack -l pid| grep spid -A 100 打印后面100行分析问题 18 | 或者  Jstack -l PID >> 123.txt输出到文件后(spid等于文件中的nid)然后根据spid搜索定位问题 19 | 20 | ### 用一行命令查看文件的最后五行。 21 | 可以使用head(查看前几行)、tail(查看末尾几行)两个命令。 22 | 23 | 24 | ### [top 命令之后有哪些内容,有什么作用。](https://www.cnblogs.com/lxyit/p/8946741.html) 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/singleton/Singleton.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.singleton; 2 | 3 | /** 4 | * 单例设计模式-单例模式的实现:饿汉式,线程安全 但效率比较低 5 | 优点是:写起来比较简单,而且不存在多线程同步问题,避免了synchronized所造成的性能问题; 6 | 缺点是:当类SingletonTest被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间,从这以后, 7 | 这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。 8 | * Created by liuxun on 2017/7/13. 9 | */ 10 | public class Singleton { 11 | // 定义私有构造方法(防止通过 new Singleton()去实例化) 12 | private Singleton(){} 13 | // 将自身的实例对象设置为一个属性,并加上Static和final修饰符 14 | private static final Singleton instance=new Singleton(); 15 | // 静态方法返回该类的实例 16 | public static Singleton getInstance(){ 17 | return instance; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/atomic/AtomicIntegerTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.atomic; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | /** 6 | * Created by liuxun on 2017/6/27. 7 | */ 8 | public class AtomicIntegerTest { 9 | static AtomicInteger ai = new AtomicInteger(1); 10 | 11 | public static void main(String[] args) { 12 | System.out.println(ai.get()); 13 | System.out.println(ai.addAndGet(1));//以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回结果。 14 | System.out.println(ai.getAndIncrement());//以原子方式将当前值加1,注意,这里返回的是自增前的值。 15 | System.out.println(ai.get()); 16 | ai.compareAndSet(ai.get(),100);//检查当前的值是否被修改过,如果没修改过就更新 17 | System.out.println(ai.get()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/MainDemo.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm; 2 | 3 | /** 4 | * @Author: liuxun 5 | * @CreateDate: 2018/11/8 下午1:50 6 | * @Version: 1.0 7 | */ 8 | public class MainDemo { 9 | public static void main(String[] args) { 10 | for (int i=0;i<100;i++){ 11 | double redPacket = (Math.random() * (0.5 - 0.1) + 0.1); 12 | System.out.println(redPacket); 13 | } 14 | System.out.println((int)(Math.random()*0.9+0.1)); 15 | 16 | System.out.println((3+1)%8); 17 | System.out.println(f(9)); 18 | } 19 | 20 | public static int f(int i){ 21 | if (i==1) return 1; 22 | System.out.println(i); 23 | return f(i-1)+1; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/singleton/SingletonTest2.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.singleton; 2 | 3 | /** 4 | * 单例设计模式-饱汉模式 5 | 优点是:使用synchronized关键字避免多线程访问时,出现多个SingletonTest实例。 6 | 缺点是:同步方法频繁调用时,效率略低。 7 | * Created by liuxun on 2017/7/13. 8 | */ 9 | public class SingletonTest2 { 10 | // 定义私有构造方法(防止通过 new SingletonTest2()去实例化) 11 | private SingletonTest2() { 12 | } 13 | // 定义一个SingletonTest类型的变量(不初始化,注意这里没有使用final关键字) 14 | private static SingletonTest2 instance; 15 | 16 | // 定义一个静态的方法(调用时再初始化SingletonTest,使用synchronized 避免多线程访问时,可能造成重的复初始化问题) 17 | public static synchronized SingletonTest2 getInstance(){ 18 | if (instance==null) { 19 | instance = new SingletonTest2(); 20 | } 21 | return instance; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/leetcode/Solution.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.leetcode; 2 | 3 | /** 4 | * 二分查找相关题目 5 | */ 6 | public class Solution { 7 | public static void main(String[] args) { 8 | 9 | } 10 | /** 11 | * 在有重复数字的有序数组中寻找n 12 | * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 13 | * ( 例如,数组 [0,0,1,2,2,5,6] 可能变为 [2,5,6,0,0,1,2] )。 14 | * 编写一个函数来判断给定的目标值是否存在于数组中。若存在返回 true,否则返回 false。 15 | * 示例 1: 16 | * 输入: nums = [2,5,6,0,0,1,2], target = 0输出: true 17 | * 示例 2: 18 | * 输入: nums = [2,5,6,0,0,1,2], target = 3输出: false 19 | * @param nums 20 | * @param target 21 | * @return 22 | */ 23 | public boolean search(int[] nums, int target) { 24 | int length=nums.length; 25 | 26 | return false; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/singleton/EnumSingleton.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.singleton; 2 | 3 | /** 4 | 传统的两私有一公开(私有构造方法、私有静态实例(懒实例化/直接实例化)、公开的静态获取方法)涉及线程安全问题(即使有多重检查锁也可以通过反射破坏单例), 5 | 目前最为安全的实现单例的方法是通过内部静态enum的方法来实现,因为JVM会保证enum不能被反射并且构造器方法只执行一次。 6 | * Created by liuxun on 2017/7/13. 7 | */ 8 | public class EnumSingleton { 9 | private EnumSingleton(){} 10 | public static EnumSingleton getInstance(){ 11 | return Singleton.INSTANCE.getInstance(); 12 | } 13 | private static enum Singleton{ 14 | INSTANCE; 15 | private EnumSingleton singleton; 16 | //JVM会保证此方法绝对只调用一次 17 | private Singleton(){ 18 | singleton = new EnumSingleton(); 19 | } 20 | public EnumSingleton getInstance(){ 21 | return singleton; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/singleton/SingletonTest1.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.singleton; 2 | 3 | /** 4 | * 单例设计模式-饱汉模式 5 | * 优点是:写起来比较简单,当类SingletonTest被加载的时候,静态变量static的instance未被创建并分配内存空间,当getInstance方法第一次被调用时,初始化instance变量, 6 | * 并分配内存,因此在某些特定条件下会节约了内存;缺点是:并发环境下很可能出现多个SingletonTest实例。 7 | * Created by liuxun on 2017/7/13. 8 | */ 9 | public class SingletonTest1 { 10 | // 定义私有构造方法(防止通过 new SingletonTest1()去实例化) 11 | private SingletonTest1() { 12 | } 13 | // 定义一个SingletonTest类型的变量(不初始化,注意这里没有使用final关键字) 14 | private static SingletonTest1 instance; 15 | 16 | // 定义一个静态的方法(调用时再初始化SingletonTest,但是多线程访问时,可能造成重复初始化问题) 17 | public static SingletonTest1 getInstance(){ 18 | if (instance==null) { 19 | instance = new SingletonTest1(); 20 | } 21 | return instance; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/java8/hello3.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.java8; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileReader; 5 | import java.io.IOException; 6 | 7 | /** 8 | * lambda环绕执行模式 9 | 第1 步:记得行为参数化 10 | 第2 步:使用函数式接口来传递行为 11 | 第3 步:执行一个行为 12 | 第4 步:传递Lambda 13 | * Created by liuxun on 2017/7/11. 14 | */ 15 | public class hello3 { 16 | public static void main(String[] args) throws IOException { 17 | System.out.println(processFile((BufferedReader b)->b.readLine())); 18 | } 19 | public static String processFile(BufferedReaderProcessor buff) throws IOException { 20 | //使用了Java 7 中的带资源的try 语句,它已经简化了代码,因为你不需要显式地关闭资源了 21 | try (BufferedReader br = 22 | new BufferedReader(new FileReader("E:\\count.txt"))) { 23 | return buff.process(br); 24 | } 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### TortoiseGit template 3 | # Project-level settings 4 | /.tgitconfig 5 | ### Maven template 6 | target/ 7 | pom.xml.tag 8 | pom.xml.releaseBackup 9 | pom.xml.versionsBackup 10 | pom.xml.next 11 | release.properties 12 | dependency-reduced-pom.xml 13 | buildNumber.properties 14 | .mvn/timing.properties 15 | 16 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 17 | !/.mvn/wrapper/maven-wrapper.jar 18 | ### Java template 19 | # Compiled class file 20 | *.class 21 | 22 | # Log file 23 | *.log 24 | 25 | # BlueJ files 26 | *.ctxt 27 | 28 | # Mobile Tools for Java (J2ME) 29 | .mtj.tmp/ 30 | 31 | # Package Files # 32 | *.jar 33 | *.war 34 | *.nar 35 | *.ear 36 | *.zip 37 | *.tar.gz 38 | *.rar 39 | 40 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 41 | hs_err_pid* 42 | 43 | /.idea/ 44 | *.iml 45 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/TanxinSolution.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm; 2 | 3 | /** 4 | * 贪心算法 5 | * @Author: liuxun 6 | * @CreateDate: 2019/3/22 上午11:01 7 | * @Version: 1.0 8 | */ 9 | public class TanxinSolution { 10 | public static void main(String[] args) { 11 | TanxinSolution.greedyGiveMoney(10); 12 | } 13 | /** 14 | * 钱币找零问题 15 | *假设1元、2元、5元、10元、20元、50元、100元的纸币,张数不限制,现在要用来支付K元,至少要多少张纸币? 16 | * @param money the money 17 | */ 18 | public static void greedyGiveMoney(int money) { 19 | System.out.println("需要找零: " + money); 20 | int[] moneyLevel = {1, 5, 10, 20, 50, 100}; 21 | for (int i=moneyLevel.length-1;i>=0;i--){ 22 | int num=money/moneyLevel[i];//张数 23 | int mod=money%moneyLevel[i];//剩余的钱 24 | money=mod; 25 | if (num>0){ 26 | System.out.println("最少需要"+num+"张"+moneyLevel[i]+"元的纸币"); 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/java8/StreamDemo.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.java8; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Comparator; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | /** 9 | * 流 10 | * stream 串行执行 11 | *parallelStream 并行处理 12 | * Created by liuxun on 2017/7/12. 13 | */ 14 | public class StreamDemo { 15 | public static void main(String[] args) { 16 | List appleList=new ArrayList<>(); 17 | appleList.add(new Apple("red",110)); 18 | appleList.add(new Apple("green",120)); 19 | appleList.add(new Apple("blue",200)); 20 | List list2 = appleList.parallelStream() 21 | .filter((a) -> a.getWeight() > 110) //过滤 22 | .sorted(Comparator.comparing((Apple a)->a.getWeight()).reversed())//排序; 23 | .map((Apple a) -> a.getColor()) 24 | .collect(Collectors.toList()); 25 | list2.forEach((String s)-> System.out.println(s)); 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/MainTest1.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | 9 | /** 10 | * @author xun2.liu 11 | * @title: MainTest1 12 | * @projectName algorithm-study 13 | * @description: TODO 14 | * @date 2020/6/24 17:30 15 | */ 16 | public class MainTest1 { 17 | public static void main(String[] args) { 18 | List> lists=new ArrayList<>(); 19 | if((lists.size() & 1)==1){ 20 | LinkedList ls=new LinkedList<>(); 21 | //奇数层放到队列尾部 22 | ls.addLast(3); 23 | lists.add(ls); 24 | }else{ 25 | LinkedList ls=new LinkedList<>(); 26 | //偶数层放到队列头部 27 | ls.addFirst(9); 28 | ls.addFirst(2); 29 | lists.add(ls); 30 | } 31 | 32 | System.out.println(JSON.toJSONString(lists)); 33 | System.out.println((2 & 1)); 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/enums/Operator.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.enums; 2 | 3 | /** 4 | * @author xun2.liu 5 | * @title: Operator 6 | * @projectName algorithm-study 7 | * @description: TODO 8 | * @date 2019/12/13 16:31 9 | */ 10 | public enum Operator { 11 | 12 | ADD { 13 | @Override 14 | public int apply(int a, int b) { 15 | return a + b; 16 | } 17 | }, 18 | 19 | MULTIPLY { 20 | @Override 21 | public int apply(int a, int b) { 22 | return a * b; 23 | } 24 | }, 25 | 26 | SUBTRACT { 27 | @Override 28 | public int apply(int a, int b) { 29 | return a - b; 30 | } 31 | }, 32 | 33 | DIVIDE { 34 | @Override 35 | public int apply(int a, int b) { 36 | return a / b; 37 | } 38 | }, 39 | 40 | MODULO { 41 | @Override 42 | public int apply(int a, int b) { 43 | return a % b; 44 | } 45 | }; 46 | 47 | public abstract int apply(int a, int b); 48 | } -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/java8/Apple.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.java8; 2 | 3 | /** 4 | * Created by liuxun on 2017/7/10. 5 | */ 6 | public class Apple { 7 | private String color; 8 | private Integer weight; 9 | public Apple(){} 10 | public Apple(Integer weight){ 11 | this.weight=weight; 12 | 13 | } 14 | public Apple(String color,Integer weight){ 15 | this.color=color; 16 | this.weight=weight; 17 | 18 | } 19 | public String getColor() { 20 | return color; 21 | } 22 | 23 | public void setColor(String color) { 24 | this.color = color; 25 | } 26 | 27 | public Integer getWeight() { 28 | return weight; 29 | } 30 | 31 | public void setWeight(Integer weight) { 32 | this.weight = weight; 33 | } 34 | 35 | 36 | public static boolean isGreenApple(Apple apple) { 37 | return "green".equals(apple.getColor()); 38 | } 39 | public boolean isHeavyApple(Apple apple) { 40 | return apple.getWeight() > 150; 41 | } 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/thread/Profiler.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.thread; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | /** 6 | * ThreadLocal,即线程变量,是一个以ThreadLocal对象为键、任意对象为值的存储结构。这 7 | 个结构被附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个 8 | 线程上的一个值。 9 | * Created by liuxun on 2017/6/16. 10 | */ 11 | public class Profiler { 12 | // 第一次get()方法调用时会进行初始化(如果set方法没有调用),每个线程会调用一次 13 | private static final ThreadLocal TIME_THREADLOCAL = new ThreadLocal() { 14 | protected Long initialValue() { 15 | return System.currentTimeMillis(); 16 | } 17 | }; 18 | public static final void begin() { 19 | TIME_THREADLOCAL.set(System.currentTimeMillis()); 20 | } 21 | public static final long end() { 22 | return System.currentTimeMillis() - TIME_THREADLOCAL.get(); 23 | } 24 | public static void main(String[] args) throws Exception { 25 | Profiler.begin(); 26 | TimeUnit.SECONDS.sleep(1); 27 | System.out.println("Cost: " + Profiler.end() + " mills"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/reflect/Test.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.reflect; 2 | 3 | import java.lang.reflect.Proxy; 4 | import java.util.LinkedHashMap; 5 | 6 | /** 7 | * 动态代理实现 8 | *Spring 实现AOP是依赖JDK动态代理和CGLIB代理实现的。 9 | JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。 10 | CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强。 11 | 12 | 如果目标对象是接口类,适合使用JDK的方式生成代理对象,当没有接口时,将采用cglib中的方式实现proxy代理对象。 13 | * Created by liuxun on 2017/7/17. 14 | */ 15 | public class Test { 16 | public static void main(String[] args) { 17 | //基于JDK的动态代理 18 | Service service=new ServiceImpl(); 19 | ServiceHandler serviceHandler=new ServiceHandler(service); 20 | Service proxy = (Service)serviceHandler.createProxyIntance(); 21 | proxy.service("hello reflect"); 22 | 23 | //基于CGlib动态代理实现 24 | CGlibProxyFactory cglib=new CGlibProxyFactory(); 25 | CGlibServiceImpl object = (CGlibServiceImpl)cglib.getInstance(new CGlibServiceImpl()); 26 | object.excute(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution12.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | /** 4 | * 实现 strStr() 函数。 5 | * 6 | * 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回  -1。 7 | * 8 | * 示例 1: 9 | * 10 | * 输入: haystack = "hello", needle = "ll" 11 | * 输出: 2 12 | * 13 | * 来源:力扣(LeetCode) 14 | * 链接:https://leetcode-cn.com/problems/implement-strstr 15 | */ 16 | public class Solution12 { 17 | public static int strStr(String haystack, String needle) { 18 | int len=haystack.length(); 19 | int n=needle.length(); 20 | if (n>len){ 21 | return -1; 22 | } 23 | if (len==n && haystack.equals(needle)){ 24 | return 0; 25 | } 26 | for (int i=0;i list= Arrays.asList(new Apple("red",1),new Apple("green",133),new Apple("blue",166)); 15 | List list2=filterApple(list, new ApplePredicate() { 16 | @Override 17 | public boolean test(Apple apple) { 18 | return apple.getWeight()>133; 19 | } 20 | }); 21 | list2.forEach((Apple a)-> System.out.println(a.getColor())); 22 | 23 | } 24 | public static List filterApple(List list,ApplePredicate predicate){ 25 | List l=new ArrayList<>(); 26 | for (Apple a:list){ 27 | if (predicate.test(a)){ 28 | l.add(a); 29 | } 30 | } 31 | return l; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution11.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | /** 4 | * @author xun2.liu 5 | * @title: Solution11 6 | * @projectName algorithm-study 7 | * @description: 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。 8 | * 9 | * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 10 | * 11 | * 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素 12 | * 13 | * https://leetcode-cn.com/problems/remove-element 14 | * @date 2020/5/21 16:15 15 | */ 16 | public class Solution11 { 17 | public static int removeElement1(int[] nums, int val) { 18 | //双指针 19 | int i=0; 20 | int n=nums.length; 21 | while(i countCharset(String str) { 20 | 21 | if (null != str && str.length() > 0) { 22 | 23 | Map result = new HashMap<>(); 24 | 25 | char[] strChars = str.toCharArray(); 26 | 27 | Integer value = null; 28 | for (int i = 0; i < strChars.length; i++) { 29 | value = result.get(strChars[i]); 30 | 31 | if (value == null) { 32 | result.put(strChars[i], 1); 33 | } else { 34 | result.put(strChars[i], value + 1); 35 | } 36 | } 37 | 38 | return result; 39 | } 40 | return null; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution5.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | /** 4 | * @author xun2.liu 5 | * @title: Solution5 6 | * @projectName algorithm-study 7 | * @description: 反转一个单链表。 8 | * 示例: 9 | * 输入: 1->2->3->4->5->NULL 10 | * 输出: 5->4->3->2->1->NULL 11 | * @date 2020/5/14 20:07 12 | */ 13 | public class Solution5 { 14 | public static class ListNode { 15 | int val; 16 | ListNode next; 17 | ListNode(int x) { val = x; } 18 | } 19 | public static ListNode reverseList(ListNode head) { 20 | //使用两个指针 21 | ListNode curr=head; 22 | ListNode prev=null; 23 | while(curr!=null){ 24 | //临时指针。用来存储下一个节点。 25 | ListNode temp=curr.next; 26 | curr.next=prev; 27 | prev=curr; 28 | curr=temp; 29 | } 30 | return prev; 31 | } 32 | 33 | public static void main(String[] args) { 34 | ListNode a=new ListNode(5); 35 | ListNode b=new ListNode(4); 36 | ListNode c=new ListNode(3); 37 | a.next=b;b.next=c; 38 | ListNode result = reverseList(a); 39 | for (ListNode node=result;node!=null;node=node.next){ 40 | System.out.println(node.val); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/singleton/SingletonTest3.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode.singleton; 2 | 3 | /** 4 | * 单例模式最优方案 5 | * 线程安全 并且效率高 6 | * Created by liuxun on 2017/7/13. 7 | */ 8 | public class SingletonTest3 { 9 | 10 | // 定义私有构造方法(防止通过 new SingletonTest3()去实例化) 11 | private SingletonTest3(){} 12 | 13 | //定义一个静态私有变量(不初始化,不使用final关键字,使用volatile保证了多线程访问时instance变量的可见性,避免了instance初始化时其他变量属性还没赋值完时,被另外线程调用) 14 | private static volatile SingletonTest3 instance; 15 | //线程安全-双重检验锁 16 | public static SingletonTest3 getInstance(){ 17 | // 对象实例化时与否判断(不使用同步代码块,instance不等于null时,直接返回对象,提高运行效率) 18 | if (instance==null){ 19 | //同步代码块(对象未初始化时,使用同步代码块,保证多线程访问时对象在第一次创建后,不再重复被创建) 20 | synchronized (SingletonTest3.class) { 21 | //未初始化,则初始instance变量 22 | if (instance == null) { 23 | instance = new SingletonTest3(); 24 | //在这个操作中,JVM主要干了三件事 25 | //1、在堆空间里分配一部分空间; 26 | //2、执行SingletonTest3的构造方法进行初始化; 27 | //3、把instance对象指向在堆空间里分配好的空间。 28 | //但是,当我们编译的时候,编译器在生成汇编代码的时候会对流程顺序进行优化。优化的结果是有可能按照1-2-3顺序执行,也可能按照1-3-2顺序执行。 29 | } 30 | } 31 | } 32 | return instance; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/LRUCache/LRULinkedMap.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.LRUCache; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * LinkedHashMap实现LRU缓存 8 | * @Author: liuxun 9 | * @CreateDate: 2018/7/12 下午8:42 10 | * @Version: 1.0 11 | */ 12 | public class LRULinkedMap extends LinkedHashMap { 13 | /** 14 | * 最大缓存大小 15 | */ 16 | private int CACHESIZE; 17 | public LRULinkedMap(int cacheSize){ 18 | // true 表示让 linkedHashMap 按照访问顺序来进行排序,最近访问的放在头部,最老访问的放在尾部。 19 | super(cacheSize,0.75f,true); 20 | CACHESIZE=cacheSize; 21 | } 22 | 23 | /** 24 | * 删除元素条件 25 | * @param eldest 26 | * @return 27 | */ 28 | @Override 29 | protected boolean removeEldestEntry(Map.Entry eldest){ 30 | return size()>CACHESIZE; 31 | } 32 | public static void main(String[] args) { 33 | LRULinkedMap map = new LRULinkedMap(4) ; 34 | map.put("1",1); 35 | map.put("2",2); 36 | map.put("3",3); 37 | map.put("4",4); 38 | System.out.println(map.get("1")); 39 | map.put("5",5); 40 | for (Map.Entry e : map.entrySet()){ 41 | System.out.print(e.getKey() + " : " + e.getValue() + "\t"); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/concurrent/SemaphoreTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.concurrent; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.Semaphore; 6 | 7 | /** 8 | * 9 | Semaphore可以用于做流量控制,特别是公用资源有限的应用场景,比如数据库连接。假 10 | 如有一个需求,要读取几万个文件的数据,因为都是IO密集型任务,我们可以启动几十个线程 11 | 并发地读取,但是如果读到内存后,还需要存储到数据库中,而数据库的连接数只有10个,这 12 | 时我们必须控制只有10个线程同时获取数据库连接保存数据,否则会报错无法获取数据库连 13 | 接。这个时候,就可以使用Semaphore来做流量控制 14 | * Created by liuxun on 2017/6/28. 15 | */ 16 | public class SemaphoreTest { 17 | static ExecutorService executorService= Executors.newFixedThreadPool(10); 18 | static Semaphore semaphore=new Semaphore(2); 19 | 20 | public static void main(String[] args) { 21 | for (int i=0;i<10;i++){ 22 | executorService.execute(new Runnable() { 23 | public void run() { 24 | try { 25 | semaphore.acquire(); 26 | System.out.println("保存数据中"+Thread.currentThread()); 27 | semaphore.release(); 28 | } catch (InterruptedException e) { 29 | e.printStackTrace(); 30 | } 31 | } 32 | }); 33 | // executorService.shutdown(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/nio/FileChannelTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.nio; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.IOException; 5 | import java.io.RandomAccessFile; 6 | import java.nio.ByteBuffer; 7 | import java.nio.channels.FileChannel; 8 | 9 | /** 10 | * @author liuxun 11 | * @version V1.0 12 | * @Description: Filechannel 操作 13 | * @date 2017/12/5 14 | */ 15 | public class FileChannelTest { 16 | public static void main(String[] args) throws IOException { 17 | //向Filechannel写入数据 18 | RandomAccessFile aFile = new RandomAccessFile("E:\\nio-data.txt", "rw"); 19 | FileChannel channel = aFile.getChannel(); 20 | String newData = "New String to write to file..." + System.currentTimeMillis(); 21 | ByteBuffer buf = ByteBuffer.allocate(48); 22 | buf.clear(); 23 | buf.put(newData.getBytes()); 24 | buf.flip(); 25 | while(buf.hasRemaining()){ 26 | channel.write(buf); 27 | System.out.println(channel.position());//通过调用position()方法获取FileChannel的当前位置 28 | } 29 | System.out.println(channel.size());//FileChannel实例的size()方法将返回该实例所关联文件的大小 30 | channel.force(true);//FileChannel.force()方法将通道里尚未写入磁盘的数据强制写到磁盘上。出于性能方面的考虑,操作系统会将数据缓存在内存中,所以无法保证写入到FileChannel里的数据一定会即时写到磁盘上。要保证这一点,需要调用force()方法。 31 | channel.close(); 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution13.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | /** 4 | * 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 5 | * 6 | * 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 7 | * 8 | * 注意:给定 n 是一个正整数。 9 | * 10 | * 示例 1: 11 | * 12 | * 输入: 2 13 | * 输出: 2 14 | * 解释: 有两种方法可以爬到楼顶。 15 | * 1. 1 阶 + 1 阶 16 | * 2. 2 阶 17 | * 18 | * 来源:力扣(LeetCode) 19 | * 链接:https://leetcode-cn.com/problems/climbing-stairs 20 | */ 21 | public class Solution13 { 22 | /** 23 | * 不难发现,这个问题可以被分解为一些包含最优子结构的子问题,即它的最优解可以从其子问题的最优解来有效地构建,我们可以使用动态规划来解决这一问题。 24 | * 第 i阶可以由以下两种方法得到: 25 | * 在第 (i-1)阶后向上爬 1 阶。 26 | * 在第 (i-2)阶后向上爬 2 阶。 27 | * 所以到达第 i 阶的方法总数就是到第 (i-1)阶和第 (i-2)阶的方法数之和。 28 | * 令 dp[i] 表示能到达第 i 阶的方法总数: 29 | * dp[i]=dp[i-1]+dp[i-2] 30 | * @param n 31 | * @return 32 | */ 33 | public static int climbStairs(int n) { 34 | if (n<=0){ 35 | return 0; 36 | } 37 | if (n==1){ 38 | return 1; 39 | } 40 | if (n==2){ 41 | return 2; 42 | } 43 | int[] dp=new int[n+1]; 44 | dp[1]=1; 45 | dp[2]=2; 46 | for (int i = 3; i <=n; i++) { 47 | dp[i]=dp[i-1]+dp[i-2]; 48 | } 49 | return dp[n]; 50 | } 51 | 52 | public static void main(String[] args) { 53 | System.out.println(climbStairs(1)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution22.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | /** 4 | * @author xun2.liu 5 | * @title: Solution22 6 | * @projectName algorithm-study 7 | * @description: 字符串压缩。利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。 8 | * 比如,字符串aabcccccaaa会变为a2b1c5a3。若“压缩”后的字符串没有变短,则返回原先的字符串。 9 | * 你可以假设字符串中只包含大小写英文字母(a至z)。 10 | * 示例1: 11 | * 12 | * 输入:"aabcccccaaa" 13 | * 输出:"a2b1c5a3" 14 | * 15 | * 来源:力扣(LeetCode) 16 | * 链接:https://leetcode-cn.com/problems/compress-string-lcci 17 | * @date 2020/6/3 20:07 18 | */ 19 | public class Solution22 { 20 | public static String compressString(String S) { 21 | //慢指针 22 | int i=0; 23 | int len=S.length(); 24 | //压缩后的字符串 25 | StringBuilder sb=new StringBuilder(); 26 | while(i map= new HashMap<>(); 28 | for(int i=0;i 7 | * 规律:首先选取数组中右上角的数字。如果该数字等于要查找的数字,查找过程结束: 8 | * 如果该数字大于要查找的数字,剔除这个数字所在的列:如果该数字小于要查找的数字,剔除这个数字所在的行。 9 | * 也就是说如果要查找的数字不在数组的右上角,则每-次都在数组的查找范围中剔除)行或者一列,这样每一步都可以缩小 10 | **/ 11 | 12 | public class Jianzhi01 { 13 | 14 | public static boolean find(int[][] matrix, int number) { 15 | 16 | if (matrix==null || matrix.length<1 || matrix[0].length<1){ 17 | return false; 18 | } 19 | 20 | int rows=matrix.length;//数组的行数 21 | int cols=matrix[0].length;//数组的列数 22 | 23 | int row=0;//从第1行开始读取 24 | int col=cols-1;//从第1列开始 25 | 26 | while (row>=0 && row=0){ 27 | if (matrix[row][col]==number){ 28 | return true; 29 | }else if(matrix[row][col]>number){ 30 | col--;//从右往左边开始读取 31 | }else{ 32 | row++;//读取下一行 33 | } 34 | } 35 | return false; 36 | 37 | 38 | } 39 | public static void main(String[] args) { 40 | int[][] matrix = { 41 | {1, 2, 8, 9}, 42 | {2, 4, 9, 12}, 43 | {4, 7, 10, 13}, 44 | {6, 8, 11, 15} 45 | }; 46 | System.out.println(find(matrix, 15)); // 要查找的数在数组中 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /MD/Reference.md: -------------------------------------------------------------------------------- 1 |
在Java语言中,除了基本数据类型外,其他的都是指向各类对象的对象引用;Java中根据其生命周期的长短,将引用分为4类。

1 强引用

特点:我们平常典型编码Object obj = new Object()中的obj就是强引用。通过关键字new创建的对象所关联的引用就是强引用。 当JVM内存空间不足,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),使程序异常终止,也不会靠随意回收具有强引用的“存活”对象来解决内存不足的问题。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,具体回收时机还是要看垃圾收集策略。

2 软引用

特点:软引用通过SoftReference类实现。 软引用的生命周期比强引用短一些。只有当 JVM 认为内存不足时,才会去试图回收软引用指向的对象:即JVM 会确保在抛出 OutOfMemoryError 之前,清理软引用指向的对象。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。后续,我们可以调用ReferenceQueue的poll()方法来检查是否有它所关心的对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。

应用场景:软引用通常用来实现内存敏感的缓存。如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存。

3 弱引用

弱引用通过WeakReference类实现。 弱引用的生命周期比软引用短。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。由于垃圾回收器是一个优先级很低的线程,因此不一定会很快回收弱引用的对象。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

应用场景:弱应用同样可用于内存敏感的缓存。

4 虚引用

特点:虚引用也叫幻象引用,通过PhantomReference类来实现。无法通过虚引用访问对象的任何属性或函数。幻象引用仅仅是提供了一种确保对象被 finalize 以后,做某些事情的机制。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue);
程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取一些程序行动。

应用场景:可用来跟踪对象被垃圾回收器回收的活动,当一个虚引用关联的对象被垃圾收集器回收之前会收到一条系统通知。
-------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution26.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | /** 6 | * @author xun2.liu 7 | * @title: Solution26 8 | * @projectName algorithm-study 9 | * @description: 删除链表中的元素 10 | * @date 2020/6/17 13:40 11 | */ 12 | public class Solution26 { 13 | public static class ListNode { 14 | int val; 15 | ListNode next; 16 | ListNode(int x) { val = x; } 17 | } 18 | public static ListNode delNode(ListNode head,int val){ 19 | //首先删除头结点等于val的节点 20 | while (head!=null && head.val==val){ 21 | head=head.next; 22 | } 23 | if (head==null){ 24 | return head; 25 | } 26 | //删除头结点后边等于val的节点 27 | ListNode temp=head; 28 | while (temp.next!=null){ 29 | if (temp.next.val==val){ 30 | temp.next=temp.next.next; 31 | }else{ 32 | temp=temp.next; 33 | } 34 | } 35 | return temp; 36 | } 37 | public static void main(String[] args) { 38 | ListNode a=new ListNode(0); 39 | ListNode b=new ListNode(1); 40 | ListNode c=new ListNode(2); 41 | a.next=b;b.next=c; 42 | ListNode temp=a; 43 | while (temp!=null){ 44 | delNode(temp, 2); 45 | temp=temp.next; 46 | } 47 | System.out.println(JSON.toJSONString(a)); 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/concurrent/JoinCountDownLatchTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.concurrent; 2 | 3 | import java.util.concurrent.*; 4 | 5 | /** 6 | * CountDownLatch允许一个或多个线程等待其他线程完成操作。 7 | * CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果你想等待N个点完成,这里就传入N。 8 | * 当我们调用CountDownLatch的countDown方法时,N就会减1,CountDownLatch的await 9 | * 会阻塞当前线程,直到N变成零。由于countDown方法可以用在任何地方,所以这里说 10 | * 点,可以是N个线程,也可以是1个线程里的N个执行步骤。用在多个线程时,只需要把 11 | * CountDownLatch的引用传递到线程里即可。 12 | * Created by liuxun on 2017/6/27. 13 | */ 14 | public class JoinCountDownLatchTest { 15 | static CountDownLatch c=new CountDownLatch(2); 16 | static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2); 17 | public static void main(String[] args) throws InterruptedException { 18 | fixedThreadPool.execute(new Runnable() { 19 | @Override 20 | public void run() { 21 | try { 22 | TimeUnit.SECONDS.sleep(2); 23 | } catch (InterruptedException e) { 24 | e.printStackTrace(); 25 | } 26 | System.out.println("1"); 27 | c.countDown(); 28 | } 29 | }); 30 | fixedThreadPool.execute(new Runnable() { 31 | @Override 32 | public void run() { 33 | System.out.println("2"); 34 | c.countDown(); 35 | } 36 | }); 37 | c.await(); 38 | System.out.println(3); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/guava/MainTest.java: -------------------------------------------------------------------------------- 1 | //package com.algorithm.study.demo.guava; 2 | // 3 | //import com.github.rholder.retry.*; 4 | //import com.google.common.base.Predicates; 5 | // 6 | //import java.io.*; 7 | //import java.text.SimpleDateFormat; 8 | //import java.time.LocalDateTime; 9 | //import java.time.format.DateTimeFormatter; 10 | //import java.util.concurrent.ExecutionException; 11 | //import java.util.concurrent.TimeUnit; 12 | // 13 | ///** 14 | // * guava 重试机制 15 | // * @Author: liuxun 16 | // * @CreateDate: 2019/1/2 上午11:29 17 | // * @Version: 1.0 18 | // */ 19 | //public class MainTest { 20 | // public static void main(String[] args) { 21 | // //定义重试机制 22 | // Retryer retryer = RetryerBuilder.newBuilder() 23 | // .retryIfException() //设置异常重试 24 | // .retryIfResult(Predicates.equalTo(true)) //call方法返回true重试 25 | // .withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS)) //设置10秒后重试 26 | // .withStopStrategy(StopStrategies.stopAfterAttempt(3)).build(); //设置重试次数 超过将出异常 27 | // try { 28 | // retryer.call(() -> { 29 | // //这里写你的业务逻辑代码 30 | // System.out.println("11111111111111111122222"); 31 | // return true; //需要重试返回true 32 | // }); 33 | // } catch (ExecutionException e) { 34 | // e.printStackTrace(); 35 | // } catch (RetryException e) { 36 | // e.printStackTrace(); 37 | // } 38 | // } 39 | //} 40 | // 41 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution15.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | /** 4 | * @author xun2.liu 5 | * @title: Solution15 6 | * @projectName algorithm-study 7 | * @description: 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 8 | * 你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。 9 | * * 10 | * * 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。 11 | * * 12 | * * 示例 1: 13 | * * s = "abc", t = "ahbgdc" 14 | * * 15 | * * 返回 true. 16 | * * 17 | * * 示例 2: 18 | * * s = "axc", t = "ahbgdc" 19 | * * 20 | * * 返回 false. 21 | * * 22 | * * 来源:力扣(LeetCode) 23 | * * 链接:https://leetcode-cn.com/problems/is-subsequence 24 | * @date 2020/5/27 19:58 25 | */ 26 | public class Solution15 { 27 | /** 28 | * 使用双指针i、n,如果s.charAt(i)等于t.charAt(n)的话,i、n指针都往前走。最后判断相等的次数是否等于s字符串的长度。 29 | * @param s 30 | * @param t 31 | * @return 32 | */ 33 | public static boolean isSubsequence(String s, String t) { 34 | int i=0; 35 | int n=0; 36 | while(i=tStart && t<=tEnd; 32 | } 33 | 34 | private static long getLong(String timeStr) throws ParseException { 35 | DateFormat dateFormat = new SimpleDateFormat(formatStr); 36 | return dateFormat.parse(timeStr).getTime(); 37 | } 38 | 39 | private static long getCurrentTime() throws ParseException { 40 | DateFormat dateFormat = new SimpleDateFormat(formatStr); 41 | return getLong(dateFormat.format(new Date())); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution24.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | /** 4 | * @author xun2.liu 5 | * @title: Solution24 6 | * @projectName algorithm-study 7 | * @description: 给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 8 | * 9 | * 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。 10 | 11 | * 示例 1: 12 | * 13 | * 给定数组 nums = [1,1,2], 14 | * 15 | * 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 16 | * 17 | * 你不需要考虑数组中超出新长度后面的元素。 18 | * 19 | * 来源:力扣(LeetCode) 20 | * 链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array 21 | * @date 2020/6/10 11:33 22 | */ 23 | public class Solution24 { 24 | /** 25 | * 解法: 双指针 26 | * 首先注意数组是有序的,那么重复的元素一定会相邻。 27 | * 要求删除重复元素,实际上就是将不重复的元素移到数组的左侧。 28 | * 考虑用 2 个指针,一个在前记作 p1,一个在后记作 p2,算法流程如下: 29 | * 比较 p1 和 p2 位置的元素是否相等。 30 | * 如果相等,p2 后移 1 位 31 | * 如果不相等,将 p2 位置的元素复制到 p1+1 位置上,p1 后移一位,p2 后移 1 位 32 | * 重复上述过程,直到 p2 等于数组长度。 33 | * 返回 p1 + 1,即为新数组长度。 34 | * @param nums 35 | * @return 36 | */ 37 | public static int removeDuplicates(int[] nums) { 38 | int p1=0; 39 | int p2=0; 40 | while(p2 { 10 | // 定义一个内部类Node,代表链表的节点 11 | private class Node { 12 | private T data;// 保存数据 13 | private Node next;// 指向下个节点的引用 14 | // 无参构造器 15 | public Node() { 16 | } 17 | // 初始化全部属性的构造器 18 | public Node(T data, Node next) { 19 | this.data = data; 20 | this.next = next; 21 | } 22 | } 23 | //栈顶元素 24 | private Node top; 25 | //元素个数 26 | private int size; 27 | 28 | public LinkStack(){ 29 | this.top=null;//初始化一个空的栈 30 | } 31 | 32 | /** 33 | * 入栈,在栈顶的位置插入元素 34 | * @param element 35 | */ 36 | public void push(T element){ 37 | top=new Node(element,top); 38 | size++; 39 | } 40 | 41 | /** 42 | * 出栈 43 | * @return 44 | */ 45 | public T pop(){ 46 | if (top==null){ 47 | return null; 48 | } 49 | Node temp=top; 50 | top=temp.next; 51 | temp.next=null;//释放应用 52 | size--; 53 | return temp.data;//返回栈顶元素 54 | } 55 | //返回栈顶的元素,但不出栈 56 | public T peek(){ 57 | return top.data; 58 | 59 | } 60 | // 判断链栈是否为空栈 61 | public boolean empty() { 62 | return size == 0; 63 | } 64 | //堆栈长度 65 | public int length(){ 66 | return size; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/atomic/AtomicReferenceTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.atomic; 2 | 3 | import java.util.concurrent.atomic.AtomicReference; 4 | 5 | /** 6 | * 当对一个共享变量执行操作时,我们可以使用循 7 | 环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子 8 | 性,这个时候就可以用锁。还有一个取巧的办法,就是把多个共享变量合并成一个共享变量来 9 | 操作。比如,有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java 1.5开始, 10 | JDK提供了AtomicReference类来保证引用对象之间的原子性,就可以把多个变量放在一个对 11 | 象里来进行CAS操作。 12 | * Created by liuxun on 2017/6/13. 13 | */ 14 | public class AtomicReferenceTest { 15 | public static AtomicReference atomicUserRef = new AtomicReference(); 16 | public static void main(String[] args) { 17 | User user = new User("conan", 15); 18 | atomicUserRef.set(user); 19 | User updateUser = new User("Shinichi", 17); 20 | atomicUserRef.compareAndSet(atomicUserRef.get(), updateUser); 21 | System.out.println(atomicUserRef.get().getName()); 22 | System.out.println(atomicUserRef.get().getOld()); 23 | } 24 | 25 | static class User { 26 | 27 | private String name; 28 | private int old; 29 | 30 | public User(String name, int old) { 31 | this.name = name; 32 | this.old = old; 33 | } 34 | 35 | public String getName() { 36 | return name; 37 | } 38 | 39 | public void setName(String name) { 40 | this.name = name; 41 | } 42 | 43 | public int getOld() { 44 | return old; 45 | } 46 | 47 | public void setOld(int old) { 48 | this.old = old; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution10.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @author xun2.liu 10 | * @title: Solution10 11 | * @projectName algorithm-study 12 | * @description: 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。 13 | * 14 | * 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。 15 | * 16 | * 示例 1: 17 | * 18 | * 输入: "abc" 19 | * 输出: 3 20 | * 解释: 三个回文子串: "a", "b", "c". 21 | * 示例 2: 22 | * 23 | * 输入: "aaa" 24 | * 输出: 6 25 | * 说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa". 26 | * 27 | * 来源:力扣(LeetCode) 28 | * 链接:https://leetcode-cn.com/problems/palindromic-substrings 29 | * @date 2020/5/21 15:34 30 | */ 31 | public class Solution10 { 32 | //通过中心扩散法查找回文字符串 33 | public static void huiwen(String s,int l,int r,List filter){ 34 | while(l>=0 && r filter=new ArrayList(); 48 | for(int i=0;i conMap = StrProc.countCharset(src); 26 | 27 | System.out.println("字符频率统计:"+conMap); 28 | 29 | HuffmanCode instance = new HuffmanCode(); 30 | Map huffCode = instance.getHuffManCode(conMap); 31 | System.out.println("huffcode字符编码映射:"+huffCode); 32 | 33 | String hufOutValue = instance.parseHuffman2(src, huffCode); 34 | System.out.println("最终编码:"+hufOutValue); 35 | 36 | String deValue = instance.decodeHuffman(hufOutValue, instance.root); 37 | System.out.println("解压结果:" + deValue); 38 | 39 | System.out.println("--------------------------------------------------------------------------------"); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/thread/DeadlockTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.thread; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | /** 6 | * 死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去 7 | * 避免死锁:一种是加锁顺序(线程按照一定的顺序加锁);另一种是加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁); 8 | */ 9 | public class DeadlockTest { 10 | private static Object o1=new Object(); 11 | private static Object o2=new Object(); 12 | public static void main(String[] args) { 13 | new Thread(()->{ 14 | synchronized (o1){ 15 | System.out.println("Thread1 get lock o1"); 16 | try { 17 | TimeUnit.SECONDS.sleep(1); 18 | } catch (InterruptedException e) { 19 | e.printStackTrace(); 20 | } 21 | synchronized (o2){ 22 | System.out.println("Thread1 get lock o2"); 23 | } 24 | System.out.println("Thread1 end"); 25 | } 26 | }).start(); 27 | 28 | new Thread(() -> { 29 | synchronized (o2){ 30 | System.out.println("Thread2 get lock o1"); 31 | try { 32 | TimeUnit.SECONDS.sleep(1); 33 | } catch (InterruptedException e) { 34 | e.printStackTrace(); 35 | } 36 | synchronized (o1){ 37 | System.out.println("Thread2 get lock o2"); 38 | } 39 | System.out.println("Thread2 end"); 40 | } 41 | }).start(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/util/Paging.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.util; 2 | 3 | import java.io.Serializable; 4 | 5 | /*** 6 | * 分页工具类 7 | */ 8 | public class Paging implements Serializable { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | private static final int PAGE_SIZE = 10; 13 | 14 | private int total = 0; 15 | 16 | private int page = 1; 17 | 18 | private int pageSize = PAGE_SIZE; 19 | 20 | private int pages = 0; 21 | 22 | public Paging() { 23 | this(1, PAGE_SIZE); 24 | } 25 | 26 | public Paging(int page, int pageSize) { 27 | this.page = page; 28 | this.pageSize = pageSize; 29 | } 30 | 31 | private void calculatePages() { 32 | total = total > 0 ? total : 0; 33 | pageSize = pageSize > 0 ? pageSize : PAGE_SIZE; 34 | pages = total / pageSize + (total % pageSize == 0 ? 0 : 1); 35 | page = pages >= 1 ? Math.min(Math.max(page, 1), pages) : 1; 36 | } 37 | 38 | public int getTotal() { 39 | return total; 40 | } 41 | 42 | public void setTotal(int total) { 43 | this.total = total; 44 | calculatePages(); 45 | } 46 | 47 | public int getPage() { 48 | return page; 49 | } 50 | 51 | public void setPage(int page) { 52 | this.page = page; 53 | } 54 | 55 | public int getPageSize() { 56 | return pageSize; 57 | } 58 | 59 | public void setPageSize(int pageSize) { 60 | this.pageSize = pageSize; 61 | } 62 | 63 | public int getPages() { 64 | return pages; 65 | } 66 | 67 | public void setPages(int pages) { 68 | this.pages = pages; 69 | } 70 | 71 | public int getStart() { 72 | return Math.max((page - 1) * pageSize, 0); 73 | } 74 | 75 | public static void main(String[] args) { 76 | 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution9.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | /** 6 | * @author xun2.liu 7 | * @title: Solution9 8 | * @projectName algorithm-study 9 | * @description: 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 10 | * 11 | * 示例 1: 12 | * 13 | * 输入: "babad" 14 | * 输出: "bab" 15 | * 注意: "aba" 也是一个有效答案。 16 | * 示例 2: 17 | * 18 | * 输入: "cbbd" 19 | * 输出: "bb" 20 | * 21 | * 来源:力扣(LeetCode) 22 | * 链接:https://leetcode-cn.com/problems/longest-palindromic-substring 23 | * @date 2020/5/21 13:46 24 | */ 25 | public class Solution9 { 26 | /** 27 | * 通过中心点向两边扩散。 28 | * @param s 29 | * @param r 30 | * @param l 31 | * @return 32 | */ 33 | public static String palindrome(String s,int l,int r){ 34 | while (l>=0 && r=p1.length()?res:p1; 51 | res=res.length()>=p2.length()?res:p2; 52 | } 53 | return res; 54 | } 55 | public static void main(String[] args) { 56 | System.out.println(longestPalindrome("babad")); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution14.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | /** 4 | * 将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。  5 | * 6 | * 示例: 7 | * 8 | * 输入:1->2->4, 1->3->4 9 | * 输出:1->1->2->3->4->4 10 | * 11 | * 来源:力扣(LeetCode) 12 | * 链接:https://leetcode-cn.com/problems/merge-two-sorted-lists 13 | */ 14 | public class Solution14 { 15 | public static class ListNode { 16 | int val; 17 | ListNode next; 18 | ListNode(int x) { val = x; } 19 | } 20 | public static ListNode mergeTwoLists(ListNode l1, ListNode l2) { 21 | //需要返回排序好的节点 22 | ListNode result=new ListNode(-1); 23 | //哨兵节点 24 | ListNode prev=result; 25 | //首先遍历两个链表比较大小如果l1比l2小。l1往前走否则l2往前走。并且把值小的节点赋值给prev.next。 26 | while(l1!=null && l2!=null){ 27 | if(l1.val> temp=new ArrayList<>(); 19 | int value=0; 20 | int remainder=0; 21 | boolean flag=false; 22 | while (!flag){ 23 | value=a / b; 24 | remainder= a%b; 25 | for (int i=0;i integerIntegerMap = temp.get(i); 27 | //如果相除得到的整数答案和余数在之前出现过,那么就会开始循环。也就是循环节点 28 | if (integerIntegerMap.containsKey(value) && integerIntegerMap.containsValue(remainder)){ 29 | flag=true; 30 | break; 31 | } 32 | } 33 | HashMap map = new HashMap<>(); 34 | map.put(value,remainder); 35 | temp.add(map); 36 | a=remainder*10; 37 | } 38 | StringBuilder sb=new StringBuilder(); 39 | for (int i=1;i integerIntegerMap = temp.get(i); 41 | integerIntegerMap.forEach((k,v)->{ 42 | sb.append(k); 43 | }); 44 | 45 | } 46 | return sb.toString(); 47 | } 48 | 49 | public static void main(String[] args) { 50 | System.out.println(function(3,7)); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution25.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | //编写一个函数来查找字符串数组中的最长公共前缀。 3 | // 4 | // 如果不存在公共前缀,返回空字符串 ""。 5 | // 6 | // 示例 1: 7 | // 8 | // 输入: ["flower","flow","flight"] 9 | //输出: "fl" 10 | // 11 | // 12 | // 示例 2: 13 | // 14 | // 输入: ["dog","racecar","car"] 15 | //输出: "" 16 | //解释: 输入不存在公共前缀。 17 | // 18 | // 19 | // 说明: 20 | // 21 | // 所有输入只包含小写字母 a-z 。 22 | // Related Topics 字符串 23 | 24 | 25 | //leetcode submit region begin(Prohibit modification and deletion) 26 | public class Solution25 { 27 | public String longestCommonPrefix(String[] strs) { 28 | if (strs.length==0){ 29 | return ""; 30 | } 31 | //令最长公共前缀 ans 的值为第一个字符串,进行初始化 32 | String commonStr=strs[0]; 33 | for (int i = 1; i < strs.length; i++) { 34 | //进行匹配的字符串 35 | String str = strs[i]; 36 | //公共前缀的下标 37 | int j=0; 38 | for (;j { 8 | // 定义一个内部类Node,代表链表的节点 9 | private class Node { 10 | private E data;// 保存数据 11 | private Node next;// 指向下个节点的引用 12 | 13 | // 无参构造器 14 | public Node() { 15 | } 16 | // 初始化全部属性的构造器 17 | public Node(E data, Node next) { 18 | this.data = data; 19 | this.next = next; 20 | } 21 | } 22 | private Node head;//头结点 23 | private Node last;//尾结点 24 | private int size; 25 | //设置初始化长度 26 | private final int capacity; 27 | //默认长度 28 | public LinkQueue(){ 29 | this(Integer.MAX_VALUE); 30 | } 31 | public LinkQueue(int capacity){ 32 | this.capacity=capacity; 33 | head=last=null; 34 | } 35 | public int size(){ 36 | return size; 37 | } 38 | public void add(E element){ 39 | if (size==capacity){ 40 | throw new RuntimeException("队列已满,size:"+size()); 41 | } 42 | Node node=new Node(element,null); 43 | if (head==null){ 44 | last=head=node; 45 | }else{ 46 | last=last.next=node;//尾部的下一个指针尾node,并设置新的尾部 47 | } 48 | size++; 49 | } 50 | public Object poll(){ 51 | if (head==null){ 52 | return null; 53 | } 54 | Node node=head; 55 | head=node.next; 56 | if (last==node){//如果首尾相等话的释放尾 57 | last=head; 58 | } 59 | node.next=null; 60 | size--; 61 | return node.data; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/reflect/ServiceHandler.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.reflect; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Proxy; 6 | 7 | /** 8 | * 动态代理解决方案 9 | 在JDK 1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例。在Sun刚推出动态代理时,还很难想象它有多大的实际用途, 10 | 现在我们终于发现动态代理是实现AOP的绝好底层技术。JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。 11 | 其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。 12 | 而Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例。 13 | * Created by liuxun on 2017/7/17. 14 | */ 15 | public class ServiceHandler implements InvocationHandler { 16 | private Object target ; 17 | 18 | public ServiceHandler(Object target){ 19 | this.target = target; 20 | } 21 | 22 | /** 23 | * Proxy负责生成一个代理的实例 24 | * 这个实例在调用service方法的时候,改成了调用serviceHandler的invoke方法,从而把begin和end的动作插入。 25 | * @return 26 | */ 27 | public Object createProxyIntance(){ 28 | //这里调用JDK生成Proxy的地方,三个参数,类装载器,代理接口,proxy回调方法所在的对象 29 | return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this); 30 | } 31 | 32 | /** 33 | * 回调方法 34 | 1、需要实现InvocationHandler 35 | 2、在invoke方法里面,实现动态代理, method是要被调用的方法 36 | * @param proxy 代理对象 37 | * @param method 调用的方法 38 | * @param args 调用的方法参数 39 | * @return 40 | * @throws Throwable 41 | */ 42 | @Override 43 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 44 | PerformanceMonitor.begin(); 45 | Object obj = method.invoke(target,args); 46 | PerformanceMonitor.end(); 47 | return obj; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /MD/String.MD: -------------------------------------------------------------------------------- 1 | **String/StringBuffer/StringBuilder区别** 2 | 3 | 1 String 4 | 5 | 6 | 7 | (1) String的创建机理 8 | 9 | 由于String在Java世界中使用过于频繁,Java为了避免在一个系统中产生大量的String对象,引入了字符串常量池。其运行机制是:创建一个字符串时,首先检查池中是否有值相同的字符串对象,如果有则不需要创建直接从池中刚查找到的对象引用;如果没有则新建字符串对象,返回对象引用,并且将新创建的对象放入池中。但是,通过new方法创建的String对象是不检查字符串池的,而是直接在堆区或栈区创建一个新的对象,也不会把对象放入池中。上述原则只适用于通过直接量给String对象引用赋值的情况。 10 | 11 | 举例:String str1 = "123"; //通过直接量赋值方式,放入字符串常量池 12 | String str2 = new String(“123”);//通过new方式赋值方式,不放入字符串常量池 13 | 14 | 注意:String提供了intern()方法。调用该方法时,如果常量池中包括了一个等于此String对象的字符串(由equals方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并且返回此池中对象的引用。 15 | 16 | 17 | (2) String的特性 18 | [A] 不可变。是指String对象一旦生成,则不能再对它进行改变。不可变的主要作用在于当一个对象需要被多线程共享,并且访问频繁时,可以省略同步和锁等待的时间,从而大幅度提高系统性能。不可变模式是一个可以提高多线程程序的性能,降低多线程程序复杂度的设计模式。 19 | 20 | [B] 针对常量池的优化。当2个String对象拥有相同的值时,他们只引用常量池中的同一个拷贝。当同一个字符串反复出现时,这个技术可以大幅度节省内存空间。 21 | 22 | 23 | 2 StringBuffer/StringBuilder 24 | 25 | 26 | StringBuffer和StringBuilder都实现了AbstractStringBuilder抽象类,拥有几乎一致对外提供的调用接口;其底层在内存中的存储方式与String相同,都是以一个有序的字符序列(char类型的数组)进行存储,不同点是StringBuffer/StringBuilder对象的值是可以改变的,并且值改变以后,对象引用不会发生改变;两者对象在构造过程中,首先按照默认大小申请一个字符数组,由于会不断加入新数据,当超过默认大小后,会创建一个更大的数组,并将原先的数组内容复制过来,再丢弃旧的数组。因此,对于较大对象的扩容会涉及大量的内存复制操作,如果能够预先评估大小,可提升性能。 27 | 28 | 唯一需要注意的是:StringBuffer是线程安全的,但是StringBuilder是线程不安全的。可参看Java标准类库的源代码,StringBuffer类中方法定义前面都会有synchronize关键字。为此,StringBuffer的性能要远低于StringBuilder。 29 | 30 | 31 | 32 | 3 应用场景 33 | 34 | 35 | [A]在字符串内容不经常发生变化的业务场景优先使用String类。例如:常量声明、少量的字符串拼接操作等。如果有大量的字符串内容拼接,避免使用String与String之间的“+”操作,因为这样会产生大量无用的中间对象,耗费空间且执行效率低下(新建对象、回收对象花费大量时间)。 36 | 37 | [B]在频繁进行字符串的运算(如拼接、替换、删除等),并且运行在多线程环境下,建议使用StringBuffer,例如XML解析、HTTP参数解析与封装。 38 | 39 | [C]在频繁进行字符串的运算(如拼接、替换、删除等),并且运行在单线程环境下,建议使用StringBuilder,例如SQL语句拼装、JSON封装等。 -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/atomic/AtomicIntegerFieldUpdaterTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.atomic; 2 | 3 | import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; 4 | 5 | /** 6 | * 如果我们只需要某个类里的某个字段,那么就需要使用原子更新字段类,Atomic包提供了以下三个类: 7 | AtomicIntegerFieldUpdater:原子更新整型的字段的更新器。 8 | AtomicLongFieldUpdater:原子更新长整型字段的更新器。 9 | AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于原子的更数据和数据的版本号,可以解决使用CAS进行原子更新时,可能出现的ABA问题。 10 | 原子更新字段类都是抽象类,每次使用都时候必须使用静态方法newUpdater创建一个更新器。原子更新类的字段的必须使用public volatile修饰符。 11 | * Created by liuxun on 2017/6/13. 12 | */ 13 | public class AtomicIntegerFieldUpdaterTest { 14 | public static AtomicIntegerFieldUpdater atomicUserRef =AtomicIntegerFieldUpdater.newUpdater(User.class, "old"); 15 | 16 | public static void main(String[] args) { 17 | User user = new User("conan", 15); 18 | atomicUserRef.set(user,15); 19 | atomicUserRef.compareAndSet(user,user.getOld(),17); 20 | System.out.println(atomicUserRef.get(user)); 21 | System.out.println(atomicUserRef.getAndIncrement(user)); 22 | System.out.println(atomicUserRef.get(user)); 23 | } 24 | 25 | static class User { 26 | 27 | private String name; 28 | public volatile int old; 29 | 30 | public User(String name, int old) { 31 | this.name = name; 32 | this.old = old; 33 | } 34 | 35 | public String getName() { 36 | return name; 37 | } 38 | 39 | public void setName(String name) { 40 | this.name = name; 41 | } 42 | 43 | public int getOld() { 44 | return old; 45 | } 46 | 47 | public void setOld(int old) { 48 | this.old = old; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution16.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | /** 4 | * 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。 5 | * 6 | * 说明:本题中,我们将空字符串定义为有效的回文串。 7 | * 8 | * 示例 1: 9 | * 10 | * 输入: "A man, a plan, a canal: Panama" 11 | * 输出: true 12 | * 示例 2: 13 | * 14 | * 输入: "race a car" 15 | * 输出: false 16 | * 17 | * 来源:力扣(LeetCode) 18 | * 链接:https://leetcode-cn.com/problems/valid-palindrome 19 | */ 20 | public class Solution16 { 21 | /** 22 | * 使用双指针对比字符相等 23 | * @param s 24 | * @param l 25 | * @param r 26 | * @return 27 | */ 28 | public static boolean palindrome(String s,int l,int r){ 29 | String news=s.toLowerCase(); 30 | while(l stack = new Stack(); 46 | Node p = root; 47 | while (p != null) { 48 | stack.push(p); 49 | p = p.next; 50 | } 51 | p = root; 52 | while (p != null) { 53 | if (p.value != stack.pop().value) 54 | return false; 55 | p = p.next; 56 | } 57 | return true; 58 | } 59 | public static void main(String[] args) { 60 | Linked_6 linked=new Linked_6(); 61 | linked.put("a"); 62 | linked.put("b"); 63 | linked.put("c"); 64 | System.out.println("是否是回文字符串"+linked.isPalindrome()); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/thread/CountTask.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.thread; 2 | 3 | import java.util.concurrent.*; 4 | 5 | /** 6 | * Fork/Join框架是Java 7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。 7 | *步骤1 分割任务。首先我们需要有一个fork类来把大任务分割成子任务,有可能子任务还是很大,所以还需要不停地分割,直到分割出的子任务足够小。 8 | 步骤2 执行任务并合并结果。分割的子任务分别放在双端队列里,然后几个启动线程分别从双端队列里获取任务执行。子任务执行完的结果都统一放在一个队列里,启动一个线程从队列里拿数据,然后合并这些数据。 9 | 10 | * Created by liuxun on 2017/6/27. 11 | */ 12 | public class CountTask extends RecursiveTask{ 13 | private final static int THRESHOLD=2;//阈值 14 | private int start; 15 | private int end; 16 | public CountTask(int start, int end){ 17 | this.start = start; 18 | this.end = end; 19 | } 20 | @Override 21 | protected Integer compute() { 22 | int sum=0; 23 | boolean canCompute=(end-start)<=THRESHOLD; 24 | if (canCompute){ 25 | for (int i=start;i<=end;i++){ 26 | sum+=i; 27 | } 28 | }else{ 29 | int middle=(start+end)/2;//分成两个子任务执行 30 | CountTask task1=new CountTask(start,middle); 31 | CountTask task2=new CountTask(middle+1,end); 32 | //执行子任务 33 | task1.fork(); 34 | task2.fork(); 35 | //等待任务执行完,并得到其结果 36 | int num1=task1.join(); 37 | int num2=task2.join(); 38 | sum=num1+num2; 39 | } 40 | return sum; 41 | } 42 | 43 | public static void main(String[] args) throws ExecutionException, InterruptedException { 44 | ForkJoinPool forkJoinPool=new ForkJoinPool(); 45 | // 生成一个计算任务,负责计算1+2+3+4 46 | CountTask task = new CountTask(1, 4); 47 | // 执行一个任务 48 | ForkJoinTask result = forkJoinPool.submit(task); 49 | System.out.println(result.get()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/util/ZipUtil.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.util; 2 | 3 | /** 4 | * @title: ZipUtil 5 | * @projectName algorithm-study 6 | * @description: TODO 7 | * @date 2019/10/18 13:39 8 | */ 9 | import java.io.ByteArrayInputStream; 10 | import java.io.ByteArrayOutputStream; 11 | import java.io.IOException; 12 | import java.util.zip.GZIPInputStream; 13 | import java.util.zip.GZIPOutputStream; 14 | 15 | // 将一个字符串按照zip方式压缩和解压缩 16 | public class ZipUtil { 17 | 18 | // 压缩 19 | public static String compress(String str) throws IOException { 20 | if (str == null || str.length() == 0) { 21 | return str; 22 | } 23 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 24 | GZIPOutputStream gzip = new GZIPOutputStream(out); 25 | gzip.write(str.getBytes()); 26 | gzip.close(); 27 | return out.toString("ISO-8859-1"); 28 | } 29 | 30 | // 解压缩 31 | public static String uncompress(String str) throws IOException { 32 | if (str == null || str.length() == 0) { 33 | return str; 34 | } 35 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 36 | ByteArrayInputStream in = new ByteArrayInputStream(str 37 | .getBytes("ISO-8859-1")); 38 | GZIPInputStream gunzip = new GZIPInputStream(in); 39 | byte[] buffer = new byte[256]; 40 | int n; 41 | while ((n = gunzip.read(buffer)) >= 0) { 42 | out.write(buffer, 0, n); 43 | } 44 | // toString()使用平台默认编码,也可以显式的指定如toString("GBK") 45 | return out.toString(); 46 | } 47 | 48 | // 测试方法 49 | public static void main(String[] args) throws IOException { 50 | System.out.println(ZipUtil.compress("中国China")); 51 | System.out.println(ZipUtil.uncompress(ZipUtil.compress("中国China"))); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution2.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * @author xun2.liu 8 | * @title: Solution2 9 | * @projectName algorithm-study 10 | * @description: 11 | * 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 12 | * 示例 1: 13 | * 14 | * 输入: "abcabcbb" 15 | * 输出: 3 16 | * 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 17 | * 18 | * 来源:力扣(LeetCode) 19 | * 链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters 20 | * @date 2020/5/13 15:51 21 | */ 22 | public class Solution2 { 23 | /** 24 | * 使用滑动窗口 25 | * 定义一个 map 数据结构存储 (k, v),其中 key 值为字符,value 值为字符位置 +1,加 1 表示从字符位置后一个才开始不重复 26 | * 我们定义不重复子串的开始位置为 start,结束位置为 end 27 | * 随着 end 不断遍历向后,会遇到与 [start, end] 区间内字符相同的情况,此时将字符作为 key 值,获取其 value 值,并更新 start,此时 [start, end] 28 | * 区间内不存在重复字符 29 | * 无论是否更新 start,都会更新其 map 数据结构和结果 ans。 30 | * 时间复杂度:O(n)O(n) 31 | * @param s 32 | * @return 33 | */ 34 | public static int lengthOfLongestSubstring(String s) { 35 | //最长子串 的长度 36 | int resultLen=0; 37 | //key为字符 value为end 38 | Map map= new HashMap<>(); 39 | //初始化起始位置和结束位置 40 | int start=0; 41 | for(int end=0;end { 13 | private Object[] data;//数组存储数据元素 14 | //栈默认长度,存放线性表的存储空间长度 15 | private final static int DEFAULT_CAPACITY=16; 16 | //数据元素的个数,也是栈顶的指针 17 | private int size=0; 18 | 19 | public ArrayStack(int capacity){ 20 | this.data=new Object[Math.abs(capacity)]; 21 | } 22 | public ArrayStack(){ 23 | this(DEFAULT_CAPACITY); 24 | } 25 | 26 | /** 27 | * 入栈,在栈顶的位置插入元素,如果栈的容量已经满了,需要先扩容 28 | * @param element 数据元素 29 | * @return 30 | */ 31 | public boolean push(E element){ 32 | /*栈满*/ 33 | if (size==data.length){//如果数组已经满了需要扩容。 34 | Object[] temp=data; 35 | data=new Object[data.length+(data.length/2)]; 36 | System.arraycopy(temp,0,data,0,temp.length); 37 | } 38 | data[size]=element;//数组的末尾插入元素 39 | size++; 40 | return true; 41 | } 42 | /** 43 | * 出栈,从栈顶的位置删除并返回当前元素。 44 | * @return 45 | */ 46 | public Object pop(){ 47 | if (size==0){ 48 | throw new RuntimeException("空栈,size:"+size); 49 | } 50 | Object result = data[size-1]; 51 | data[size-1]=null; 52 | size--; 53 | return result; 54 | } 55 | //返回栈顶的元素,但不出栈 56 | public Object peek(){ 57 | return data[size-1]; 58 | 59 | } 60 | //获取栈的大小 61 | public int getLength() 62 | { 63 | return size; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/mode/TestMode.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.mode; 2 | 3 | import com.algorithm.study.demo.mode.factory.HumanFactory; 4 | import com.algorithm.study.demo.mode.factory.WhiteHuman; 5 | import com.algorithm.study.demo.mode.proxy.GamePlayer; 6 | import com.algorithm.study.demo.mode.proxy.IGamePlayer; 7 | import com.algorithm.study.demo.mode.singleton.EnumSingleton; 8 | import com.algorithm.study.demo.mode.strategy.MemberStrategy; 9 | import com.algorithm.study.demo.mode.strategy.Price; 10 | import com.algorithm.study.demo.mode.strategy.PrimaryMemberStrategy; 11 | import com.algorithm.study.demo.mode.templates.SubClassOne; 12 | import com.algorithm.study.demo.mode.templates.SubClassTwo; 13 | import com.algorithm.study.demo.mode.templates.TemplateInterface; 14 | 15 | /** 16 | * Created by liuxun on 2017/7/13. 17 | */ 18 | public class TestMode { 19 | public static void main(String[] args) { 20 | //单例模式 21 | EnumSingleton obj1 = EnumSingleton.getInstance(); 22 | EnumSingleton obj2 = EnumSingleton.getInstance(); 23 | //输出结果:obj1==obj2?true 24 | System.out.println("obj1==obj2?" + (obj1==obj2)); 25 | /** 26 | * 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换,策略模式让算法独立于使用它的客户而独立变化。 27 | * 策略模式的缺点: 28 | * 1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。 29 | * 2、策略模式造成很多的策略类,每个具体策略类都会产生一个新类。 30 | */ 31 | MemberStrategy memberStrategy=new PrimaryMemberStrategy(); 32 | Price price=new Price(memberStrategy); 33 | price.quote(2222); 34 | 35 | 36 | //模板方法 37 | TemplateInterface subClassOne=new SubClassOne(); 38 | TemplateInterface subClassTwo=new SubClassTwo(); 39 | subClassOne.execute(); 40 | subClassTwo.execute(); 41 | 42 | //工厂模式 43 | WhiteHuman white = HumanFactory.createHuman(WhiteHuman.class); 44 | white.getColor(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/ArraySolution.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm; 2 | 3 | import java.util.HashMap; 4 | import java.util.HashSet; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | /** 9 | * 数组练习题 10 | * @Author: liuxun 11 | * @CreateDate: 2019/3/22 上午9:47 12 | * @Version: 1.0 13 | */ 14 | public class ArraySolution { 15 | 16 | public static void main(String[] args) { 17 | ArraySolution p=new ArraySolution(); 18 | 19 | System.out.println(p.containsDuplicate(new int[]{1,2,3,1})); 20 | } 21 | 22 | /*** 23 | * 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 24 | * 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 25 | * 26 | * 示例: 27 | * 给定 nums = [2, 7, 11, 15], target = 9 28 | * 因为 nums[0] + nums[1] = 2 + 7 29 | */ 30 | public int[] twoSum(int[] nums, int target) { 31 | if (nums.length==0){ 32 | return new int[]{}; 33 | } 34 | Map map=new HashMap(); 35 | for(int i=0;i set=new HashSet<>(); 57 | for (int i=0;i sheetBankWaterCount=new ConcurrentHashMap(); 16 | /** 17 | * 开启四个个线程 18 | */ 19 | private Executor executor = Executors.newFixedThreadPool(4); 20 | class handler implements Runnable{ 21 | public void run() { 22 | int result = 0; 23 | // 汇总每个sheet计算出的结果 24 | for (Map.Entry sheet : sheetBankWaterCount.entrySet()) { 25 | result += sheet.getValue(); 26 | System.out.println(sheet.getKey()+":"+sheet.getValue()); 27 | } 28 | // 将结果输出 29 | sheetBankWaterCount.put("result", result); 30 | System.out.println(result); 31 | } 32 | } 33 | private void count() { 34 | for (int i = 0; i< 4; i++) { 35 | executor.execute(new Runnable() { 36 | public void run() { 37 | // 计算当前sheet的银流数据,计算代码省略 38 | sheetBankWaterCount.put(Thread.currentThread().getName(), 1); 39 | // 银流计算完成,插入一个屏障 40 | try { 41 | c.await(); 42 | } catch (Exception e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | }); 47 | } 48 | } 49 | public static void main(String[] args) { 50 | BankWaterService bankWaterCount = new BankWaterService(); 51 | bankWaterCount.count(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/huffman/DataOutputStreamHuffman.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.huffman; 2 | import java.io.FileNotFoundException; 3 | import java.io.FileOutputStream; 4 | import java.io.IOException; 5 | 6 | /** 7 | * @author xun2.liu 8 | * @title: DataOutputStreamHuffman 9 | * @projectName algorithm-study 10 | * @description: TODO 11 | * @date 2019/11/19 17:03 12 | */ 13 | public class DataOutputStreamHuffman { 14 | 15 | public static final DataOutputStreamHuffman OUTPUT = new DataOutputStreamHuffman(); 16 | 17 | public static final String path = "D:\\java\\test\\datastruct\\hoffman\\"; 18 | 19 | public void outtoFile(byte[] value) { 20 | FileOutputStream output = null; 21 | try { 22 | output = new FileOutputStream(path + "src.file"); 23 | output.write(value); 24 | } catch (FileNotFoundException e) { 25 | e.printStackTrace(); 26 | } catch (IOException e) { 27 | e.printStackTrace(); 28 | } finally { 29 | if (null != output) { 30 | try { 31 | output.close(); 32 | } catch (IOException e) { 33 | e.printStackTrace(); 34 | } 35 | } 36 | } 37 | } 38 | 39 | public void outHuffmantoFile(byte[] value) { 40 | FileOutputStream output = null; 41 | try { 42 | output = new FileOutputStream(path + "out.huff"); 43 | output.write(value); 44 | } catch (FileNotFoundException e) { 45 | e.printStackTrace(); 46 | } catch (IOException e) { 47 | e.printStackTrace(); 48 | } finally { 49 | if (null != output) { 50 | try { 51 | output.close(); 52 | } catch (IOException e) { 53 | e.printStackTrace(); 54 | } 55 | } 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution3.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.PriorityQueue; 6 | 7 | /** 8 | * @author xun2.liu 9 | * @title: Solution3 10 | * @projectName algorithm-study 11 | * @description:前 K 个高频元素 12 | * 给定一个非空的整数数组,返回其中出现频率前 k 高的元素。 13 | * 14 | * 示例 1: 15 | * 16 | * 输入: nums = [1,1,1,2,2,3], k = 2 17 | * 输出: [1,2] 18 | * 19 | * 来源:力扣(LeetCode) 20 | * 链接:https://leetcode-cn.com/problems/top-k-frequent-elements 21 | * @date 2020/5/13 16:28 22 | */ 23 | public class Solution3 { 24 | /** 25 | * 使用优先队列 26 | * 首先建立一个元素值对应出现频率的哈希表。在 Java 中使用 HashMap,但需要手工填值。 27 | * 这个步骤需要 O(N) 时间其中 NN 是列表中元素个数。 28 | * 第二步建立堆,堆中添加一个元素的复杂度是 O(\log(k)),要进行 NN 次复杂度是 O(N)。 29 | * 最后一步是输出结果,复杂度为 O(k\log(k))。 30 | * @param nums 31 | * @param k 32 | * @return 33 | */ 34 | public static int[] topKFrequent(int[] nums, int k) { 35 | 36 | //用来存储每个数字出现的次数 37 | Map counter=new HashMap<>(); 38 | for(int n:nums){ 39 | counter.put(n,counter.getOrDefault(n,0)+1); 40 | } 41 | //使用每个数字出现的次数作为排序规则来建立初始化一个优先队列 42 | PriorityQueue heap=new PriorityQueue<>((n1,n2)-> counter.get(n1)-counter.get(n2)); 43 | //把数字写入优先队列中 44 | for(int num:counter.keySet()){ 45 | heap.add(num); 46 | //如果优先队列中的元素大于前K个就删除,因为默认是升序。 47 | if(heap.size()>k){ 48 | heap.poll(); 49 | } 50 | } 51 | //取出前K个元素从优先队列中 52 | int[] result=new int[k]; 53 | for(int i=0;i{ 30 | System.out.println("Action...Go!"); 31 | }); 32 | static ExecutorService executorService= Executors.newFixedThreadPool(2); 33 | public static void main(String[] args) { 34 | executorService.submit(new Runnable() { 35 | public void run() { 36 | try { 37 | c.await(); 38 | } catch (Exception e) { 39 | e.printStackTrace(); 40 | } 41 | System.out.println("1"); 42 | } 43 | }); 44 | executorService.submit(new Runnable() { 45 | public void run() { 46 | try { 47 | c.await(); 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | } 51 | System.out.println("2"); 52 | } 53 | }); 54 | try { 55 | c.await(); 56 | } catch (Exception e) { 57 | e.printStackTrace(); 58 | } 59 | System.out.println("3"); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/nio/ChannelTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.nio; 2 | 3 | import java.io.IOException; 4 | import java.io.RandomAccessFile; 5 | import java.nio.ByteBuffer; 6 | import java.nio.CharBuffer; 7 | import java.nio.channels.FileChannel; 8 | import java.nio.charset.Charset; 9 | import java.nio.charset.CharsetDecoder; 10 | 11 | /** 12 | * @author liuxun 13 | * @version V1.0 14 | * @Description: JavaNio Channel 15 | * @date 2017/12/4 16 | */ 17 | public class ChannelTest { 18 | public static void main(String[] args) throws IOException { 19 | try { 20 | Charset charset = Charset.forName("GBK"); 21 | //Java.nio.charset.Charset处理了字符转换问题。它通过构造CharsetEncoder和CharsetDecoder将字符序列转换成字节和逆转换。 22 | CharsetDecoder decoder = charset.newDecoder(); 23 | 24 | RandomAccessFile raf = new RandomAccessFile("E:\\data.txt", "rw"); 25 | FileChannel fc = raf.getChannel(); 26 | 27 | // RandomAccessFile raf1 = new RandomAccessFile("E:\\count.txt", "rw"); 28 | // FileChannel fc1 = raf1.getChannel(); 29 | // 30 | // fc1.transferTo(0, fc.size(),fc); 31 | 32 | //create buffer with capatity of 512 bytes 33 | ByteBuffer buffer = ByteBuffer.allocate(512); 34 | CharBuffer cb = CharBuffer.allocate(512); 35 | //写入数据到Buff 36 | int count = fc.read(buffer); 37 | while (count != -1) { 38 | System.out.println("count = "+count); 39 | //通过flip()方法将Buffer从写模式切换到读模式 40 | buffer.flip(); 41 | decoder.decode(buffer, cb, false); 42 | cb.flip(); 43 | //从Buffer中读取数据 44 | while (cb.hasRemaining()) { 45 | System.out.print(cb.get()); 46 | } 47 | System.out.println(); 48 | //清空缓冲区 49 | buffer.clear(); 50 | cb.clear(); 51 | count = fc.read(buffer); 52 | } 53 | raf.close(); 54 | } catch (Exception e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/datastructure/heap/MidNumCount.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.datastructure.heap; 2 | 3 | import java.util.Comparator; 4 | import java.util.PriorityQueue; 5 | 6 | /** 7 | * 求中位数的问题 8 | * @Author: liuxun 9 | * @CreateDate: 2019/1/31 下午1:57 10 | * @Version: 1.0 11 | */ 12 | public class MidNumCount { 13 | 14 | /** 大顶堆,用来存储前半部分的数据,如果完整为100,那此存储的为0-50 */ 15 | private PriorityQueue firstBigHeap =new PriorityQueue<>(11, new Comparator() { 16 | @Override 17 | public int compare(Integer o1, Integer o2) { 18 | return o2-o1; 19 | } 20 | }); 21 | 22 | /** 小顶堆,用来存储后半部分的数据,如果完整为100,那此存储的为51-100 */ 23 | private PriorityQueue afterLittleHeap = new PriorityQueue<>(11); 24 | 25 | /** 元素的个数 */ 26 | private int count; 27 | 28 | /** 29 | * 插入数据 30 | * 31 | * @param num 当前动态的数据集 32 | */ 33 | public void putNum(int num) { 34 | 35 | count++; 36 | 37 | // 1,如果堆为空,则插入大顶堆中 38 | if (firstBigHeap.isEmpty() && afterLittleHeap.isEmpty()) { 39 | firstBigHeap.offer(num); 40 | return; 41 | } 42 | //奇数 43 | if (((firstBigHeap.size()+afterLittleHeap.size()) & 1)==1){ 44 | //如果数据当前元素比大顶堆中的元素大,则插入小顶堆中 45 | if (afterLittleHeap.peek() > num) { 46 | afterLittleHeap.offer(num); 47 | 48 | } 49 | }else{ 50 | 51 | } 52 | 53 | } 54 | 55 | /** 56 | * 返回中位数的数据 57 | * 58 | * @return 59 | */ 60 | public int getMidValue() { 61 | return firstBigHeap.peek(); 62 | } 63 | 64 | /** 65 | * 从一个堆向另一个堆中移动元素 66 | * 67 | * @param src 68 | * @param out 69 | */ 70 | private void move(PriorityQueue src, PriorityQueue out, int runNum) { 71 | for (int i = 0; i < runNum; i++) { 72 | out.offer(src.poll()); 73 | } 74 | } 75 | 76 | public static void main(String[] args) { 77 | 78 | int[] da=new int[]{5,6,4,1,2}; 79 | 80 | System.out.println(6>>1); 81 | System.out.println(6&1); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution27.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | /** 4 | * @author xun2.liu 5 | * @title: Solution27 6 | * @projectName algorithm-study 7 | * @description: 在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。 8 | * 你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。 9 | * 给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物? 10 | 11 | * 示例 1: 12 | * 13 | * 输入: 14 | * [ 15 | *   [1,3,1], 16 | *   [1,5,1], 17 | *   [4,2,1] 18 | * ] 19 | * 输出: 12 20 | * 解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物 21 | * 来源:力扣(LeetCode) 22 | * 链接:https://leetcode-cn.com/problems/li-wu-de-zui-da-jie-zhi-lcof 23 | * @date 2020/6/30 20:32 24 | */ 25 | public class Solution27 { 26 | 27 | public static int maxValue(int[][] grid) { 28 | int row=grid.length; 29 | int col=grid[0].length; 30 | int[][] db=new int[row+1][col+1]; 31 | for (int i=1;i<=row;i++){ 32 | for (int j=1;j<=col;j++){ 33 | db[i][j]=Math.max(db[i-1][j],db[i][j-1])+grid[i-1][j-1]; 34 | } 35 | } 36 | return db[row][col]; 37 | } 38 | /** 39 | * 设 f(i, j) 为从棋盘左上角走至单元格 (i ,j)的礼物最大累计价值,易得到以下递推关系:f(i,j) 40 | * 等于 f(i,j-1) 和 f(i-1,j) 中的较大值加上当前单元格礼物价值 grid(i,j) 41 | * f(i,j)=max[f(i,j−1),f(i−1,j)]+grid(i,j) 42 | */ 43 | public static int maxValue2(int[][] grid) { 44 | int m = grid.length, n = grid[0].length; 45 | for(int i = 0; i < m; i++) { 46 | for(int j = 0; j < n; j++) { 47 | if(i == 0 && j == 0) { 48 | continue; 49 | } 50 | if(i == 0) { 51 | grid[i][j] += grid[i][j - 1] ; 52 | } else if(j == 0) { 53 | grid[i][j] += grid[i - 1][j]; 54 | } else { 55 | grid[i][j] += Math.max(grid[i][j - 1], grid[i - 1][j]); 56 | } 57 | } 58 | } 59 | return grid[m - 1][n - 1]; 60 | } 61 | public static void main(String[] args) { 62 | int[][] dd={{1,3,1},{1,5,1},{4,2,1}}; 63 | 64 | int i = maxValue(dd); 65 | System.out.println(i); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution7.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | /** 4 | * @author xun2.liu 5 | * @title: Solution7 6 | * @projectName algorithm-study 7 | * @description: 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 8 | * 9 | * 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 10 | * 11 | * 说明:不允许修改给定的链表。 12 | * 13 | * 示例 1: 14 | * 15 | * 输入:head = [1,2], pos = 0 16 | * 输出:tail connects to node index 0 17 | * 解释:链表中有一个环,其尾部连接到第一个节点。 18 | * 19 | * 来源:力扣(LeetCode) 20 | * 链接:https://leetcode-cn.com/problems/linked-list-cycle-ii 21 | * 22 | * @date 2020/5/19 17:16 23 | */ 24 | public class Solution7 { 25 | public static class ListNode { 26 | int val; 27 | ListNode next; 28 | ListNode(int x) { val = x; } 29 | } 30 | 31 | /** 32 | * 快慢指针遍历连表。看是否相遇。如果相遇在判断是否是循环链表。 33 | * p1=x+y 34 | * p2=x+y+z+y; 35 | * 因为p2是p1的两倍 36 | * 2*(x+y)=x+y+z+y 37 | * x=z 38 | * @param head 39 | * @return 40 | */ 41 | public static ListNode detectCycle(ListNode head) { 42 | if (null== head || head.next==null){ 43 | return null; 44 | } 45 | //p1指针走一步、p2指针走两步。 46 | ListNode p1=head; 47 | ListNode p2=head; 48 | while(p2!=null && p2.next!=null){ 49 | p1=p1.next; 50 | p2=p2.next.next; 51 | //如果相等就表示是环形。然后寻找环形入口。 52 | if(p1==p2){ 53 | //p1指向头结点。找到环形入口 54 | p1=head; 55 | while(p1!=p2){ 56 | p1=p1.next; 57 | p2=p2.next; 58 | } 59 | return p1; 60 | } 61 | } 62 | return null; 63 | } 64 | public static void main(String[] args) { 65 | ListNode a=new ListNode(5); 66 | ListNode b=new ListNode(4); 67 | ListNode c=new ListNode(6); 68 | ListNode d=new ListNode(-1); 69 | a.next=b; 70 | b.next=c; 71 | c.next=b; 72 | // c.next=b; 73 | ListNode listNode = detectCycle(a); 74 | System.out.println(listNode==null?"":listNode.val); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution8.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | /** 4 | * @author xun2.liu 5 | * @title: Solution8 6 | * @projectName algorithm-study 7 | * @description: 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。 8 | * 9 | * 示例: 10 | * 给定一个链表: 1->2->3->4->5, 和 n = 2. 11 | * 当删除了倒数第二个节点后,链表变为 1->2->3->5. 12 | * 来源:力扣(LeetCode) 13 | * 链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list 14 | * @date 2020/5/20 21:01 15 | */ 16 | public class Solution8 { 17 | public static class ListNode { 18 | int val; 19 | ListNode next; 20 | ListNode(int x) { val = x; } 21 | } 22 | /** 23 | * 我们可以使用两个指针而不是一个指针。第一个指针从列表的开头向前移动 n+1步,而第二个指针将从列表的开头出发。现在,这两个指针被n个结点分开。 24 | * 我们通过同时移动两个指针向前来保持这个恒定的间隔,直到第一个指针到达最后一个结点。此时第二个指针将指向从最后一个结点数起的第n个结点。 25 | * 我们重新链接第二个指针所引用的结点的 next 指针指向该结点的下下个结点。 26 | * @param head 27 | * @param n 28 | * @return 29 | */ 30 | public static ListNode removeNthFromEnd(ListNode head, int n) { 31 | if (head.next==null){ 32 | return null; 33 | } 34 | //增加一个头部节点,方便删除倒数的节点刚好是第一个节点。 35 | ListNode temp=new ListNode(-1); 36 | temp.next=head; 37 | ListNode p1=temp; 38 | ListNode p2=temp; 39 | //第一个指针从列表的开头向前移动 n+1步 40 | for (int i=0;i queue=new LinkedList<>(); 45 | //把当前的第一层添加至队列中 46 | queue.offer(root); 47 | //默认深度为0 48 | int depth=0; 49 | while (queue.size()>0){ 50 | //获取当前层的节点数量 51 | int size = queue.size(); 52 | //遍历当前层的节点 53 | for (int i = 0; i < size; i++) { 54 | //弹出当前层的节点。获取节点下一层的节点 55 | TreeNode head = queue.poll(); 56 | if (head.left!=null){ 57 | queue.offer(head.left); 58 | } 59 | if (head.right!=null){ 60 | queue.offer(head.right); 61 | } 62 | } 63 | //当前层遍历结束后。树的深度+1 64 | depth++; 65 | } 66 | return depth; 67 | 68 | } 69 | public static void main(String[] args) { 70 | TreeNode a=new TreeNode(3); 71 | TreeNode b=new TreeNode(9); 72 | TreeNode c=new TreeNode(20); 73 | TreeNode d=new TreeNode(15); 74 | TreeNode r=new TreeNode(7); 75 | a.left=b; 76 | a.right=c; 77 | c.left=d; 78 | c.right=r; 79 | System.out.println(maxDepth(a)); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | import com.algorithm.study.demo.LRUCache.LRUCache; 4 | 5 | /** 6 | * @author xun2.liu 7 | * @title: Solution 8 | * @projectName algorithm-study 9 | * @description: 10 | * 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的, 11 | * 并且它们的每个节点只能存储 一位 数字。 12 | * 13 | * 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 14 | * 15 | * 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 16 | * 示例: 17 | * 18 | * 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 19 | * 输出:7 -> 0 -> 8 20 | * 原因:342 + 465 = 807 21 | * 22 | * 来源:力扣(LeetCode) 23 | * 链接:https://leetcode-cn.com/problems/add-two-numbers 24 | * @date 2020/5/9 14:42 25 | */ 26 | public class Solution { 27 | static class ListNode{ 28 | private int val; 29 | private ListNode next; 30 | private ListNode(int val){ 31 | this.val=val; 32 | } 33 | 34 | } 35 | 36 | public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { 37 | //返回的结果,初始化 38 | ListNode result=new ListNode(0); 39 | //j结果游标 40 | ListNode curr=result; 41 | //满十进1,存储进位 42 | int carry=0; 43 | while(l1!=null || l2!=null){ 44 | int p1=l1==null?0:l1.val; 45 | int p2=l2==null?0:l2.val; 46 | //计算当前两数相加后的值 47 | int sum=p1+p2+carry; 48 | //计算相加后的值的进位 49 | carry=sum/10; 50 | //存储当前相加后的值除以10的余数 51 | curr.next=new ListNode(sum%10); 52 | //游标指向下个节点 53 | curr=curr.next; 54 | 55 | if (l1!=null){ 56 | l1=l1.next; 57 | } 58 | if (l2!=null){ 59 | l2=l2.next; 60 | } 61 | } 62 | if (carry>0){ 63 | curr.next=new ListNode(carry); 64 | } 65 | return result.next; 66 | } 67 | public static void main(String[] args) { 68 | ListNode a=new ListNode(5); 69 | ListNode b=new ListNode(5); 70 | a.next=b; 71 | 72 | 73 | ListNode result = addTwoNumbers(a, a); 74 | for (ListNode node=result;node!=null;node=node.next){ 75 | System.out.println(node.val); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution23.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * @author xun2.liu 7 | * @title: Solution23 8 | * @projectName algorithm-study 9 | * @description: 给你一个整数数组 nums,请你将该数组升序排列。 10 | * 11 | * 示例 1: 12 | * 13 | * 输入:nums = [5,2,3,1] 14 | * 输出:[1,2,3,5] 15 | * @date 2020/6/5 13:50 16 | */ 17 | public class Solution23 { 18 | /** 19 | * 归并排序 20 | * https://www.cnblogs.com/chengxiao/p/6194356.html 21 | * @param nums 22 | * @return 23 | */ 24 | public static int[] sortArray(int[] nums) { 25 | //在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间 26 | int[] temp=new int[nums.length]; 27 | mSort(nums,0,nums.length-1,temp); 28 | return nums; 29 | } 30 | 31 | public static void mSort(int[] nums,int left,int right,int[] temp){ 32 | if (left inorderTraversal(TreeNode root) { 44 | List result=new ArrayList(); 45 | Stack stack=new Stack(); 46 | TreeNode curr=root; 47 | while(curr!=null || !stack.isEmpty()){ 48 | //首先遍历左子节点 49 | if (curr!=null){ 50 | //不断往左子树方向走,每走一次就将当前节点保存到栈中 51 | //这是模拟递归的调用 52 | stack.push(curr); 53 | curr=curr.left; 54 | }else{ 55 | //当前节点为空,说明左边走到头了,从栈中弹出节点并保存 56 | //然后转向右边节点,继续上面整个过程 57 | curr= stack.pop(); 58 | result.add(curr.val); 59 | curr=curr.right; 60 | } 61 | } 62 | return result; 63 | } 64 | public static void main(String[] args) { 65 | TreeNode a=new TreeNode(3); 66 | TreeNode b=new TreeNode(9); 67 | TreeNode c=new TreeNode(20); 68 | TreeNode d=new TreeNode(15); 69 | TreeNode r=new TreeNode(2); 70 | a.left=b; 71 | a.right=c; 72 | c.left=d; 73 | c.right=r; 74 | List integers = inorderTraversal(a); 75 | for (Integer integer : integers) { 76 | System.out.println(integer); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/concurrent/CallableDemo.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.concurrent; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.*; 6 | 7 | /** 8 | * @author liuxun 9 | * @version V1.0 10 | * @Description: Future使用 11 | * @date 2017/10/27 12 | */ 13 | public class CallableDemo { 14 | public static void main(String[] args) { 15 | ExecutorService executorService = Executors.newCachedThreadPool(); 16 | List> resultList = new ArrayList>(); 17 | 18 | //创建10个任务并执行 19 | for (int i = 0; i < 10; i++) { 20 | //使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中 21 | Future future = executorService.submit(new TaskWithResult(i)); 22 | //将任务执行结果存储到List中 23 | resultList.add(future); 24 | } 25 | 26 | //遍历任务的结果 27 | for (Future fs : resultList) { 28 | try { 29 | System.out.println(fs.get()); //打印各个线程(任务)执行的结果 30 | } catch (InterruptedException e) { 31 | e.printStackTrace(); 32 | } catch (ExecutionException e) { 33 | e.printStackTrace(); 34 | } finally { 35 | //启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用。 36 | executorService.shutdown(); 37 | } 38 | } 39 | System.out.println("所有任务任务执行完毕"); 40 | } 41 | 42 | static class TaskWithResult implements Callable { 43 | private int id; 44 | 45 | public TaskWithResult(int id) { 46 | this.id = id; 47 | } 48 | 49 | /** 50 | * 任务的具体过程,一旦任务传给ExecutorService的submit方法,则该方法自动在一个线程上执行。 51 | * 52 | * @return 53 | * @throws Exception 54 | */ 55 | @Override 56 | public String call() throws Exception { 57 | System.out.println("call()方法被自动调用,干活!!! " + Thread.currentThread().getName()); 58 | //一个模拟耗时的操作 59 | for (int i = 999999; i > 0; i--){ 60 | return"call()方法被自动调用,任务的结果是:" + id + " " + Thread.currentThread().getName(); 61 | } 62 | return "1111111111111111"; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/datastructure/queue/SqQueue.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.datastructure.queue; 2 | 3 | /** 4 |  队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同, 5 | 其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其另一端进行删除操作。 6 | 队列中允许进行插入操作的一端称为队尾,允许进行删除操作的一端称为队头。队列的插入操作通常称作入队列,队列的删除操作通常称作出队列。 7 | 8 | 循环队列可以有效的利用资源。如果使用普通数组实现队列时,如果不进行移动,随着数据的不断读写弹出插入,会出现假满队列的情况。例如不断向队列中添加元素,然后在弹出元素。这是弹出元素所空闲出来的空间并没有得到重复利用, 9 | 这是就会出现数组尾部已经满了,但是头部还有空闲空间没有得到利用。 10 | 入队时尾指针向前追赶头指针,出队时头指针向前追赶尾指针 11 | 12 | * Created by liuxun on 2017/6/22. 13 | */ 14 | public class SqQueue { 15 | private Object[] data; 16 | private int front;//头指针 17 | private int rear;//尾指针 18 | private int maxsize;//长度 19 | 20 | public SqQueue(int capacity){ 21 | this.maxsize=capacity; 22 | this.data=new Object[capacity]; 23 | front=rear=0; 24 | } 25 | /**返回队列当前长度**/ 26 | public int size(){ 27 | if (isFull()){ 28 | return maxsize; 29 | } 30 | return (rear-front+maxsize)%maxsize; 31 | } 32 | 33 | /** 34 | * 循环队列入队操作 35 | * @param element 36 | */ 37 | public boolean add(E element){ 38 | if ((rear+1)%maxsize==front) return false;//队列已满 39 | data[rear]=element; 40 | //逻辑上实现首尾相连,循环队列 41 | rear=(rear+1)%maxsize; 42 | return true; 43 | } 44 | /** 45 | * 循环队列出队操作,并清空头部 46 | * @return 47 | */ 48 | public Object poll(){ 49 | if (rear==front && data[front]==null){ 50 | return null; 51 | } 52 | Object result=data[front]; 53 | data[front]=null; 54 | front=(front+1)%maxsize; 55 | return result; 56 | } 57 | /** 58 | * 循环队列出队操作,不清空头部 59 | * @return 60 | */ 61 | public Object peek(){ 62 | return data[front]; 63 | } 64 | //check is null 65 | private boolean isFull(){ 66 | //首尾相等并且首不为空的话就代表队列已满 67 | return front == rear && data[front]!=null; 68 | } 69 | 70 | public static void main(String[] args) { 71 | SqQueue queue=new SqQueue(8); 72 | for (int i=0;i<8;i++){ 73 | queue.add(i); 74 | } 75 | System.out.println(queue.poll()); 76 | System.out.println(queue.size()); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/string/TestString.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.string; 2 | 3 | /** 4 | * Created by liuxun on 2017/6/22. 5 | */ 6 | public class TestString { 7 | public static void main(String[] args) { 8 | TestString test = new TestString(); 9 | 10 | System.out.println(test.Index("goodgoogle", "google", 0)); 11 | 12 | System.out.println(test.indexKMP("goodgoogle", "google", 0)); 13 | } 14 | 15 | //朴素模式匹配算法 16 | public int Index(String s,String t,int pos){ 17 | 18 | int i = pos;//主串中第几个位置开始比较 19 | int j = 0;//模式串中的第一个位置 20 | while(i=t.length()) { 32 | return i-t.length(); 33 | }else { 34 | return -1; 35 | } 36 | 37 | } 38 | 39 | //////////KMP模式匹配算法//////////////// 40 | public int[] getNext(String T){ 41 | int[] next = new int[T.length()]; 42 | int i = 0; 43 | int j = -1; 44 | 45 | next[i] = j; 46 | 47 | while(i=T.length()) { 81 | return i-T.length(); 82 | }else { 83 | return 0; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/Solution.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | import java.util.*; 6 | 7 | /** 8 | * 算法面试题 9 | * @Author: liuxun 10 | * @CreateDate: 2019/2/13 下午3:11 11 | * @Version: 1.0 12 | */ 13 | public class Solution { 14 | 15 | /** 16 | * 整数反转 17 | * 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 18 | * @param x 19 | * @return 20 | */ 21 | public static int reverse(int x) { 22 | long result = 0; 23 | while (x != 0) { 24 | result = result * 10 + x % 10; 25 | x /= 10; 26 | } 27 | if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) 28 | result = 0; 29 | return (int)result; 30 | } 31 | 32 | /** 33 | * 求一个字符串的最大不重复子串 34 | */ 35 | public static int lengthOfLongestSubstring(String s) { 36 | int n = s.length(); 37 | Set set = new HashSet<>(); 38 | int ans = 0, i = 0, j = 0; 39 | while (i < n && j < n) { 40 | // try to extend the range [i, j] 41 | if (!set.contains(s.charAt(j))){ 42 | set.add(s.charAt(j++)); 43 | ans = Math.max(ans, j - i); 44 | } 45 | else { 46 | //删除重复的字符 47 | set.remove(s.charAt(i++)); 48 | } 49 | } 50 | return ans; 51 | } 52 | 53 | /** 54 | * 求2个有序数组的有序交集 55 | * @param args 56 | */ 57 | public static void arrayIntersection(int[] a,int[] b){ 58 | int lena=a.length; 59 | int lenb=b.length; 60 | if (lena==0 || lenb==0){ 61 | System.out.println("无数据交集"); 62 | return; 63 | } 64 | int i=0,j=0; 65 | List result=new ArrayList<>(); 66 | while (ib[j]){ 70 | j++; 71 | }else{ 72 | result.add(a[i]); 73 | i++; 74 | j++; 75 | } 76 | } 77 | System.out.println("交集为:"+ JSON.toJSONString(result)); 78 | } 79 | public static void main(String[] args) { 80 | System.out.println(lengthOfLongestSubstring("abaa")); 81 | int[] a = { 2, 3, 4, 4, 4, 4, 7, 8, 8, 8, 8, 9, 100, 130, 150, 160 }; 82 | int[] b = { 4, 6, 7, 7, 7, 7, 8, 8, 9, 10, 100, 130, 130, 140, 150 }; 83 | arrayIntersection(a,b); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/leetcode/Solution21.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.leetcode; 2 | 3 | /** 4 | * @author xun2.liu 5 | * @title: Solution21 6 | * @projectName algorithm-study 7 | * @description: 字符串转换整数 (atoi) 8 | * 请你来实现一个 atoi 函数,使其能将字符串转换成整数。 9 | * 10 | * 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下: 11 | * 12 | * 如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。 13 | * 假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。 14 | * 该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。 15 | * 注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。 16 | * 17 | * 在任何情况下,若函数不能进行有效的转换时,请返回 0 。 18 | * 19 | * 提示: 20 | * 21 | * 本题中的空白字符只包括空格字符 ' ' 。 22 | * 假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231,  231 − 1]。如果数值超过这个范围,请返回  INT_MAX (231 − 1) 或 INT_MIN (−231) 。 23 | *   24 | * 示例 1: 25 | * 26 | * 输入: "42" 27 | * 输出: 42 28 | * 29 | * 来源:力扣(LeetCode) 30 | * 链接:https://leetcode-cn.com/problems/string-to-integer-atoi 31 | * @date 2020/6/2 11:49 32 | */ 33 | public class Solution21 { 34 | public static int myAtoi(String str) { 35 | if(str==null) { 36 | return 0; 37 | } 38 | int n = str.length(); 39 | int i = 0; 40 | int res = 0; 41 | boolean is_negative = false; 42 | //第一步,跳过前面若干个空格 43 | while(i='0' && str.charAt(i)<='9') { 60 | //'0'的ASCII码是48,'1'的是49,这么一减就从就可以得到真正的整数值 61 | int tmp = str.charAt(i)-48; 62 | //判断是否大于 最大32位整数 63 | if(!is_negative &&(res>Integer.MAX_VALUE ||(res==Integer.MAX_VALUE && tmp>=7))) { 64 | return Integer.MAX_VALUE; 65 | } 66 | //判断是否小于 最小32位整数 67 | if(is_negative &&(-res<-Integer.MAX_VALUE || (-res==-Integer.MAX_VALUE && tmp>=8))) { 68 | return -Integer.MAX_VALUE; 69 | } 70 | res = res*10 + tmp; 71 | ++i; 72 | } 73 | //如果有负号标记则返回负数 74 | if(is_negative) { 75 | return -res; 76 | } 77 | return res; 78 | } 79 | 80 | public static void main(String[] args) { 81 | System.out.println(myAtoi("-42")); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/LRUCache/LRULinked.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.LRUCache; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * 单链表实现LRU缓存 8 | * @Author: liuxun 9 | * @CreateDate: 2019/1/23 下午4:03 10 | * @Version: 1.0 11 | */ 12 | public class LRULinked{ 13 | //缓存 14 | private final Map cacheMap = new HashMap<>(); 15 | //根节点 16 | private Node root; 17 | private int cacheSize; 18 | private int size; 19 | public LRULinked(int cacheSize){ 20 | this.cacheSize=cacheSize; 21 | } 22 | /** 23 | * 插入头结点 24 | * @param value 25 | */ 26 | public void put(int key,int value){ 27 | cacheMap.put(key,value); 28 | Node node=new Node(key,value); 29 | if (size==cacheSize){//容量满了删除尾节点 30 | Node temp=root.next; 31 | if (temp==null){ 32 | root=null; 33 | }else{ 34 | Node current=root; 35 | while (temp.next!=null){ 36 | current=temp; 37 | temp=temp.next; 38 | } 39 | current.next=null; 40 | } 41 | size--; 42 | } 43 | node.next=root; 44 | root=node; 45 | size++; 46 | } 47 | public int get(int key){ 48 | if (!cacheMap.containsKey(key)){ 49 | return -1; 50 | } 51 | for (Node node = root; node!=null&&!root.key.equals(key); node=node.next){ 52 | if (node.next.key.equals(key)){ 53 | Node nodeNew=new Node(node.next.key,node.next.value); 54 | node.next=node.next.next; 55 | size--; 56 | this.put(nodeNew.key,nodeNew.value);//查找的节点放到头结点 57 | break; 58 | } 59 | } 60 | return cacheMap.get(key); 61 | } 62 | @Override 63 | public String toString(){ 64 | StringBuilder sb=new StringBuilder(); 65 | for (Node temp=root;temp!=null;temp=temp.next){ 66 | sb.append(temp.value); 67 | } 68 | return sb.toString(); 69 | } 70 | class Node{ 71 | private Integer key; 72 | private Integer value; 73 | private Node next; 74 | public Node(Integer key, Integer value){ 75 | this.key=key; 76 | this.value=value; 77 | } 78 | } 79 | 80 | public static void main(String[] args) { 81 | LRULinked linked=new LRULinked(3); 82 | linked.put(1,2); 83 | linked.put(2,2); 84 | linked.put(3,3); 85 | System.out.println(linked.get(1)); 86 | linked.put(4,4); 87 | System.out.println(linked.size); 88 | System.out.println(linked.toString()); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/thread/TestTryLock.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.thread; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.locks.Lock; 6 | import java.util.concurrent.locks.ReentrantLock; 7 | 8 | /** 9 | 假如线程A和线程B使用同一个锁LOCK,此时线程A首先获取到锁LOCK.lock(),并且始终持有不释放。如果此时B要去获取锁,有四种方式: 10 | LOCK.lock(): 此方式会始终处于等待中,即使调用B.interrupt()也不能中断,除非线程A调用LOCK.unlock()释放锁。 11 | LOCK.lockInterruptibly(): 此方式会等待,但当调用B.interrupt()会被中断等待,并抛出InterruptedException异常,否则会与lock()一样始终处于等待中,直到线程A释放锁。 12 | LOCK.tryLock(): 该处不会等待,获取不到锁并直接返回false,去执行下面的逻辑。 13 | LOCK.tryLock(10, TimeUnit.SECONDS):该处会在10秒时间内处于等待中,但当调用B.interrupt()会被中断等待,并抛出InterruptedException。10秒时间内如果线程A释放锁,会获取到锁并返回true,否则10秒过后会获取不到锁并返回false,去执行下面的逻辑。 14 | 15 | 1、ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候 16 | 线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定, 17 | 如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断 18 | 如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情 19 | 2、synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中 20 | 3、在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态; 21 | 4、synchronized原始采用的是CPU悲观锁机制,即线程获得的是独占锁。而Lock用的是乐观锁方式。乐观锁实现的机制就是CAS操作(Compare and Swap)。 22 | * Created by liuxun on 2017/6/12. 23 | */ 24 | public class TestTryLock { 25 | private List list = new ArrayList(); 26 | private Lock lock = new ReentrantLock(); 27 | 28 | public static void main(String[] args) { 29 | final TestTryLock test = new TestTryLock(); 30 | for (int i=0;i<10;i++){ 31 | new Thread("第一个线程"+i+" ") { 32 | 33 | @Override 34 | public void run() { 35 | test.doSomething(Thread.currentThread()); 36 | } 37 | }.start(); 38 | 39 | new Thread("第二个线程"+i+" ") { 40 | 41 | @Override 42 | public void run() { 43 | test.doSomething(Thread.currentThread()); 44 | } 45 | }.start(); 46 | } 47 | 48 | } 49 | 50 | public void doSomething(Thread thread) { 51 | if (lock.tryLock()) {//如果没获取到锁不会等待、阻塞,继续执行。 52 | try { 53 | System.out.println(thread.getName() + "得到了锁."); 54 | for (int i = 0; i < 10; i++) { 55 | list.add(i); 56 | } 57 | } catch (Exception e) { 58 | e.printStackTrace(); 59 | } finally { 60 | System.out.println(thread.getName() + "释放了锁."); 61 | lock.unlock(); 62 | } 63 | } else { 64 | System.out.println(thread.getName() + "获取锁失败."); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/java8/Hello.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.java8; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | import java.io.File; 6 | import java.io.FileFilter; 7 | import java.util.*; 8 | import java.util.concurrent.Callable; 9 | import java.util.function.Predicate; 10 | import java.util.stream.Collectors; 11 | 12 | /** 13 | * Created by liuxun on 2017/7/10. 14 | */ 15 | public class Hello { 16 | public static void main(String[] args) { 17 | List list = Arrays.asList(1,5,6,7,2,3,4); 18 | list.sort(Comparator.comparing(Integer::intValue)); 19 | list.sort((Integer i,Integer j)->i.compareTo(j)); 20 | 21 | for (Integer a:list) { 22 | System.out.println(a); 23 | } 24 | 25 | File[] fs = new File("E:\\download").listFiles(new FileFilter() { 26 | @Override 27 | public boolean accept(File pathname) { 28 | return pathname.isHidden(); 29 | } 30 | }); 31 | File[] f2= new File("E:\\download").listFiles(File::isHidden); 32 | for (File f:f2){ 33 | System.out.println(f.getName()); 34 | } 35 | List inventory=new ArrayList<>(); 36 | inventory.add(new Apple("green",100)); 37 | inventory.add(new Apple("red",110)); 38 | inventory.add(new Apple("blue",150)); 39 | 40 | //方法应用,把方法作为值来传递 41 | List nl = filterApples(inventory, Apple::isGreenApple); 42 | for (Apple a:nl){ 43 | System.out.println(a.getColor()); 44 | } 45 | //匿名函数(Lambda),把方法作为值来传递 46 | List nl2 = filterApples(inventory,(Apple a)->a.getWeight() > 110); 47 | for (Apple a:nl2){ 48 | System.out.println(a.getColor()); 49 | } 50 | //流操作数据 51 | Map> map=new HashMap<>(); 52 | List s = inventory.stream().filter((Apple a) -> a.getWeight() > 110).collect(Collectors.toList());//串行处理 53 | s.forEach((Apple a)-> System.out.println(a.getColor())); 54 | List s2=inventory.parallelStream().filter((Apple a) -> a.getWeight() > 110).collect(Collectors.toList());//并行处理 55 | s2.forEach((Apple a)-> System.out.println(a.getColor())); 56 | 57 | Thread t=new Thread(()-> System.out.println(Thread.currentThread().getName())); 58 | t.start(); 59 | 60 | } 61 | public Callable fetch() { 62 | return () -> "Tricky example ;-)"; 63 | } 64 | /** 65 | * 把方法作为值来传递 66 | * Predicate,而这是一个函数式接口 67 | * @param inventory 68 | * @param p 69 | * @return 70 | */ 71 | public static List filterApples(List inventory, Predicate p ) { 72 | List result = new ArrayList<>(); 73 | for (T a: inventory){ 74 | if (p.test(a) ) { 75 | result.add(a); 76 | } 77 | } 78 | return result; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/java8/FunctionTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.java8; 2 | 3 | import org.testng.Assert; 4 | 5 | import java.util.function.Consumer; 6 | import java.util.function.Function; 7 | import java.util.function.Predicate; 8 | 9 | /** 10 | * @author xun2.liu 11 | * @title: FunctionTest 12 | * @projectName algorithm-study 13 | * @description: Consumer实例 14 | * @date 2019/12/20 15:19 15 | */ 16 | public class FunctionTest { 17 | public static void main(String[] args) { 18 | // consumerTest(); 19 | functionTest(); 20 | } 21 | 22 | /*** 23 | * Consumer是一个函数式编程接口; 顾名思义,Consumer的意思就是消费,即针对某个东西我们来使用它,因此它包含有一个有输入而无输出的accept接口方法; 24 | * 除accept方法,它还包含有andThen这个方法; 25 | */ 26 | public static void consumerTest() { 27 | Consumer f = System.out::println; 28 | Consumer f2 = n -> System.out.println(n + "-F2"); 29 | 30 | //执行完F后再执行F2的Accept方法 31 | f.andThen(f2).accept("test"); 32 | 33 | //连续执行F的Accept方法 34 | // f.andThen(f).andThen(f).andThen(f).accept("test1"); 35 | } 36 | 37 | /** 38 | * Function测试 39 | * Function也是一个函数式编程接口;它代表的含义是“函数”,而函数经常是有输入输出的,因此它含有一个apply方法, 40 | * 包含一个输入与一个输出;除apply方法外,它还有compose与andThen及indentity三个方法 41 | */ 42 | public static void functionTest() { 43 | Function f = s -> s++; 44 | Function g = s -> s * 2; 45 | 46 | /** 47 | * 下面表示在执行F时,先执行G,并且执行F时使用G的输出当作输入。 48 | * 相当于以下代码: 49 | * Integer a = g.apply(1); 50 | * System.out.println(f.apply(a)); 51 | */ 52 | System.out.println(f.compose(g).apply(1)); 53 | 54 | /** 55 | * 表示执行F的Apply后使用其返回的值当作输入再执行G的Apply; 56 | * 相当于以下代码 57 | * Integer a = f.apply(1); 58 | * System.out.println(g.apply(a)); 59 | */ 60 | System.out.println(f.andThen(g).apply(1)); 61 | 62 | /** 63 | * identity方法会返回一个不进行任何处理的Function,即输出与输入值相等; 64 | */ 65 | System.out.println(Function.identity().apply("a")); 66 | } 67 | 68 | 69 | 70 | /** 71 | * Predicate测试 72 | * Predicate为函数式接口,predicate的中文意思是“断定”,即判断的意思,判断某个东西是否满足某种条件; 73 | * 因此它包含test方法,根据输入值来做逻辑判断,其结果为True或者False。 74 | */ 75 | private static void predicateTest() { 76 | Predicate p = o -> o.equals("test"); 77 | Predicate g = o -> o.startsWith("t"); 78 | 79 | /** 80 | * negate: 用于对原来的Predicate做取反处理; 81 | * 如当调用p.test("test")为True时,调用p.negate().test("test")就会是False; 82 | */ 83 | Assert.assertFalse(p.negate().test("test")); 84 | 85 | /** 86 | * and: 针对同一输入值,多个Predicate均返回True时返回True,否则返回False; 87 | */ 88 | Assert.assertTrue(p.and(g).test("test")); 89 | 90 | /** 91 | * or: 针对同一输入值,多个Predicate只要有一个返回True则返回True,否则返回False 92 | */ 93 | Assert.assertTrue(p.or(g).test("ta")); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/datastructure/heap/Heap.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.datastructure.heap; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | /** 6 | * 堆 7 | * 堆就是一颗完全二叉树 8 | * 堆中每一个节点的值都必须大于等于(或者小于等于)其子树(左右子节点)中每个节点的值。 9 | * 堆顶存储的就是最大值或者最小值 10 | * 用数组存储非常节省存储空间,下标为id的节点的左子节点就是i*2的节点,右子节点的下标为i*2+1。父节点就是i/2的节点。 11 | * 12 | * @Author: liuxun 13 | * @CreateDate: 2019/1/31 上午10:30 14 | * @Version: 1.0 15 | */ 16 | public class Heap { 17 | private int[] data; 18 | private int count;//堆中元素的个数 19 | private int capacity;//堆容量 20 | 21 | /** 22 | * 初始化堆 23 | * @param capacity 24 | */ 25 | public Heap(int capacity){ 26 | this.capacity=capacity; 27 | data=new int[capacity]; 28 | count=0; 29 | } 30 | 31 | /** 32 | * 往堆中插入数据 33 | * 从下往上的方法堆化 34 | * @param d 35 | */ 36 | public void insert(int d){ 37 | if (count>=capacity) return;//堆满了 38 | count++;//从下标为1开始填充数据 39 | data[count]=d; 40 | int i=count; 41 | while (i/2>0 && data[i]>data[i/2]){ 42 | //交换数据 43 | swap(data,i,i/2); 44 | i=i/2;//切到父节点 45 | } 46 | } 47 | 48 | private static void swap(int[] a,int i,int n) { 49 | int temp=a[i]; 50 | a[i]=a[n]; 51 | a[n]=temp; 52 | } 53 | 54 | /** 55 | * 删除堆顶元素 56 | * 把最后一个元素放到对顶,然后从上到下的方法堆化。 57 | */ 58 | public void removeMax(){ 59 | data[1]=data[count]; 60 | count--; 61 | int i=1; 62 | heapify(data,count,i); 63 | } 64 | 65 | private static void buildHeap(int[] a, int n) { 66 | for (int i = n/2; i >= 1; --i) { 67 | heapify(a, n, i); 68 | } 69 | System.out.println(JSON.toJSONString(a)); 70 | } 71 | 72 | private static void heapify(int[] a, int n, int i) { 73 | while (true) { 74 | int maxPos = i; 75 | if (i*2 <= n && a[i] < a[i*2]) maxPos = i*2; 76 | if (i*2+1 <= n && a[maxPos] < a[i*2+1]) maxPos = i*2+1; 77 | if (maxPos == i) break; 78 | swap(a, i, maxPos); 79 | i = maxPos; 80 | } 81 | } 82 | 83 | // n 表示数据的个数,数组 a 中的数据从下标 1 到 n 的位置。 84 | public static void sort(int[] a, int n) { 85 | buildHeap(a, n);//构建堆 86 | int k = n; 87 | while (k > 1) { 88 | swap(a, 1, k);//堆顶跟最后一个元素交换 89 | --k;//每次k-1,也就去取出 90 | heapify(a, k, 1);//1-k堆化 91 | } 92 | System.out.println(JSON.toJSONString(a)); 93 | } 94 | 95 | 96 | public static void main(String[] args) { 97 | // Heap heap=new Heap(6); 98 | // for (int i=1;i<=5;i++){ 99 | // heap.insert(i); 100 | // } 101 | // System.out.println(heap.count); 102 | 103 | int[] d = new int[]{0, 5, 2, 1, 4, 3}; 104 | sort(d,d.length-1); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/java8/Hello4.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.java8; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Comparator; 6 | import java.util.List; 7 | import java.util.function.*; 8 | 9 | /** 10 | * Java8函数式接口-Predicate、Consumer、Function 11 | * Created by liuxun on 2017/7/11. 12 | */ 13 | public class Hello4 { 14 | public static void main(String[] args) { 15 | List listOfStrings= Arrays.asList("asdf","","132",newBean(()->new String("333"))); 16 | Predicate notempty = (String s) -> !s.isEmpty(); 17 | List nonEmpty = filter(listOfStrings, notempty); 18 | foreach(nonEmpty,(String s)-> System.out.println(s)); 19 | 20 | List listLength = map(listOfStrings, (String s) -> s.length()); 21 | foreach(listLength,(Integer i)-> System.out.println(i)); 22 | 23 | int num=5656; 24 | Thread t=new Thread(() -> System.out.println(num)); 25 | t.start(); 26 | } 27 | 28 | /** 29 | * Predicate定义了抽象方法test,代表函数描述符是(T)->boolean 30 | * @param params 31 | * @param predicate 32 | * @return 33 | */ 34 | public static List filter(List params,Predicate predicate){ 35 | List list=new ArrayList<>(); 36 | for (String str:params){ 37 | if (predicate.test(str)){ 38 | list.add(str); 39 | } 40 | } 41 | return list; 42 | } 43 | 44 | /** 45 | * Consumer定义了抽象方法accept,代表函数描述符是(T)->void 46 | * @param params 47 | * @param consumer 48 | * @param 49 | */ 50 | public static void foreach(List params, Consumer consumer){ 51 | for (T str:params){ 52 | consumer.accept(str); 53 | } 54 | } 55 | 56 | /** 57 | * Function定义了抽象方法apply,代表函数描述符是(T,R)->R 58 | * @param params 59 | * @param function 60 | * @return 61 | */ 62 | public static List map(List params, Function function){ 63 | List list=new ArrayList<>(); 64 | for (String str:params){ 65 | list.add(function.apply(str)); 66 | } 67 | return list; 68 | } 69 | 70 | /** 71 | * IntPredicate定义了抽象方法test,代表函数描述符是(int i)->boolean 72 | * @param params 73 | * @param intPredicate 74 | * @return 75 | */ 76 | public static List filterInt(List params,IntPredicate intPredicate){ 77 | List list=new ArrayList<>(); 78 | for (Integer i:params){ 79 | if (intPredicate.test(i)){ 80 | list.add(i); 81 | } 82 | } 83 | return list; 84 | } 85 | 86 | /** 87 | * Supplier定义了抽象方法get,代表函数描述符是()->T 88 | * @param supplier 89 | * @param 90 | * @return 91 | */ 92 | public static T newBean(Supplier supplier){ 93 | return supplier.get(); 94 | } 95 | 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/datastructure/heap/TopkCount.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.datastructure.heap; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | import java.util.PriorityQueue; 6 | 7 | /** 8 | * @Author: liuxun 9 | * @CreateDate: 2019/1/30 下午8:10 10 | * @Version: 1.0 11 | */ 12 | public class TopkCount { 13 | /** 14 | * 求数据中前K大数据 15 | * 16 | * @param data 17 | * @param k 18 | * @return 19 | */ 20 | public static int topk(int[] data, int k) { 21 | PriorityQueue queue = new PriorityQueue<>(k); 22 | 23 | for (int i = 0; i < data.length; i++) { 24 | if (queue.size() < k) { 25 | queue.offer(data[i]); 26 | } else { 27 | int value = queue.peek(); 28 | // 如果发现数据比堆顶元素大,则加入到小顶堆中 29 | if (data[i] > value) { 30 | queue.poll();//删除 31 | queue.offer(data[i]); 32 | } 33 | } 34 | } 35 | return queue.peek(); 36 | } 37 | 38 | /** 39 | * 手动实现堆然后查找topK 40 | * @param nums 41 | * @param k 42 | * @return 43 | */ 44 | public static int findKthLargest(int[] nums, int k) { 45 | //构建一个小顶堆数组 46 | int[] out = new int[k]; 47 | //小顶堆元素数量 48 | int count = 0; 49 | //循环处理数组 50 | for (int i=0;iout[0]){ 59 | out[0] = nums[i]; 60 | up2down(out,0); 61 | } 62 | } 63 | } 64 | return out[0]; 65 | } 66 | 67 | //从下向上调整,构建小顶堆 68 | public static void down2up(int[] nums,int i){ 69 | int parent = (i-1)/2; 70 | while(parent>=0&&nums[i] 2 | 5 | 4.0.0 6 | 7 | com.algorithm.study 8 | algorithm-study 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | fastjson 14 | com.alibaba 15 | 1.2.9 16 | 17 | 18 | 19 | cglib 20 | cglib 21 | 2.2.2 22 | 23 | 24 | 25 | 26 | org.testng 27 | testng 28 | 6.14.3 29 | 30 | 31 | 32 | 33 | com.google.guava 34 | guava 35 | 23.0 36 | 37 | 38 | 39 | commons-io 40 | commons-io 41 | 2.4 42 | 43 | 44 | 45 | org.projectlombok 46 | lombok 47 | 1.18.8 48 | provided 49 | 50 | 51 | 52 | joda-time 53 | joda-time 54 | 2.10.1 55 | 56 | 57 | 58 | org.apache.commons 59 | commons-lang3 60 | 3.9 61 | 62 | 63 | 64 | 65 | 66 | 67 | org.apache.maven.plugins 68 | maven-compiler-plugin 69 | 3.3 70 | 71 | 1.8 72 | 1.8 73 | UTF-8 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/nio/SocketChannelTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.nio; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | import java.nio.ByteBuffer; 6 | import java.nio.channels.SelectionKey; 7 | import java.nio.channels.Selector; 8 | import java.nio.channels.SocketChannel; 9 | import java.nio.charset.Charset; 10 | import java.util.Scanner; 11 | 12 | /** 13 | * @author liuxun 14 | * @version V1.0 15 | * @Description: Nio SocketChannel 16 | * @date 2017/12/6 17 | */ 18 | public class SocketChannelTest { 19 | //定义检测SocketChannel的Selector对象 20 | private Selector selector=null; 21 | //定义处理编码和解码的字符集 22 | private Charset charset=Charset.forName("UTF-8"); 23 | //客户端SocketChannel 24 | private SocketChannel sc=null; 25 | public void init() throws IOException{ 26 | selector=Selector.open(); 27 | InetSocketAddress isa=new InetSocketAddress("127.0.0.1",30000); 28 | //调用open静态方法创建连接到指定主机的SocketChannel 29 | sc=SocketChannel.open(isa); 30 | //设置该sc以非阻塞方式工作 31 | sc.configureBlocking(false); 32 | //将Socketchannel对象注册到指定Selector 33 | sc.register(selector, SelectionKey.OP_READ); 34 | //启动读取服务器端数据的线程 35 | new ClientThread().start(); 36 | //创建键盘输入流 37 | Scanner scan=new Scanner(System.in); 38 | while(scan.hasNextLine()){ 39 | //读取键盘输入 40 | String line=scan.nextLine(); 41 | //将键盘输入的内容输出到SocketChannel中 42 | sc.write(charset.encode("libai:"+line)); 43 | } 44 | } 45 | //定义读取服务器数据的线程 46 | private class ClientThread extends Thread{ 47 | @Override 48 | public void run(){ 49 | try{ 50 | while(selector.select()>0){ 51 | //遍历每个有可用IO操作Channel对应的SelectionKey 52 | for(SelectionKey sk:selector.selectedKeys()){ 53 | //删除正在处理的SelectionKey 54 | selector.selectedKeys().remove(sk); 55 | //如果该SelectionKey对应的Channel中有可读的数据 56 | if(sk.isReadable()){ 57 | //使用NIO读取channel中的数据 58 | SocketChannel sc=(SocketChannel) sk.channel(); 59 | ByteBuffer buff=ByteBuffer.allocate(1024); 60 | String content=""; 61 | while(sc.read(buff)>0){ 62 | //sc.read(buff); 63 | buff.flip(); 64 | content+=charset.decode(buff); 65 | } 66 | //打印输出读取的内容 67 | System.out.println(content); 68 | //为下一次读取做准备 69 | sk.interestOps(SelectionKey.OP_READ); 70 | } 71 | } 72 | } 73 | }catch(IOException ex){ 74 | ex.printStackTrace(); 75 | } 76 | } 77 | } 78 | public static void main(String[] args) throws IOException { 79 | new SocketChannelTest().init(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/atomic/AtomicStampedReferenceDemo.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.atomic; 2 | 3 | import java.util.concurrent.atomic.AtomicStampedReference; 4 | 5 | /** 6 | * 因为CAS需要在操作值的时候,检查值有没有发生变化,如果没有发生变化 7 | 则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它 8 | 的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面 9 | 追加上版本号,每次变量更新的时候把版本号加1,那么A→B→A就会变成1A→2B→3A。从 10 | Java 1.5开始,JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个 11 | 类的compareAndSet方法的作用是首先检查当前引用是否等于预期引用,并且检查当前标志是 12 | 否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。 13 | 14 | AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起 15 | 来,可用于原子的更新数据和数据的版本号,可以解决使用CAS进行原子更新时可能出现的 16 | ABA问题。 17 | * Created by liuxun on 2017/6/13. 18 | */ 19 | public class AtomicStampedReferenceDemo { 20 | static AtomicStampedReference money = new AtomicStampedReference( 21 | 19, 0); 22 | 23 | public static void main(String[] args) 24 | { 25 | for (int i = 0; i < 3; i++) 26 | { 27 | final int timestamp = money.getStamp(); 28 | new Thread() 29 | { 30 | public void run() 31 | { 32 | while (true) 33 | { 34 | while (true) 35 | { 36 | Integer m = money.getReference(); 37 | if (m < 20) 38 | { 39 | if (money.compareAndSet(m, m + 20, timestamp, 40 | timestamp + 1)) 41 | { 42 | System.out.println("充值成功,余额:" 43 | + money.getReference()); 44 | break; 45 | } 46 | } 47 | else 48 | { 49 | break; 50 | } 51 | } 52 | } 53 | }; 54 | }.start(); 55 | } 56 | 57 | new Thread() 58 | { 59 | public void run() 60 | { 61 | for (int i = 0; i < 100; i++) 62 | { 63 | while (true) 64 | { 65 | int timestamp = money.getStamp(); 66 | Integer m = money.getReference(); 67 | if (m > 10) 68 | { 69 | if (money.compareAndSet(m, m - 10, timestamp, 70 | timestamp + 1)) 71 | { 72 | System.out.println("消费10元,余额:" 73 | + money.getReference()); 74 | break; 75 | } 76 | }else { 77 | break; 78 | } 79 | } 80 | try 81 | { 82 | Thread.sleep(100); 83 | } 84 | catch (Exception e) 85 | { 86 | e.printStackTrace(); 87 | } 88 | } 89 | }; 90 | }.start(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/java8/Hello5.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.java8; 2 | 3 | import java.util.*; 4 | import java.util.function.BiFunction; 5 | import java.util.function.Function; 6 | import java.util.function.Predicate; 7 | import java.util.function.Supplier; 8 | 9 | /** 10 | * 方法引用 11 | * Created by liuxun on 2017/7/11. 12 | */ 13 | public class Hello5 { 14 | 15 | public static void main(String[] args) { 16 | List str= Arrays.asList("a","b","D","c","f"); 17 | // str.sort((String o1,String o2)->o1.compareToIgnoreCase(o2)); 18 | str.sort(String::compareToIgnoreCase); 19 | str.forEach((String s)-> System.out.println(s)); 20 | 21 | //实例化对象-调用构造方法 22 | BiFunction a=Apple::new; 23 | Apple apple = a.apply("red",222); 24 | System.out.println(apple.getColor()); 25 | 26 | List we=Arrays.asList(1,2,3,4,5,6); 27 | map(we,Apple::new); 28 | 29 | List appleList=new ArrayList<>(); 30 | appleList.add(new Apple("red",110)); 31 | appleList.add(new Apple("green",110)); 32 | appleList.add(new Apple("blue",200)); 33 | appleList.sort(Comparator.comparing(Apple::getWeight).reversed().thenComparing(Apple::getColor).reversed()); 34 | appleList.forEach((Apple apple1)-> System.out.println(apple1.getColor()+":"+apple1.getWeight())); 35 | System.out.println("————————————————————————————————"); 36 | Predicate preWeight=(Apple k)->k.getWeight()>110; 37 | // Predicate negateApple=preWeight.negate(); 38 | Predicate red=preWeight.and((Apple k)->k.getColor().equals("blue")).or(k->k.getColor().equals("red")); 39 | List listRe = filter(appleList, preWeight.negate()); 40 | listRe.forEach(ab-> System.out.println(ab.getColor()+":"+ab.getWeight())); 41 | System.out.println("————————————————————————————————"); 42 | Function f=(x)->x+1; 43 | Function g=(x)->x*2; 44 | Function h=f.andThen(g);//先执行f然后执行g 45 | System.out.println(h.apply(1)); 46 | 47 | Function r=f.compose(g);//先执行g然后执行f 48 | System.out.println(r.apply(1)); 49 | System.out.println("————————————————————————————————"); 50 | Apple ap=new Apple("green",22); 51 | Predicate isGreenApple=Apple::isGreenApple;//指向静态方法的方法引用 此方法只能是static 52 | System.out.println(isGreenApple.test(ap)); 53 | Predicate isHeavyApple=ap::isHeavyApple;//指向现有对象的实例方法的方法引用 此方法不能是static修饰的 54 | 55 | System.out.println(isHeavyApple.test(ap)); 56 | Function function=Integer::intValue; 57 | System.out.println(function.apply(456465));//指向任意类型实例方法的方法引用 58 | 59 | 60 | 61 | } 62 | public static List map(List list, 63 | Function f){ 64 | List result = new ArrayList<>(); 65 | for(Integer e: list){ 66 | result.add(f.apply(e)); 67 | } 68 | return result; 69 | } 70 | public static List filter(List params,Predicate predicate){ 71 | List list=new ArrayList<>(); 72 | for (T b:params){ 73 | if (predicate.test(b)){ 74 | list.add(b); 75 | } 76 | } 77 | return list; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/greedyalgorithm/Solutions.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm.greedyalgorithm; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.PriorityQueue; 6 | 7 | /** 8 | * @author liuxun 9 | * @title: Solutions 10 | * @projectName algorithm-study 11 | * @description: 零钱支付问题 12 | * 假设我们有 1 元、2 元、5 元、10 元、20 元、50 元、100 元这些面额的纸币, 13 | * 它们的张数分别是 c1、c2、c5、c10、c20、c50、c100。 14 | * 我们现在要用这些钱来支付 K 元,最少要用多少张纸币呢? 15 | * 先用面值最大的来支付,如果不够,就继续用更小一点面值的,以此类推,最后剩下的用 1 元来补齐。 16 | * @date 2019/11/14 17:20 17 | */ 18 | public class Solutions { 19 | /** 20 | * 用于存储金额的信息,根据金额从大到小排序 21 | */ 22 | public PriorityQueue moneyQueue = 23 | new PriorityQueue<>( 24 | (o1, o2) -> { 25 | if (o1.getMemory() < o2.getMemory()) { 26 | return 1; 27 | } else if (o1.getMemory() > o2.getMemory()) { 28 | return -1; 29 | } 30 | return 0; 31 | }); 32 | 33 | /** 34 | * 添加金额信息 35 | * @param value 面值信息 36 | * @param num 张数 37 | * @param memory 金额值 38 | */ 39 | public void addMemoryInfo(String value, int num, int memory) { 40 | moneyQueue.offer(new MoneyBusi(value, num, memory)); 41 | } 42 | 43 | /** 44 | * 计算找零钱的问题 45 | * 46 | * @param money 找零的金额信息 47 | * @return 找零钱的信息 48 | */ 49 | public List looseChange(int money) { 50 | 51 | List resultMemory = new ArrayList<>(); 52 | 53 | List moreMemory = new ArrayList<>(); 54 | 55 | int surplus = money; 56 | 57 | while (surplus > 0) { 58 | //返回队列头部元素 59 | MoneyBusi busi = moneyQueue.peek(); 60 | if (null != busi) { 61 | System.out.println("当前金额:"+busi.getMemory()); 62 | if (busi.getMemory() <= surplus) { 63 | busi = moneyQueue.poll(); 64 | surplus = surplus - busi.getMemory(); 65 | 66 | MoneyBusi busiNew = new MoneyBusi(busi.getValue(), 1, busi.getMemory()); 67 | resultMemory.add(busiNew); 68 | 69 | busi.setNum(busi.getNum() - 1); 70 | 71 | if (busi.getNum() > 0) { 72 | moneyQueue.offer(busi); 73 | } 74 | } else { 75 | moreMemory.add(moneyQueue.poll()); 76 | } 77 | } else { 78 | break; 79 | } 80 | } 81 | moneyQueue.addAll(moreMemory); 82 | return resultMemory; 83 | } 84 | 85 | public static void main(String[] args) { 86 | Solutions instance = new Solutions(); 87 | instance.addMemoryInfo("100元", 2, 100); 88 | instance.addMemoryInfo("50元", 2, 50); 89 | instance.addMemoryInfo("20元", 2, 20); 90 | instance.addMemoryInfo("10元", 2, 10); 91 | instance.addMemoryInfo("5元", 2, 5); 92 | instance.addMemoryInfo("2元", 2, 2); 93 | instance.addMemoryInfo("1元", 5, 1); 94 | System.out.println(instance.moneyQueue); 95 | List list = instance.looseChange(332); 96 | for (MoneyBusi busi : list) { 97 | System.out.println(busi); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/datastructure/graph/Mgraph.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.datastructure.graph; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | /** 7 | * 图 8 | * @Author: liuxun 9 | * @CreateDate: 2019/2/21 上午10:40 10 | * @Version: 1.0 11 | */ 12 | public class Mgraph { 13 | private int v;//顶点的个数 14 | private LinkedList adj[];//邻接表 15 | 16 | public Mgraph(int capaCity){ 17 | v=capaCity; 18 | adj=new LinkedList[capaCity]; 19 | for (int i=0;i(); 21 | } 22 | } 23 | 24 | /** 25 | * 添加数据 26 | * @param oSide 27 | * @param rSide 28 | */ 29 | private void add(int oSide,int rSide){ 30 | adj[oSide].add(rSide); 31 | adj[rSide].add(oSide); 32 | } 33 | 34 | /** 35 | * 构造一个无向图 36 | */ 37 | private void createGraph() { 38 | // 0 -- 1 -- 2 39 | // | | | 40 | // 3 -- 4 -- 5 41 | // | | | 42 | // 6 -- 7 -- 8 43 | add(0,1);//add(1,0); 44 | add(0,3);//add(3,0); 45 | 46 | add(1,2);//add(2,1); 47 | add(1,4);// add(4,1); 48 | 49 | add(2,5);//add(5,2); 50 | 51 | add(3,4);//add(4,3); 52 | add(3,6);//add(6,3); 53 | 54 | add(4,5);//add(5,4); 55 | add(4,7);// add(7,4); 56 | 57 | add(5,8);//add(8,5); 58 | 59 | add(6,7);//add(7,6); 60 | 61 | add(7,8);//add(8,7); 62 | } 63 | private void print(int[] prev, int oSide, int rSide) { 64 | if (prev[rSide] != -1 && oSide != rSide) { 65 | print(prev, oSide, prev[rSide]); 66 | } 67 | System.out.print(rSide + " "); 68 | } 69 | 70 | /** 71 | * 广度优先搜索,从字面意思理解,它就是一种“地毯式”的搜索策略,先查找离起始顶点最近的,然后是次近的,依次往外搜索,层层递进。 72 | * 73 | * 在这里三个重要的核心辅助变量 visited、queue、prev。 74 | * visited 记录已经被访问的顶点,避免顶点被重复访问 75 | * queue 用来存储已经被访问、但相连的顶点还没有被访问的顶点的这样的一个队列。 76 | * prev 记录搜索路径,它是反向存储,便于后续正向打印输出图的路径。 77 | * @param oSide 78 | * @param rSide 79 | */ 80 | private void bfs(int oSide, int rSide) { 81 | if (oSide == rSide) return; 82 | 83 | boolean[] visited = new boolean[v]; 84 | visited[oSide] = true; 85 | Queue queue = new LinkedList<>(); 86 | queue.offer(oSide); 87 | int[] prev = new int[v]; 88 | for (int i = 0; i < v; i++) { 89 | prev[i] = -1; 90 | } 91 | while (!queue.isEmpty()) { 92 | int index = queue.poll(); 93 | for (int j = 0; j < adj[index].size(); j++) { 94 | int value = adj[index].get(j); 95 | if (!visited[value]) { 96 | prev[value] = index; 97 | if (value == rSide) { 98 | print(prev, oSide, rSide); 99 | } 100 | visited[value] = true; 101 | queue.offer(value); 102 | } 103 | } 104 | } 105 | } 106 | 107 | public static void main(String[] args) { 108 | int count = 9; 109 | Mgraph graph = new Mgraph(count); 110 | // 0 -- 1 -- 2 111 | // | | | 112 | // 3 -- 4 -- 5 113 | // | | | 114 | // 6 -- 7 -- 8 115 | graph.createGraph(); 116 | System.out.println("BFS(广度优先搜索)"); 117 | graph.bfs(0,6); 118 | 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/algorithm/StringSolution.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.algorithm; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | /** 7 | * 字符串算法系列 8 | * @Author: liuxun 9 | * @CreateDate: 2019/3/19 下午2:26 10 | * @Version: 1.0 11 | */ 12 | public class StringSolution { 13 | /** 14 | * 判断一个字符串是否在另外一个字符串中,并返回出现的位置 15 | * @param src 16 | * @param dst 17 | * @return 18 | */ 19 | public static int indexOf(String src,String dst){ 20 | if (null==src || null==dst || src.length()<1 || dst.length()<1 || dst.length() objects = new HashSet<>(); 87 | for (String w:words){ 88 | StringBuilder sb=new StringBuilder(); 89 | char[] chars = w.toCharArray(); 90 | for (char aChar : chars) { 91 | sb.append(m[aChar-'a']); 92 | } 93 | System.out.println("密码为:"+sb); 94 | objects.add(sb.toString()); 95 | } 96 | return objects.size(); 97 | } 98 | 99 | public static void main(String[] args) { 100 | // System.out.println(StringSolution.indexOf("ab","asdkfjasldjfab")); 101 | // System.out.println("asdkfjasldjfab".indexOf("ab")); 102 | 103 | // System.out.println(StringSolution.toLowerCase("ccccccccccBB")); 104 | System.out.println(StringSolution.reverseString("abc".toCharArray())); 105 | System.out.println(StringSolution.uniqueMorseRepresentations(new String[]{"abc","cba"})); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/datastructure/linear/MyArrayList.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.datastructure.linear; 2 | 3 | /** 4 | * 线性表的顺序存储结构 5 | * 优点:可以快速的存取表中的任意元素;无须为表中元素之间的逻辑关系而增加额外的存储空间。 6 | * 缺点:插入和删除操作需要移动大量元素;当线性表长度变化较大时,难以确定存储空间容量;造成存储空间的碎片。 7 | * Created by liuxun on 2017/6/14. 8 | */ 9 | public class MyArrayList{ 10 | 11 | private Object[] data;//数组存储数据元素 12 | private int size; //线性表当前的长度size,数据元素的个数,是变化的,长度小于等于数组的长度 13 | private final static int DEFAULT_CAPACITY=16;//数组默认长度,存放线性表的存储空间长度 14 | 15 | public MyArrayList(int capacity){ 16 | this.data=new Object[Math.abs(capacity)]; 17 | this.size=0; 18 | } 19 | /** 20 | * 初始化数组,长度为16 21 | */ 22 | public MyArrayList(){ 23 | this(DEFAULT_CAPACITY); 24 | } 25 | 26 | /** 27 | * 根据下标获取元素 28 | * @param index 29 | * @return 30 | */ 31 | public E getElem(int index){ 32 | if (data.length==0 || index<0 || index>data.length){ 33 | return null; 34 | } 35 | return (E) data[index]; 36 | } 37 | 38 | /** 39 | * 设置index位置的对象为element 40 | * @param index 41 | * @param element 42 | * @return 43 | */ 44 | public E setElem(int index, Object element) { 45 | if (index<0 || index>=size){ 46 | throw new RuntimeException("数组越界 index:"+index+",size:"+size); 47 | } 48 | E old=(E)data[index]; 49 | data[index]=element; 50 | return old; 51 | } 52 | 53 | /** 54 | * 在index位置插入element对象,后面的元素需要后移 55 | * @param index 56 | * @param element 57 | * @return 58 | */ 59 | public boolean addElem(int index, Object element) { 60 | if (size==data.length){//如果数组已经满了需要扩容,每次扩两倍。 61 | Object[] temp=data; 62 | data=new Object[temp.length*2]; 63 | for (int i=0;isize){ 68 | throw new RuntimeException("数组越界 index:"+index+",size:"+size); 69 | } 70 | //元素后移 71 | for (int k=size-1;k>=index;k--){ 72 | data[k+1]=data[k]; 73 | } 74 | //插入新元素 75 | data[index]=element; 76 | size++; 77 | return true; 78 | } 79 | 80 | /** 81 | * 在末尾添加元素 82 | * @param element 83 | * @return 84 | */ 85 | public boolean add(Object element) { 86 | return this.addElem(size,element); 87 | } 88 | 89 | /** 90 | * 删除下标index的元素 91 | * 该下标后的元素需要前移 92 | * @param index 93 | * @return 94 | */ 95 | public boolean delElem(int index) { 96 | if (index<0 || index>=size){ 97 | throw new RuntimeException("数组越界 index:"+index+",size:"+size); 98 | } 99 | for(int k=index;k0) { 126 | for (int k = 0; k < size - 1; k++) { 127 | data[k] = null; 128 | } 129 | size=0; 130 | } 131 | return true; 132 | } 133 | 134 | /** 135 | * 返回线性表长度 136 | * @return 137 | */ 138 | public int size() { 139 | return size; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/LRUCache/LRUCache.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.LRUCache; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * LRU缓存链表实现思路 8 | * 每次写入数据时将数据放入链表头结点。 9 | * 使用数据时候将数据移动到头结点。 10 | * 缓存数量超过阈值时移除链表尾部数据。 11 | * @Author: liuxun 12 | * @CreateDate: 2018/7/12 下午6:05 13 | * @Version: 1.0 14 | */ 15 | public class LRUCache { 16 | class Node{ 17 | private int key; 18 | private int value; 19 | private Node prev; 20 | private Node next; 21 | 22 | public Node(int key,int value){ 23 | this.key=key; 24 | this.value=value; 25 | } 26 | public Node(){} 27 | 28 | public int getKey() { 29 | return key; 30 | } 31 | 32 | public void setKey(int key) { 33 | this.key = key; 34 | } 35 | 36 | public int getValue() { 37 | return value; 38 | } 39 | 40 | public void setValue(int value) { 41 | this.value = value; 42 | } 43 | } 44 | private void moveToHead(Node node){ 45 | remove(node); 46 | addNode(node); 47 | } 48 | //删除尾节点 49 | private Node popTail(){ 50 | Node prevNode= tail.prev; 51 | tail.prev=prevNode.prev; 52 | prevNode.prev.next=tail; 53 | 54 | prevNode.next=null; 55 | prevNode.prev=null; 56 | 57 | size--; 58 | return prevNode; 59 | } 60 | //删除中间节点 61 | private void remove(Node node){ 62 | Node prevNode=node.prev; 63 | Node nextNode=node.next; 64 | 65 | prevNode.next=nextNode; 66 | nextNode.prev=prevNode; 67 | 68 | node.next=null; 69 | node.prev=null; 70 | 71 | size--; 72 | } 73 | //添加节点 74 | private void addNode(Node node){ 75 | node.next=head.next; 76 | node.prev=head; 77 | node.next.prev=node; 78 | head.next=node; 79 | size++; 80 | } 81 | private Map cache=new HashMap(); 82 | private int size=0; 83 | private int capacity=0; 84 | //头结点 85 | private Node head; 86 | //尾结点 87 | private Node tail; 88 | public LRUCache(int capacity) { 89 | this.capacity=capacity; 90 | //初始化头尾节点 91 | this.head=new Node(); 92 | this.tail=new Node(); 93 | head.next=tail; 94 | tail.prev=head; 95 | } 96 | 97 | public int get(int key) { 98 | //从缓存获取 99 | Node node=cache.get(key); 100 | if(null==node){ 101 | return -1; 102 | } 103 | //数据移到头结点 104 | moveToHead(node); 105 | return node.value; 106 | } 107 | 108 | public void put(int key, int value) { 109 | Node node=cache.get(key); 110 | if(null==node){ 111 | node=new Node(key,value); 112 | //写入新节点至头节点 113 | addNode(node); 114 | cache.put(key,node); 115 | //如果容量已满,删除尾节点 116 | if(size>capacity){ 117 | //删除尾节点 118 | Node delNode=popTail(); 119 | cache.remove(delNode.key); 120 | } 121 | }else{ 122 | //数据更新并移到头结点 123 | node.value=value; 124 | moveToHead(node); 125 | } 126 | } 127 | 128 | @Override 129 | public String toString() { 130 | StringBuilder sb = new StringBuilder() ; 131 | for (Node node = head;node!=null;node=node.next){ 132 | sb.append(node.getKey()).append(":") 133 | .append(node.getValue()) 134 | .append("-->"); 135 | } 136 | return sb.toString(); 137 | } 138 | public static void main(String[] args) { 139 | LRUCache lruMap=new LRUCache(2); 140 | lruMap.put(1,1); 141 | lruMap.put(2,2); 142 | lruMap.get(1); 143 | lruMap.put(3,3); 144 | lruMap.get(2); 145 | lruMap.put(4,4); 146 | lruMap.get(1); 147 | lruMap.get(3); 148 | lruMap.get(4); 149 | System.out.println(lruMap.toString()); 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/study/demo/datastructure/linear/Solution.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.study.demo.datastructure.linear; 2 | 3 | /** 4 | * 单链表链表算法题 5 | * @Author: liuxun 6 | * @CreateDate: 2019/2/12 下午3:43 7 | * @Version: 1.0 8 | */ 9 | public class Solution { 10 | 11 | /** 12 | * 环形链表检测 13 | * @param head 14 | * @return 15 | */ 16 | public static ListNode detectCycle(ListNode head) { 17 | ListNode temp=head; 18 | ListNode temp2=head; 19 | while(temp!=null && temp.next.next!=null){ 20 | //通过快慢指针遍历 21 | temp2=temp2.next.next; 22 | temp=temp.next; 23 | if (temp==temp2){ 24 | //寻找环形入口 25 | ListNode q = head; 26 | while(temp2!=q){ 27 | temp2=temp2.next; 28 | q=q.next; 29 | } 30 | return q; 31 | } 32 | } 33 | return null; 34 | } 35 | 36 | /*** 37 | * 单链表的前K个的逆序输出 38 | * 39 | */ 40 | public static void reversedTopK(ListNode head,int k){ 41 | if (head==null || head.next==null){ 42 | return; 43 | } 44 | printNode(head); 45 | int count=1; 46 | ListNode p1=head; 47 | ListNode p2=head.next; 48 | ListNode p3=null; 49 | while (count"); 116 | } 117 | } 118 | 119 | public static void main(String[] args) { 120 | ListNode head=new ListNode(3); 121 | ListNode head0=new ListNode(1); 122 | 123 | ListNode head1=new ListNode(2); 124 | ListNode head2=new ListNode(-4); 125 | 126 | // head.next=head0; 127 | // head0.next=head1; 128 | // head1.next=head2; 129 | // head2.next=head1; 130 | // ListNode c=Solution.detectCycle(head); 131 | // System.out.println(c==null?-1:1); 132 | 133 | head.next=head0; 134 | head0.next=head1; 135 | head1.next=head2; 136 | head2.next=null; 137 | // Solution.reverseLinkedList(head); 138 | // Solution.reversedTopK(head,2); 139 | 140 | Solution.findKthToTail(head,2); 141 | } 142 | } 143 | --------------------------------------------------------------------------------