├── .gitignore ├── README.md ├── _config.yml ├── note ├── 18 │ └── README.md ├── 50 │ └── README.md ├── 01 │ └── README.md ├── 02 │ └── README.md ├── 03 │ └── README.md └── 06 │ └── README.md └── src ├── _01 └── AssignmentOperator.java ├── _02 ├── Singleton1.java ├── Singleton2.java ├── Singleton3.java ├── Singleton4.java └── Singleton5.java ├── _03 └── DuplicationInArray.java ├── _04 └── FindInPartiallySortedMatrix.java ├── _05 └── ReplaceSpaces.java ├── _06 └── PrintListInReversedOrder.java ├── _07 └── ConstructBinaryTree.java ├── _08 └── NextNodeInBinaryTrees.java ├── _09 ├── QueueWithTwoStacks.java ├── StackWithOneQueue.java └── StackWithTwoQueues.java ├── _10 └── Fibonacci.java ├── _11 └── MinNumberInRotatedArray.java ├── _14 └── CuttingRope.java ├── _15 └── NumberOf1InBinary.java ├── _18 ├── DeleteDuplicatedNode.java └── DeleteNodeInList.java ├── _19 └── RegularExpressionsMatching.java ├── _21 └── ReorderArray.java ├── _22 └── KthNodeFromEnd.java ├── _23 └── EntryNodeInListLoop.java ├── _24 └── ReverseList.java ├── _25 └── MergeSortedLists.java ├── _26 └── SubstructureInTree.java ├── _27 └── MirrorOfBinaryTree.java ├── _28 └── SymmetricalBinaryTree.java ├── _30 └── MinInStack.java ├── _31 └── StackPushPopOrder.java ├── _32 ├── PrintTreeFromTopToBottom.java ├── PrintTreesInLines.java └── PrintTreesInZigzag.java ├── _33 └── SequenceOfBST.java ├── _34 └── PathInTree.java ├── _37 └── SerializeBinaryTrees.java ├── _39 └── MoreThanHalfNumber.java ├── _40 └── KLeastNumbers.java ├── _41 └── StreamMedian.java ├── _42 └── GreatestSumOfSubArrays.java ├── _45 └── SortArrayForMinNumber.java ├── _46 └── TranslateNumbersToStrings.java ├── _47 └── MaxValueOfGifts.java ├── _48 └── LongestSubstringWithoutDup.java ├── _50 ├── FirstCharacterInStream.java └── FirstNotRepeatingChar.java ├── _51 └── InversePairs.java ├── _52 └── FirstCommonNodesInLists.java ├── _53 ├── MissingNumber.java └── NumberOfK.java ├── _54 └── KthNodeInBST.java ├── _55 ├── BalancedBinaryTree.java └── TreeDepth.java ├── _56 ├── NumbersAppearOnce.java └── NumbersAppearingOnce.java ├── _58 ├── LeftRotateString.java └── ReverseWordsInSentence.java ├── _59 └── MaxInSlidingWindow.java ├── _65 ├── AddTwoNumbers.java └── ExchangeTwoNumbers.java └── structure ├── BinaryTree.java ├── ListNode.java └── TreeNode.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | *.log 4 | 5 | hs_err_pid* 6 | 7 | .classpath 8 | .project 9 | .settings/ 10 | 11 | *.iml 12 | *.idea 13 | 14 | .vscode/ 15 | 16 | target/ 17 | out/ 18 | build/ 19 | bin/ 20 | 21 | .DS_Store 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # coding-interview-java 2 | 3 | 《剑指 Offer》第二版 Java 实现 4 | 5 | ## 参考 6 | 7 | * https://github.com/zhedahht/CodingInterviewChinese2 8 | * https://github.com/ryderchan/point-to-offer-edition2 9 | 10 | ## 题目 11 | * [面试题 1:赋值运算符函数](./note/01) 12 | * [面试题 2:实现 Singleton 模式](./note/02) 13 | * [面试题 3:找出数组中重复的数字](./src/_03/DuplicationInArray.java) 14 | * [面试题 4:二维数组中的查找](./src/_04/FindInPartiallySortedMatrix.java) 15 | * [面试题 5:替换空格](./src/_05/ReplaceSpaces.java) 16 | * [面试题 6:从尾到头打印链表](./src/_06/PrintListInReversedOrder.java) 17 | * [面试题 7:重建二叉树](./src/_07/ConstructBinaryTree.java) 18 | * [面试题 8:二叉树的下一个结点](./src/_08/NextNodeInBinaryTrees.java) 19 | * [面试题 9:用两个栈实现队列](./src/_09/QueueWithTwoStacks.java) 20 | * [面试题 10:斐波那契数列](./src/_10/Fibonacci.java) 21 | * [面试题 11:旋转数组的最小数字](./src/_11/MinNumberInRotatedArray.java) 22 | * 面试题 12:矩阵中的路径 23 | * 面试题 13:机器人的运动范围 24 | * [面试题 14:剪绳子](./src/_14/CuttingRope.java) 25 | * [面试题 15:二进制中 1 的个数](./src/_15/NumberOf1InBinary.java) 26 | * 面试题 16:数值的整数次方 27 | * 面试题 17:打印 1 到最大的 n 位数 28 | * [面试题 18-1:在 O(1) 时间删除链表结点](./src/_18/DeleteNodeInList.java) 29 | * [面试题 18-2:删除链表中重复的结点](./src/_18/DeleteDuplicatedNode.java) 30 | * [面试题 19:正则表达式匹配](./src/_19/RegularExpressionsMatching.java) 31 | * 面试题 20:表示数值的字符串 32 | * [面试题 21:调整数组顺序使奇数位于偶数前面](./src/_21/ReorderArray.java) 33 | * [面试题 22:链表中倒数第 k 个结点](./src/_22/KthNodeFromEnd.java) 34 | * [面试题 23:链表中环的入口结点](./src/_23/EntryNodeInListLoop.java) 35 | * [面试题 24:反转链表](./src/_24/ReverseList.java) 36 | * [面试题 25:合并两个排序的链表](./src/_25/MergeSortedLists.java) 37 | * [面试题 26:树的子结构](./src/_26/SubstructureInTree.java) 38 | * [面试题 27:二叉树的镜像](./src/_27/MirrorOfBinaryTree.java) 39 | * [面试题 28:对称的二叉树](./src/_28/SymmetricalBinaryTree.java) 40 | * 面试题 29:顺时针打印矩阵 41 | * [面试题 30:包含min函数的栈](./src/_30/MinInStack.java) 42 | * [面试题 31:栈的压入、弹出序列](./src/_31/StackPushPopOrder.java) 43 | * [面试题 32-1:不分行从上往下打印二叉树](./src/_32/PrintTreeFromTopToBottom.java) 44 | * [面试题 32-2:分行从上到下打印二叉树](./src/_32/PrintTreesInLines.java) 45 | * [面试题 32-3:之字形打印二叉树](./src/_32/PrintTreesInZigzag.java) 46 | * [面试题 33:二叉搜索树的后序遍历序列](./src/_33/SequenceOfBST.java) 47 | * [面试题 34:二叉树中和为某一值的路径](./src/_34/PathInTree.java) 48 | * 面试题 35:复杂链表的复制 49 | * 面试题 36:二叉搜索树与双向链表 50 | * [面试题 37:序列化二叉树](./src/_37/SerializeBinaryTrees.java) 51 | * 面试题 38:字符串的排列 52 | * [面试题 39:数组中出现次数超过一半的数字](./src/_39/MoreThanHalfNumber.java) 53 | * [面试题 40:最小的 k 个数](./src/_40/KLeastNumbers.java) 54 | * [面试题 41:数据流中的中位数](./src/_41/StreamMedian.java) 55 | * [面试题 42:连续子数组的最大和](./src/_42/GreatestSumOfSubArrays.java) 56 | * 面试题 43:从 1 到 n 整数中 1 出现的次数 57 | * 面试题 44:数字序列中某一位的数字 58 | * [面试题 45:把数组排成最小的数](./src/_45/SortArrayForMinNumber.java) 59 | * [面试题 46:把数字翻译成字符串](./src/_46/TranslateNumbersToStrings.java) 60 | * [面试题 47:礼物的最大价值](./src/_47/MaxValueOfGifts.java) 61 | * [面试题 48:最长不含重复字符的子字符串](./src/_48/LongestSubstringWithoutDup.java) 62 | * 面试题 49:丑数 63 | * [面试题 50-1:字符串中第一个只出现一次的字符](./src/_50/FirstNotRepeatingChar.java) 64 | * [面试题 50-2:字符流中第一个只出现一次的字符](./src/_50/FirstCharacterInStream.java) 65 | * [面试题 51:数组中的逆序对](./src/_51/InversePairs.java) 66 | * [面试题 52:两个链表的第一个公共结点](./src/_52/FirstCommonNodesInLists.java) 67 | * [面试题 53-1:数字在排序数组中出现的次数](./src/_53/NumberOfK.java) 68 | * [面试题 53-2:0 到 n-1 中缺失的数字](./src/_53/MissingNumber.java) 69 | * 面试题 53-3:数组中数值和下标相等的元素 70 | * [面试题 54:二叉搜索树的第 k 个结点](./src/_54/KthNodeInBST.java) 71 | * [面试题 55-1:二叉树的深度](./src/_55/TreeDepth.java) 72 | * [面试题 55-2:平衡二叉树](./src/_55/BalancedBinaryTree.java) 73 | * [面试题 56-1:数组中只出现一次的两个数字](./src/_56/NumbersAppearOnce.java) 74 | * [面试题 56-2:数组中唯一只出现一次的数字](./src/_56/NumbersAppearingOnce.java) 75 | * 面试题 57-1:和为 s 的两个数字 76 | * 面试题 57-2:和为 s 的连续正数序列 77 | * [面试题 58-1:翻转单词顺序](./src/_58/ReverseWordsInSentence.java) 78 | * [面试题 58-2:左旋转字符串](./src/_58/LeftRotateString.java) 79 | * [面试题 59-1:滑动窗口的最大值](./src/_59/MaxInSlidingWindow.java) 80 | * 面试题 59-2:队列的最大值 81 | * 面试题 60:n 个骰子的点数 82 | * 面试题 61:扑克牌的顺子 83 | * 面试题 62:圆圈中最后剩下的数字 84 | * 面试题 63:股票的最大利润 85 | * 面试题 64:求 1+2+…+n 86 | * [面试题 65:不用加减乘除做加法](./src/_65/AddTwoNumbers.java) 87 | * 面试题 66:构建乘积数组 88 | * 面试题 67:把字符串转换成整数 89 | * 面试题 68:树中两个结点的最低公共祖先 90 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /note/01/README.md: -------------------------------------------------------------------------------- 1 | # 面试题 1:赋值运算符函数 2 | 3 | ## 问题描述 4 | 5 | 为自定义类添加赋值运算符函数。 6 | 7 | ## 问题分析 8 | 9 | * 对于传入的参数,不应该被修改,使用 final 修饰。 10 | * 判断传入的参数和当前的实例是不是同一个实例,如果是同一个,或者两个实例的值相等,则不进行赋值操作,直接返回。 11 | * 返回值最好为 this,这样可以使赋值链接起来。 12 | 13 | ## [代码实现][src] 14 | 15 | ```java 16 | public MyString assign(final MyString another) { 17 | if (this == another || this.data.equals(another.data)) { 18 | return this; 19 | } else { 20 | this.data = another.data; 21 | return this; 22 | } 23 | } 24 | ``` 25 | 26 | [src]: https://github.com/andavid/coding-interview-java/blob/master/src/_01/AssignmentOperator.java 27 | -------------------------------------------------------------------------------- /note/02/README.md: -------------------------------------------------------------------------------- 1 | # 面试题 2:实现 Singleton 模式 2 | 3 | ## 问题描述 4 | 5 | 设计一个类,只能生成该类的一个实例。 6 | 7 | ## 懒汉式,线程不安全 8 | 9 | 在第一次调用获取实例方法时分配内存,实现了懒加载。但是当有多个线程并行调用 getInstance() 的时候,就会创建多个实例,也就是说在多线程下不能正常工作。 10 | 11 | ```java 12 | public class Singleton { 13 | private static Singleton instance; 14 | private Singleton() {} 15 | public static Singleton getInstance() { 16 | if (instance == null) { 17 | instance = new Singleton(); 18 | } 19 | return instance; 20 | } 21 | } 22 | ``` 23 | 24 | ## 懒汉式,线程安全 25 | 26 | 为了解决上面的问题,最简单的方法是将整个 getInstance() 方法设为同步(synchronized)。 27 | 28 | ```java 29 | public class Singleton { 30 | private static Singleton instance; 31 | private Singleton() {} 32 | public static synchronized Singleton getInstance() { 33 | if (instance == null) { 34 | instance = new Singleton(); 35 | } 36 | return instance; 37 | } 38 | } 39 | ``` 40 | 41 | 也可以对 getInstance() 方法里的代码块设为同步。 42 | 43 | ```java 44 | public class Singleton { 45 | private static Singleton instance; 46 | private Singleton() {} 47 | public static Singleton getInstance() { 48 | synchronized (Singleton.class) { 49 | if (instance == null) { 50 | instance = new Singleton(); 51 | } 52 | } 53 | return instance; 54 | } 55 | } 56 | ``` 57 | 58 | 使用 synchronized 虽然做到了线程安全,并且解决了多实例的问题,但是它并不高效。synchronized 修饰的同步方法比一般方法要慢很多,如果多次调用 getInstance(),累积的性能损耗就比较大了。此外,由于在任何时候只能有一个线程调用 getInstance() 方法,但是同步操作只需要在第一次调用时才被需要,即第一次创建单例实例对象时。这就引出了双重检验锁。 59 | 60 | ## 双重校验锁 61 | 62 | 双重检验锁模式(double checked locking pattern),是一种使用同步块加锁的方法。程序员称其为双重检查锁,因为会有两次检查 instance == null,一次是在同步块外,一次是在同步块内。为什么在同步块内还要再检验一次?因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次检验的话就会生成多个实例了。 63 | 64 | ```java 65 | public class Singleton { 66 | private static Singleton instance; 67 | private Singleton() {} 68 | public static Singleton getInstance() { 69 | if (instance == null) { 70 | synchronized (Singleton.class) { 71 | if (instance == null) { 72 | instance = new Singleton(); 73 | } 74 | } 75 | } 76 | return instance ; 77 | } 78 | } 79 | ``` 80 | 81 | 可以看到上面在同步代码块外多了一层 instance 为空的判断。由于单例对象只需要创建一次,如果后面再次调用 getInstance() 只需要直接返回单例对象。因此,大部分情况下,调用 getInstance() 都不会执行到同步代码块,从而提高了程序性能。 82 | 83 | 但是,这里还有一个隐患,主要是因为 instance = new Singleton() 这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。 84 | 85 | 1. 给 instance 分配内存 86 | 2. 调用 Singleton 的构造函数来初始化成员变量 87 | 3. 将 instance 对象指向分配的内存空间(执行完这步 instance 就为非 null 了) 88 | 89 | 这里要提到 Java中 的指令重排优化。所谓指令重排优化是指在不改变原语义的情况下,通过调整指令的执行顺序让程序运行的更快。 90 | 91 | 由于指令重排优化的存在,导致初始化 Singleton 和将对象地址赋给 instance 的顺序是不确定的。也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错。 92 | 93 | 不过还好在 JDK1.5 及之后版本增加了 volatile 关键字。volatile 的一个语义是禁止指令重排序优化,也就保证了 instance 变量被赋值的时候对象已经是初始化过的,从而避免了上面说到的问题。 94 | 95 | ```java 96 | public class Singleton { 97 | private static volatile Singleton instance; 98 | private Singleton() {} 99 | public static Singleton getInstance() { 100 | if (instance == null) { 101 | synchronized (Singleton.class) { 102 | if (instance == null) { 103 | instance = new Singleton(); 104 | } 105 | } 106 | } 107 | return instance ; 108 | } 109 | } 110 | ``` 111 | 112 | ## 饿汉式 113 | 114 | 因为单例的实例被声明成 static 和 final 变量了,在第一次加载类到内存中时就会初始化,所以创建实例本身是线程安全的。 115 | 116 | 但是它的缺点也很明显,它不是一种懒加载模式。即使这个单例没有用到也会被创建,而且在类加载之后就被创建,内存就被浪费了。 117 | 118 | ```java 119 | class Singleton { 120 | private static final Singleton instance = new Singleton(); 121 | private Singleton() {} 122 | public static Singleton getInstance() { 123 | return instance; 124 | } 125 | } 126 | ``` 127 | 128 | ## 静态内部类 129 | 130 | 与饿汉式一样,这种方式也是利用了类加载机制来保证只创建一个 instance 实例,因此不存在多线程并发的问题,是线程安全的。 131 | 132 | 此外,它是在内部类里面去创建对象实例,只要应用中不使用内部类,JVM 就不会去加载这个单例类,也就不会创建单例对象,从而实现懒汉式的延迟加载。 133 | 134 | ```java 135 | class Singleton { 136 | private static class SingletonHolder { 137 | public static final Singleton INSTANCE = new Singleton(); 138 | } 139 | private Singleton() {} 140 | public static Singleton getInstance() { 141 | return SingletonHolder.INSTANCE; 142 | } 143 | } 144 | ``` 145 | 146 | ## 枚举 147 | 148 | ```java 149 | public enum Singleton { 150 | INSTANCE; 151 | } 152 | ``` 153 | 154 | 通过 Singleton.INSTANCE 就可以获取到单例对象。 155 | 156 | 枚举除了线程安全和防止反射调用构造器之外,还提供了自动序列化机制,防止反序列化的时候创建新的对象。 157 | 158 | ## 总结 159 | 160 | 一般情况下直接使用饿汉式就好了,如果明确要求要懒加载可以使用静态内部类,如果涉及到反序列化创建对象时可以使用枚举的方式来实现单例。 161 | -------------------------------------------------------------------------------- /note/03/README.md: -------------------------------------------------------------------------------- 1 | # 面试题 3:数组中重复的数 2 | 3 | ## 问题描述 4 | 5 | 在一个长度为 n 的数组中,所有数字的取值范围都在 [0,n-1],但不知道有几个数字重复或重复几次,找出其中任意一个重复的数字。 6 | 7 | ## 问题分析 8 | 9 | 借助哈希表,遍历一次数组即可找到重复的数字。 10 | 11 | ## [代码实现][src] 12 | 13 | ```java 14 | public static int getDuplication(int[] data) { 15 | if (data == null || data.length < 2) { 16 | return -1; 17 | } 18 | 19 | Set set = new HashSet<>(); 20 | for (int item : data) { 21 | if (set.contains(item)) { 22 | return item; 23 | } 24 | set.add(item); 25 | } 26 | 27 | return -1; 28 | } 29 | ``` 30 | 31 | [src]: https://github.com/andavid/coding-interview-java/blob/master/src/_03/DuplicationInArray.java 32 | -------------------------------------------------------------------------------- /note/06/README.md: -------------------------------------------------------------------------------- 1 | # 面试题 6:从尾到头打印链表 2 | 3 | ## 问题描述 4 | 5 | 输入一个链表的头节点,从尾到头反过来打印出每个节点的值。 6 | 7 | ## 问题分析 8 | 9 | * 不能改变链表的结构。 10 | * 可以用栈或递归来实现。 11 | 12 | ## [递归实现][src] 13 | 14 | ```java 15 | void printReversinglyRecursively(ListNode node) { 16 | if (node == null) { 17 | return; 18 | } 19 | printReversinglyIteratively(node.next); 20 | System.out.println(node.val); 21 | } 22 | ``` 23 | 24 | ## [栈实现][src] 25 | 26 | ```java 27 | void printReversinglyIteratively(ListNode node) { 28 | Stack stack = new Stack<>(); 29 | while (node != null) { 30 | stack.push(node.val); 31 | node = node.next; 32 | } 33 | while (!stack.empty()) { 34 | System.out.println(stack.pop()); 35 | } 36 | } 37 | ``` 38 | 39 | [src]: https://github.com/andavid/coding-interview-java/blob/master/src/_06/PrintListInReversedOrder.java 40 | -------------------------------------------------------------------------------- /note/18/README.md: -------------------------------------------------------------------------------- 1 | # 面试题 18:删除链表的节点 2 | 3 | ## 在 O(1) 时间内删除单链表的节点 4 | 5 | 给定单向链表的头指针和一个节点指针,定义一个函数在 O(1) 时间内删除该节点。 6 | 7 | ## 解题思路 8 | 9 | 直接删除单链表某一节点,需要 O(n) 时间找到其前继节点,如果想在 O(1) 时间完成删除操作,可以将欲删节点的后一个节点的值拷贝到欲删节点之上,然后删除欲删节点的后一个节点。对于尾节点的删除仍然需要 O(n),其他节点都是 O(1),因此均摊时间复杂度是 O(1),满足要求。 10 | 11 | ## [代码实现][src1] 12 | 13 | ```java 14 | ListNode deleteNode(ListNode head, ListNode node) { 15 | if (head == null) { 16 | return null; 17 | } 18 | 19 | if (node == head) { 20 | ListNode next = head.next; 21 | head = null; 22 | return next; 23 | } 24 | 25 | if (node.next != null) { 26 | ListNode next = node.next; 27 | node.val = next.val; 28 | node.next = next.next; 29 | next = null; 30 | } else { 31 | ListNode p = head; 32 | while (p.next != node) { 33 | p = p.next; 34 | } 35 | p.next = null; 36 | node = null; 37 | } 38 | 39 | return head; 40 | } 41 | ``` 42 | 43 | ## 删除链表中重复的节点 44 | 45 | 在一个排序的链表中,如何删除重复的节点?例如 [1,2,2,3,3,3],删除之后为 [1]。 46 | 47 | ## [代码实现][src2] 48 | 49 | ```java 50 | ListNode deleteDuplication(ListNode head) { 51 | if (head == null) { 52 | return null; 53 | } 54 | 55 | ListNode dummy = new ListNode(0); 56 | dummy.next = head; 57 | 58 | ListNode pre = dummy; 59 | ListNode cur = head; 60 | ListNode post = cur.next; 61 | boolean isDuplicate = false; 62 | 63 | while (post != null) { 64 | if (post.val == cur.val) { 65 | isDuplicate = true; 66 | post = post.next; 67 | } else if (isDuplicate && post.val != cur.val) { 68 | pre.next = post; 69 | // 删除从 cur 到 post 中间的所有节点 70 | while (cur != post) { 71 | ListNode p = cur; 72 | cur = cur.next; 73 | p.next = null; 74 | p = null; 75 | } 76 | post = post.next; 77 | isDuplicate = false; 78 | } else { 79 | pre = cur; 80 | cur = post; 81 | post = post.next; 82 | } 83 | } 84 | 85 | if (isDuplicate) { 86 | pre.next = null; 87 | } 88 | 89 | return dummy.next; 90 | } 91 | ``` 92 | 93 | [src1]: https://github.com/andavid/coding-interview-java/blob/master/src/_18/DeleteNodeInList.java 94 | [src2]: https://github.com/andavid/coding-interview-java/blob/master/src/_18/DeleteDuplicatedNode.java 95 | -------------------------------------------------------------------------------- /note/50/README.md: -------------------------------------------------------------------------------- 1 | # 面试题 50:第一个只出现一次的字符 2 | 3 | ## 问题一描述 4 | 5 | 在字符串中找出第一个只出现一次的字符。如输入abaccdeff,则输出b。 6 | 7 | ## 问题一分析 8 | 9 | 假设字符是 ASCII 编码的字符。可以申请一个长度为 256 的 int 数组作为哈希表,占用空间 1kB,用它来记录字符出现的次数。第一遍扫描字符串,修改对应字符的出现的次数;第二遍扫描,当遇到在数组中对应值为 1 的字符,即得到所求,时间复杂度 o(n)。 10 | 11 | ## [问题一代码实现][src1] 12 | 13 | ```java 14 | char firstNotRepeatingChar(String str) { 15 | int[] count = new int[256]; 16 | for (char ch : str.toCharArray()) { 17 | count[ch]++; 18 | } 19 | for (char ch : str.toCharArray()) { 20 | if (count[ch] == 1) { 21 | return ch; 22 | } 23 | } 24 | return '?'; 25 | } 26 | ``` 27 | 28 | ## 问题二描述 29 | 30 | 实现一个函数,找出字符流中第一个只出现一次的字符。例如,当从字符流 google 中只读出前两个字符 go 时,第一个只出现一次的字符是 g;当读完 google 时,第一个只出现一次的字符是 l。 31 | 32 | ## 问题二分析 33 | 34 | 可以使用一个队列,保存只出现一次的字符。队列的队头就是第一个只出现一次的字符。 35 | 36 | ## [问题二代码实现][src2] 37 | 38 | ```java 39 | public class FirstNotRepeatingCharInStream { 40 | private Queue queue; 41 | public static final char DEFAULT_CHAR = '?'; 42 | 43 | public FirstNotRepeatingCharInStream() { 44 | queue = new LinkedList<>(); 45 | } 46 | 47 | public void insert(char ch) { 48 | if (queue.isEmpty()) { 49 | queue.offer(ch); 50 | } else if (queue.contains(ch)) { 51 | queue.remove(ch); 52 | } else { 53 | queue.offer(ch); 54 | } 55 | } 56 | 57 | public char find() { 58 | if (queue.isEmpty()) { 59 | return DEFAULT_CHAR; 60 | } else { 61 | return queue.peek(); 62 | } 63 | } 64 | } 65 | ``` 66 | 67 | [src1]: https://github.com/andavid/coding-interview-java/blob/master/src/_50/FirstNotRepeatingChar.java 68 | [src2]: https://github.com/andavid/coding-interview-java/blob/master/src/_50/FirstNotRepeatingCharInStream.java 69 | -------------------------------------------------------------------------------- /src/_01/AssignmentOperator.java: -------------------------------------------------------------------------------- 1 | package _01; 2 | 3 | public class AssignmentOperator { 4 | 5 | public static class MyString { 6 | private String data; 7 | 8 | public MyString(String data) { 9 | this.data = data; 10 | } 11 | 12 | public MyString assign(final MyString another) { 13 | if (this == another || this.data.equals(another.data)) { 14 | return this; 15 | } else { 16 | this.data = another.data; 17 | return this; 18 | } 19 | } 20 | 21 | @Override 22 | public String toString() { 23 | return "MyString{" + "data='" + data + '\'' + '}'; 24 | } 25 | } 26 | 27 | public static void main(String[] args) { 28 | MyString s1 = new MyString("a"); 29 | MyString s2 = new MyString("b"); 30 | MyString s3 = new MyString("c"); 31 | System.out.println(s1.assign(s2).assign(s3)); 32 | System.out.println("s1:" + s1); 33 | System.out.println("s2:" + s2); 34 | System.out.println("s3:" + s3); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/_02/Singleton1.java: -------------------------------------------------------------------------------- 1 | package _02; 2 | 3 | public class Singleton1 { 4 | 5 | // 懒汉式,线程不安全 6 | private static Singleton1 instance; 7 | private Singleton1() {} 8 | public static Singleton1 getInstance() { 9 | if (instance == null) { 10 | instance = new Singleton1(); 11 | } 12 | return instance; 13 | } 14 | 15 | public static void main(String[] args) { 16 | System.out.println(Singleton1.getInstance() == Singleton1.getInstance()); 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/_02/Singleton2.java: -------------------------------------------------------------------------------- 1 | package _02; 2 | 3 | public class Singleton2 { 4 | 5 | // 懒汉式,线程安全 6 | private static Singleton2 instance; 7 | private Singleton2() {} 8 | public static synchronized Singleton2 getInstance() { 9 | if (instance == null) { 10 | instance = new Singleton2(); 11 | } 12 | return instance; 13 | } 14 | 15 | public static void main(String[] args) { 16 | System.out.println(Singleton2.getInstance() == Singleton2.getInstance()); 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/_02/Singleton3.java: -------------------------------------------------------------------------------- 1 | package _02; 2 | 3 | public class Singleton3 { 4 | 5 | // 双重校验锁 6 | private static volatile Singleton3 instance; 7 | private Singleton3() {} 8 | public static Singleton3 getInstance() { 9 | if (instance == null) { 10 | synchronized (Singleton3.class) { 11 | if (instance == null) { 12 | instance = new Singleton3(); 13 | } 14 | } 15 | } 16 | return instance; 17 | } 18 | 19 | public static void main(String[] args) { 20 | System.out.println(Singleton3.getInstance() == Singleton3.getInstance()); 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /src/_02/Singleton4.java: -------------------------------------------------------------------------------- 1 | package _02; 2 | 3 | public class Singleton4 { 4 | 5 | // 饿汉式 6 | private static final Singleton4 instance = new Singleton4(); 7 | private Singleton4() {} 8 | public static Singleton4 getInstance() { 9 | return instance; 10 | } 11 | 12 | public static void main(String[] args) { 13 | System.out.println(Singleton4.getInstance() == Singleton4.getInstance()); 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /src/_02/Singleton5.java: -------------------------------------------------------------------------------- 1 | package _02; 2 | 3 | public class Singleton5 { 4 | 5 | // 静态内部类 6 | private static class SingletonHolder { 7 | public static final Singleton5 INSTANCE = new Singleton5(); 8 | } 9 | private Singleton5() {} 10 | public static Singleton5 getInstance() { 11 | return SingletonHolder.INSTANCE; 12 | } 13 | 14 | public static void main(String[] args) { 15 | System.out.println(Singleton5.getInstance() == Singleton5.getInstance()); 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /src/_03/DuplicationInArray.java: -------------------------------------------------------------------------------- 1 | package _03; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | public class DuplicationInArray { 7 | 8 | public static int getDuplication(int[] data) { 9 | if (data == null || data.length < 2) { 10 | return -1; 11 | } 12 | 13 | Set set = new HashSet<>(); 14 | for (int item : data) { 15 | if (set.contains(item)) { 16 | return item; 17 | } 18 | set.add(item); 19 | } 20 | 21 | return -1; 22 | } 23 | 24 | public static void main(String[] args) { 25 | int[] data = {2,3,1,0,2,5,3}; 26 | System.out.println(getDuplication(data)); 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /src/_04/FindInPartiallySortedMatrix.java: -------------------------------------------------------------------------------- 1 | package _04; 2 | 3 | public class FindInPartiallySortedMatrix { 4 | /** 5 | * 一个二维数组中,每一行从左到右递增,每一列从上到下递增。 6 | * 输入一个整数,判断数组中是否含有该整数。 7 | * 8 | * 从右上角开始往左下方向查找 9 | */ 10 | public static boolean findInPartiallySortedMatrix(int[][] data, int target) { 11 | if (data == null || data.length == 0 || data[0].length == 0) { 12 | return false; 13 | } 14 | 15 | int rowMax = data.length - 1; 16 | int colMax = data[0].length - 1; 17 | int rowCur = 0; 18 | int colCur = colMax; 19 | 20 | while (rowCur <= rowMax && colCur >= 0) { 21 | if (data[rowCur][colCur] == target) { 22 | return true; 23 | } else if (data[rowCur][colCur] > target) { 24 | colCur--; 25 | } else { 26 | rowCur++; 27 | } 28 | } 29 | 30 | return false; 31 | } 32 | 33 | public static void main(String[] args) { 34 | int[][] data = { 35 | {1,2,8,9}, 36 | {2,4,9,12}, 37 | {4,7,10,13}, 38 | {6,8,11,15} 39 | }; 40 | System.out.println(findInPartiallySortedMatrix(data, 10)); 41 | System.out.println(findInPartiallySortedMatrix(data, 5)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/_05/ReplaceSpaces.java: -------------------------------------------------------------------------------- 1 | package _05; 2 | 3 | public class ReplaceSpaces { 4 | /** 5 | * 实现一个函数,把字符串中的每个空格都替换成“%20”, 6 | * 已知原位置后面有足够的空余位置,要求改替换过程发生在原来的位置上。 7 | * 8 | * 计算替换后的字符串的长度,从后往前替换 9 | */ 10 | public static void replaceBlank(char[] data, int length) { 11 | int newLen = length; 12 | for (int i = 0; i < length; i++) { 13 | if (data[i] == ' ') { 14 | newLen += 2; 15 | } 16 | } 17 | 18 | for (int indexOld = length - 1, indexNew = newLen - 1; 19 | indexOld >= 0 && indexOld != indexNew; 20 | indexOld--, indexNew--) { 21 | if (data[indexOld] == ' ') { 22 | data[indexNew--] = '0'; 23 | data[indexNew--] = '2'; 24 | data[indexNew] = '%'; 25 | } else { 26 | data[indexNew] = data[indexOld]; 27 | } 28 | } 29 | } 30 | 31 | public static void main(String[] args) { 32 | char[] predata = "we are happy.".toCharArray(); 33 | int length = predata.length; 34 | 35 | char[] data = new char[30]; 36 | for (int i = 0; i < length; i++) { 37 | data[i] = predata[i]; 38 | } 39 | 40 | replaceBlank(data, length); 41 | System.out.println(data); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/_06/PrintListInReversedOrder.java: -------------------------------------------------------------------------------- 1 | package _06; 2 | 3 | import java.util.Stack; 4 | 5 | import structure.ListNode; 6 | 7 | public class PrintListInReversedOrder { 8 | 9 | public static void printReversinglyRecursively(ListNode node) { 10 | if (node == null) { 11 | return; 12 | } 13 | printReversinglyIteratively(node.next); 14 | System.out.println(node.val); 15 | } 16 | 17 | public static void printReversinglyIteratively(ListNode node) { 18 | Stack stack = new Stack<>(); 19 | while (node != null) { 20 | stack.push(node.val); 21 | node = node.next; 22 | } 23 | while (!stack.empty()) { 24 | System.out.println(stack.pop()); 25 | } 26 | } 27 | 28 | public static void main(String[] args) { 29 | ListNode root = new ListNode(1); 30 | root.next = new ListNode(2); 31 | root.next.next = new ListNode(3); 32 | 33 | printReversinglyRecursively(root); 34 | printReversinglyIteratively(root); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/_07/ConstructBinaryTree.java: -------------------------------------------------------------------------------- 1 | package _07; 2 | 3 | import java.util.HashMap; 4 | 5 | import structure.BinaryTree; 6 | import structure.TreeNode; 7 | 8 | public class ConstructBinaryTree { 9 | public static HashMap inMap = new HashMap<>(); 10 | 11 | public static TreeNode construct(int[] preorder, int[] inorder) { 12 | if (preorder == null || inorder == null || preorder.length != inorder.length) { 13 | return null; 14 | } 15 | 16 | for (int i = 0; i < inorder.length; i++) { 17 | inMap.put(inorder[i], i); 18 | } 19 | 20 | return helper(preorder, 0, 0, inorder.length - 1); 21 | } 22 | 23 | public static TreeNode helper(int[] preorder, int preIndex, int inStart, int inEnd) { 24 | if (preIndex > preorder.length - 1 || inStart > inEnd) { 25 | return null; 26 | } 27 | 28 | TreeNode root = new TreeNode(preorder[preIndex]); 29 | int inIndex = inMap.get(root.val); 30 | int leftTreeSize = inIndex - inStart; 31 | 32 | root.left = helper(preorder, preIndex + 1, inStart, inIndex - 1); 33 | root.right = helper(preorder, preIndex + leftTreeSize + 1, inIndex + 1, inEnd); 34 | 35 | return root; 36 | } 37 | 38 | public static void main(String[] args) { 39 | int[] pre = {1, 2, 4, 5, 3}; 40 | int[] in = {4, 2, 5, 1, 3}; 41 | TreeNode root = construct(pre, in); 42 | System.out.println(BinaryTree.preorderIteratively(root)); 43 | System.out.println(BinaryTree.inorderIteratively(root)); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/_08/NextNodeInBinaryTrees.java: -------------------------------------------------------------------------------- 1 | package _08; 2 | 3 | public class NextNodeInBinaryTrees { 4 | /** 5 | * 给定二叉树和其中一个节点,找到中序遍历序列的下一个节点。 6 | * 树中的节点除了有左右孩子指针,还有一个指向父节点的指针。 7 | * 8 | * 1. 如果当前节点有右孩子,下一个节点为右子树最左边的节点 9 | * 2. 如果当前节点没有右孩子,判断与其父亲节点的关系 10 | * 2.1 如果当前节点没有父亲节点,不存在下一个节点 11 | * 2.1 如果当前节点是其父亲节点的左孩子,下一个节点为其父亲节点 12 | * 2.2 如果当前节点是其父亲节点的右孩子,将父亲节点作为新的当前节点,回到 2 13 | */ 14 | public static TreeNode getNext(TreeNode node) { 15 | if (node == null) { 16 | return null; 17 | } 18 | 19 | if (node.right != null) { 20 | node = node.right; 21 | while (node.left != null) { 22 | node = node.left; 23 | } 24 | return node; 25 | } 26 | 27 | while (node.father != null) { 28 | if (node.father.left == node) { 29 | return node.father; 30 | } 31 | node = node.father; 32 | } 33 | 34 | return null; 35 | } 36 | 37 | public static void main(String[] args) { 38 | // 1 39 | // // \\ 40 | // 2 3 41 | // // \\ 42 | // 4 5 43 | // inorder -> 42513 44 | TreeNode root = new TreeNode(1); 45 | root.left = new TreeNode(2); 46 | root.left.father = root; 47 | root.right = new TreeNode(3); 48 | root.right.father = root; 49 | root.left.left = new TreeNode(4); 50 | root.left.left.father = root.left; 51 | root.left.right = new TreeNode(5); 52 | root.left.right.father = root.left; 53 | 54 | System.out.println(getNext(root.left.left).val); // 2 55 | System.out.println(getNext(root.left).val); // 5 56 | System.out.println(getNext(root.left.right).val); // 1 57 | System.out.println(getNext(root).val); // 3 58 | System.out.println(getNext(root.right)); // null 59 | } 60 | 61 | static class TreeNode { 62 | int val; 63 | TreeNode left; 64 | TreeNode right; 65 | TreeNode father; 66 | 67 | public TreeNode(int val) { 68 | this.val = val; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/_09/QueueWithTwoStacks.java: -------------------------------------------------------------------------------- 1 | package _09; 2 | 3 | import java.util.Stack; 4 | 5 | public class QueueWithTwoStacks { 6 | /** 7 | * 用两个栈,实现队列的从队尾插入元素 offer() 和从队头抛出元素 poll() 8 | * 9 | * 使用两个栈,in 负责插入,out 负责弹出。 10 | * 如果 out 不为空,直接弹出。 11 | * 如果 out 为空,将 in 的元素依次弹出并存放到 out 中,之后对 out 进行弹出操作。 12 | */ 13 | static class MyQueue { 14 | private Stack in = new Stack<>(); 15 | private Stack out = new Stack<>(); 16 | 17 | public void offer(T data) { 18 | in.push(data); 19 | } 20 | 21 | public T poll() { 22 | if (out.empty()) { 23 | while (!in.empty()) { 24 | out.push(in.pop()); 25 | } 26 | } 27 | if (!out.empty()) { 28 | return out.pop(); 29 | } 30 | return null; 31 | } 32 | } 33 | 34 | public static void main(String[] args) { 35 | MyQueue myQueue = new MyQueue<>(); 36 | System.out.println(myQueue.poll()); 37 | myQueue.offer(1); 38 | myQueue.offer(2); 39 | myQueue.offer(3); 40 | System.out.println(myQueue.poll()); 41 | System.out.println(myQueue.poll()); 42 | myQueue.offer(4); 43 | System.out.println(myQueue.poll()); 44 | System.out.println(myQueue.poll()); 45 | System.out.println(myQueue.poll()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/_09/StackWithOneQueue.java: -------------------------------------------------------------------------------- 1 | package _09; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | public class StackWithOneQueue { 7 | static class MyStack { 8 | private Queue queue = new LinkedList<>(); 9 | 10 | public void push(T data) { 11 | queue.offer(data); 12 | int size = queue.size(); 13 | for (int i = 0; i < size - 1; i++) { 14 | queue.offer(queue.poll()); 15 | } 16 | } 17 | 18 | public T pop() { 19 | if (queue.isEmpty()) { 20 | return null; 21 | } 22 | return queue.poll(); 23 | } 24 | } 25 | 26 | public static void main(String[] args) { 27 | MyStack myStack = new MyStack<>(); 28 | System.out.println(myStack.pop()); 29 | myStack.push(1); 30 | myStack.push(2); 31 | myStack.push(3); 32 | System.out.println(myStack.pop()); 33 | System.out.println(myStack.pop()); 34 | myStack.push(4); 35 | System.out.println(myStack.pop()); 36 | System.out.println(myStack.pop()); 37 | System.out.println(myStack.pop()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/_09/StackWithTwoQueues.java: -------------------------------------------------------------------------------- 1 | package _09; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | public class StackWithTwoQueues { 7 | /** 8 | * 用两个队列,实现栈的从队尾插入元素 push() 和从队尾抛出元素 pop() 9 | * 10 | * 选一个不为空的队列进行插入,初始都为空,随便选一个。 11 | * 弹出时将不为空的队列元素(除最后一个元素)依次取出放到另一个队列中,将最后那一个元素取出返回。 12 | */ 13 | static class MyStack { 14 | private Queue queue1 = new LinkedList<>(); 15 | private Queue queue2 = new LinkedList<>(); 16 | 17 | public void push(T data) { 18 | if (!queue2.isEmpty()) { 19 | queue2.offer(data); 20 | } else { 21 | queue1.offer(data); 22 | } 23 | } 24 | 25 | public T pop() { 26 | if (!queue2.isEmpty()) { 27 | int size = queue2.size(); 28 | for (int i = 0; i < size - 1; i++) { 29 | queue1.offer(queue2.poll()); 30 | } 31 | return queue2.poll(); 32 | } else if (!queue1.isEmpty()) { 33 | int size = queue1.size(); 34 | for (int i = 0; i < size - 1; i++) { 35 | queue2.offer(queue1.poll()); 36 | } 37 | return queue1.poll(); 38 | } 39 | return null; 40 | } 41 | } 42 | 43 | public static void main(String[] args) { 44 | MyStack myStack = new MyStack<>(); 45 | System.out.println(myStack.pop()); 46 | myStack.push(1); 47 | myStack.push(2); 48 | myStack.push(3); 49 | System.out.println(myStack.pop()); 50 | System.out.println(myStack.pop()); 51 | myStack.push(4); 52 | System.out.println(myStack.pop()); 53 | System.out.println(myStack.pop()); 54 | System.out.println(myStack.pop()); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/_10/Fibonacci.java: -------------------------------------------------------------------------------- 1 | package _10; 2 | 3 | // 斐波那契数列 4 | // 写一个函数,输入 n,求斐波那契(Fibonacci)数列的第 n 项。 5 | public class Fibonacci { 6 | public static long fibonacci1(int n) { 7 | if (n <= 0) { 8 | return 0; 9 | } 10 | 11 | if (n == 1) { 12 | return 1; 13 | } 14 | 15 | return fibonacci1(n - 1) + fibonacci1(n - 2); 16 | } 17 | 18 | public static long fibonacci2(int n) { 19 | if (n <= 0) { 20 | return 0; 21 | } 22 | 23 | if (n == 1) { 24 | return 1; 25 | } 26 | 27 | long oneStepBefore = 1; 28 | long twoStepsBefore = 0; 29 | long result = 1; 30 | 31 | for (int i = 2; i <= n; i++) { 32 | result = oneStepBefore + twoStepsBefore; 33 | twoStepsBefore = oneStepBefore; 34 | oneStepBefore = result; 35 | } 36 | 37 | return result; 38 | } 39 | 40 | public static void main(String[] args) { 41 | System.out.println(fibonacci1(13)); 42 | System.out.println(fibonacci2(13)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/_11/MinNumberInRotatedArray.java: -------------------------------------------------------------------------------- 1 | package _11; 2 | 3 | public class MinNumberInRotatedArray { 4 | /** 5 | * 把一个数组最开始的若干个元素搬到末尾成为数组的旋转。 6 | * 如1,2,3,4,5=>3,4,5,1,2;0,1,1,1,1=>1,1,1,0,1;0,1,1,1,1=>1,0,1,1,1。 7 | * 求一个原本递增的数组旋转后的最小数字。 8 | */ 9 | public static int min(int[] data) { 10 | if (data == null || data.length == 0) { 11 | return -1; 12 | } 13 | 14 | int left = 0; 15 | int right = data.length - 1; 16 | while (left < right) { 17 | int mid = left + (right - left)/2; 18 | if (data[left] < data[right]) { 19 | return data[left]; 20 | } else if (data[left] > data[right]) { 21 | // 前面部分是较大的递增序列,后面是较小的递增序列 22 | if (data[left] <= data[mid]) { 23 | // left 到 mid 是递增的,最小值在 mid + 1 到 right 之间 24 | left = mid + 1; 25 | } else { 26 | // left 到 mid 不是递增的,最小值在 left 到 mid 之间 27 | right = mid; 28 | } 29 | } else { 30 | if (data[left] < data[mid]) { 31 | left = mid + 1; 32 | } else if (data[left] > data[mid]) { 33 | right = mid; 34 | } else { 35 | // 左右中三个值都相等,查找范围缩小一步 36 | left = left + 1; 37 | right = right - 1; 38 | } 39 | } 40 | } 41 | 42 | return data[right]; 43 | } 44 | 45 | public static void main(String[] args) { 46 | int[] data1 = {3,4,5,1,2}; 47 | int[] data2 = {1,0,1,1,1}; 48 | int[] data3 = {1,1,1,0,1}; 49 | System.out.println(min(data1)); 50 | System.out.println(min(data2)); 51 | System.out.println(min(data3)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/_14/CuttingRope.java: -------------------------------------------------------------------------------- 1 | package _14; 2 | 3 | public class CuttingRope { 4 | /** 5 | * 给你一根长度为n的绳子,把绳子剪成m段,求每段绳子长度乘积的最大值。 6 | * f(n) = max(f(i)*f(n-i)), i=[0,n/2] 7 | */ 8 | public static int maxCutting(int length) { 9 | if (length < 2) return 0; 10 | if (length == 2) return 1; 11 | if (length == 3) return 2; 12 | 13 | int[] dp = new int[length + 1]; 14 | dp[0] = 0; 15 | dp[1] = 1; 16 | dp[2] = 2; 17 | dp[3] = 3; 18 | 19 | for (int i = 4; i <= length; i++) { 20 | int max = 0; 21 | for (int j = 1; j <= i/2; j++) { 22 | int temp = dp[j] * dp[i - j]; 23 | if (temp > max) { 24 | max = temp; 25 | } 26 | } 27 | dp[i] = max; 28 | } 29 | 30 | return dp[length]; 31 | } 32 | 33 | public static void main(String[] args) { 34 | for (int i = 2; i < 10; i++) { 35 | System.out.println("" + i + " -> " + maxCutting(i)); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/_15/NumberOf1InBinary.java: -------------------------------------------------------------------------------- 1 | package _15; 2 | 3 | public class NumberOf1InBinary { 4 | private static int numberOf1(int n) { 5 | int count = 0; 6 | while (n != 0) { 7 | n = n & (n-1); 8 | count++; 9 | } 10 | return count; 11 | } 12 | 13 | public static void main(String[] args) { 14 | System.out.println(numberOf1(9)); 15 | System.out.println(numberOf1(-3)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/_18/DeleteDuplicatedNode.java: -------------------------------------------------------------------------------- 1 | package _18; 2 | 3 | import structure.ListNode; 4 | 5 | public class DeleteDuplicatedNode { 6 | 7 | public static ListNode deleteDuplication(ListNode head) { 8 | if (head == null) { 9 | return null; 10 | } 11 | 12 | ListNode dummy = new ListNode(0); 13 | dummy.next = head; 14 | 15 | ListNode pre = dummy; 16 | ListNode cur = head; 17 | ListNode post = cur.next; 18 | boolean isDuplicate = false; 19 | 20 | while (post != null) { 21 | if (post.val == cur.val) { 22 | isDuplicate = true; 23 | post = post.next; 24 | } else if (isDuplicate && post.val != cur.val) { 25 | pre.next = post; 26 | // 删除从 cur 到 post 中间的所有节点 27 | while (cur != post) { 28 | ListNode p = cur; 29 | cur = cur.next; 30 | p.next = null; 31 | p = null; 32 | } 33 | post = post.next; 34 | isDuplicate = false; 35 | } else { 36 | pre = cur; 37 | cur = post; 38 | post = post.next; 39 | } 40 | } 41 | 42 | if (isDuplicate) { 43 | pre.next = null; 44 | } 45 | 46 | return dummy.next; 47 | } 48 | 49 | public static void main(String[] args) { 50 | ListNode head = new ListNode(1); 51 | head.next= new ListNode<>(1); 52 | head.next.next = new ListNode<>(2); 53 | head.next.next.next = new ListNode<>(2); 54 | head.next.next.next.next = new ListNode<>(2); 55 | head.next.next.next.next.next = new ListNode<>(3); 56 | System.out.println(head); 57 | head = deleteDuplication(head); 58 | System.out.println(head); 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /src/_18/DeleteNodeInList.java: -------------------------------------------------------------------------------- 1 | package _18; 2 | 3 | import structure.ListNode; 4 | 5 | public class DeleteNodeInList { 6 | 7 | public static ListNode deleteNode(ListNode head, ListNode node) { 8 | if (head == null) { 9 | return null; 10 | } 11 | 12 | if (node == head) { 13 | ListNode next = head.next; 14 | head = null; 15 | return next; 16 | } 17 | 18 | if (node.next != null) { 19 | ListNode next = node.next; 20 | node.val = next.val; 21 | node.next = next.next; 22 | next = null; 23 | } else { 24 | ListNode p = head; 25 | while (p.next != node) { 26 | p = p.next; 27 | } 28 | p.next = null; 29 | node = null; 30 | } 31 | 32 | return head; 33 | } 34 | 35 | public static void main(String[] args) { 36 | ListNode head = new ListNode(1); 37 | ListNode node2 = new ListNode(2); 38 | ListNode node3 = new ListNode(3); 39 | head.next = node2; 40 | node2.next = node3; 41 | 42 | System.out.println(head); 43 | 44 | head = deleteNode(head, head); 45 | System.out.println(head); 46 | 47 | head = deleteNode(head, node2); 48 | System.out.println(head); 49 | 50 | head = deleteNode(head, node3); 51 | System.out.println(head); 52 | 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /src/_19/RegularExpressionsMatching.java: -------------------------------------------------------------------------------- 1 | package _19; 2 | 3 | public class RegularExpressionsMatching { 4 | /** 5 | * 实现正则表达式中.和*的功能。.表示任意一个字符,*表示他前面的字符的任意次(含0次)。 6 | * 比如aaa与a.a和ab*ac*a匹配,但与aa.a和ab*a不匹配。 7 | * 8 | * 由于*的匹配会涉及到前一个字符,所以要区分模式串的第二个字符是不是*的情况,然后在考虑.的问题。 9 | */ 10 | public static boolean match(String str, String pattern) { 11 | if (str == null || pattern == null) { 12 | return false; 13 | } 14 | return matchInternal(str, 0, pattern, 0); 15 | } 16 | 17 | public static boolean matchInternal(String str, int strIndex, String pattern, int patternIndex) { 18 | int strLength = str.length(); 19 | int patternLength = pattern.length(); 20 | 21 | // 如果匹配串和模式串都匹配结束 22 | if (patternIndex == patternLength) { 23 | return (strIndex == strLength); 24 | } 25 | 26 | // 如果匹配串匹配结束,模式串没有匹配结束,判断模式串第二个字符是不是 * 27 | if (strIndex == strLength) { 28 | if (patternIndex+1 < patternLength && pattern.charAt(patternIndex + 1) == '*') { 29 | return matchInternal(str, strIndex, pattern, patternIndex + 2); // * 匹配 0 次 30 | } else { 31 | return false; 32 | } 33 | } 34 | 35 | // 匹配串和模式串都没有匹配结束,区分模式串的第二个字符是不是* 36 | if (patternIndex == patternLength-1 || pattern.charAt(patternIndex + 1) != '*') { 37 | // 模式串只剩下一个字符,或者模式串的第二个字符不是* 38 | if (matchOne(str, strIndex, pattern, patternIndex)) { 39 | // 当前字符匹配成功,继续匹配下一个字符 40 | return matchInternal(str, strIndex + 1, pattern, patternIndex + 1); 41 | } else { 42 | return false; 43 | } 44 | } else { 45 | // 模式串的第二个字符是* 46 | if (matchOne(str, strIndex, pattern, patternIndex)) { 47 | return matchInternal(str, strIndex, pattern, patternIndex + 2) // * 匹配 0 次 48 | || matchInternal(str, strIndex + 1, pattern, patternIndex + 2) // * 匹配 1 次 49 | || matchInternal(str, strIndex + 1, pattern, patternIndex); // * 匹配 N 次 50 | } else { 51 | return matchInternal(str, strIndex, pattern, patternIndex + 2); // * 匹配 0 次 52 | } 53 | } 54 | } 55 | 56 | public static boolean matchOne(String str, int strIndex, String pattern, int patternIndex) { 57 | return pattern.charAt(patternIndex) == '.' || pattern.charAt(patternIndex) == str.charAt(strIndex); 58 | } 59 | 60 | public static void main(String[] args) { 61 | System.out.println(match("aaa", "a.a"));//true 62 | System.out.println(match("aaa", "ab*ac*a"));//true 63 | System.out.println(match("aaa", "aa.a"));//false 64 | System.out.println(match("aaa", "ab*a"));//false 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/_21/ReorderArray.java: -------------------------------------------------------------------------------- 1 | package _21; 2 | 3 | import java.util.Arrays; 4 | 5 | public class ReorderArray { 6 | /** 7 | * 实现一个函数来调整数组中的数字,使得所有奇数位于数组的前半部分,偶数位于后半部分。 8 | * 9 | * 使用双指针从两端往中间扫描 10 | */ 11 | public static void reorder(int[] data) { 12 | if (data == null || data.length < 2) { 13 | return; 14 | } 15 | 16 | int left = 0; 17 | int right = data.length - 1; 18 | 19 | while (left < right) { 20 | while (left < right && !isEven(data[left])) { 21 | left++; 22 | } 23 | while (left < right && isEven(data[right])) { 24 | right--; 25 | } 26 | if (left < right) { 27 | int temp = data[left]; 28 | data[left] = data[right]; 29 | data[right] = temp; 30 | } 31 | } 32 | } 33 | 34 | public static boolean isEven(int value) { 35 | return (value&1) == 0; 36 | } 37 | 38 | public static void main(String[] args) { 39 | int[] data = {1,2,3,4,5,7,7}; 40 | reorder(data); 41 | System.out.println(Arrays.toString(data)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/_22/KthNodeFromEnd.java: -------------------------------------------------------------------------------- 1 | package _22; 2 | 3 | import structure.ListNode; 4 | 5 | public class KthNodeFromEnd { 6 | public static ListNode findKthToTail(ListNode head, int k) { 7 | if (head == null || k <= 0) { 8 | return null; 9 | } 10 | 11 | ListNode dummy = new ListNode(0); 12 | dummy.next = head; 13 | ListNode slow = dummy; 14 | ListNode fast = dummy; 15 | 16 | for (int i = 0; fast != null && i < k; i++) { 17 | fast = fast.next; 18 | } 19 | 20 | while (fast != null) { 21 | slow = slow.next; 22 | fast = fast.next; 23 | } 24 | 25 | return (slow == dummy) ? null : slow; 26 | } 27 | 28 | public static void main(String[] args) { 29 | ListNode head = new ListNode<>(1); 30 | head.next= new ListNode<>(2); 31 | head.next.next = new ListNode<>(3); 32 | System.out.println(findKthToTail(head,1).val); 33 | System.out.println(findKthToTail(head,2).val); 34 | System.out.println(findKthToTail(head,3).val); 35 | System.out.println(findKthToTail(head,4)); 36 | } 37 | } -------------------------------------------------------------------------------- /src/_23/EntryNodeInListLoop.java: -------------------------------------------------------------------------------- 1 | package _23; 2 | 3 | import structure.ListNode; 4 | 5 | public class EntryNodeInListLoop { 6 | public static ListNode meetingNode(ListNode head) { 7 | ListNode slow = head; 8 | ListNode fast = head; 9 | boolean hasCycle = false; 10 | 11 | while (fast != null && fast.next != null) { 12 | slow = slow.next; 13 | fast = fast.next.next; 14 | if (slow == fast) { 15 | hasCycle = true; 16 | break; 17 | } 18 | } 19 | 20 | if (!hasCycle) { 21 | return null; 22 | } 23 | 24 | slow = head; 25 | while (slow != fast) { 26 | slow = slow.next; 27 | fast = fast.next; 28 | } 29 | 30 | return slow; 31 | } 32 | 33 | public static void main(String[] args) { 34 | // 1->2->3->4->5->6 35 | // |________| 36 | ListNode head = new ListNode<>(1); 37 | head.next= new ListNode<>(2); 38 | ListNode node = new ListNode<>(3); 39 | head.next.next = node; 40 | node.next = new ListNode<>(4); 41 | node.next.next = new ListNode<>(5); 42 | node.next.next.next = new ListNode<>(6); 43 | node.next.next.next.next = node; 44 | ListNode meet = meetingNode(head); 45 | if(meet==null) { 46 | System.out.println("没有环"); 47 | } else { 48 | System.out.println("环的入口值:" + meet.val); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/_24/ReverseList.java: -------------------------------------------------------------------------------- 1 | package _24; 2 | 3 | import structure.ListNode; 4 | 5 | public class ReverseList { 6 | public static ListNode reverseList(ListNode head) { 7 | ListNode pre = null; 8 | ListNode cur = head; 9 | 10 | while (cur != null) { 11 | ListNode post = cur.next; 12 | cur.next = pre; 13 | pre = cur; 14 | cur = post; 15 | } 16 | 17 | return pre; 18 | } 19 | 20 | public static ListNode reverseListRecursively(ListNode head) { 21 | if (head == null || head.next == null) { 22 | return head; 23 | } 24 | ListNode node = reverseListRecursively(head.next); 25 | head.next.next = head; 26 | head.next = null; 27 | return node; 28 | } 29 | 30 | public static void main(String[] args) { 31 | ListNode head = new ListNode<>(1); 32 | head.next= new ListNode<>(2); 33 | head.next.next = new ListNode<>(3); 34 | System.out.println(head); 35 | 36 | head = reverseList(head); 37 | System.out.println(head); 38 | 39 | head = reverseListRecursively(head); 40 | System.out.println(head); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/_25/MergeSortedLists.java: -------------------------------------------------------------------------------- 1 | package _25; 2 | 3 | import structure.ListNode; 4 | 5 | public class MergeSortedLists { 6 | public static ListNode merge(ListNode head1, ListNode head2) { 7 | if (head1 == null) { 8 | return head2; 9 | } 10 | 11 | if (head2 == null) { 12 | return head1; 13 | } 14 | 15 | if (head1.val < head2.val) { 16 | head1.next = merge(head1.next, head2); 17 | return head1; 18 | } else { 19 | head2.next = merge(head1, head2.next); 20 | return head2; 21 | } 22 | } 23 | 24 | public static void main(String[] args) { 25 | ListNode head1 = new ListNode<>(1); 26 | head1.next= new ListNode<>(3); 27 | head1.next.next = new ListNode<>(5); 28 | head1.next.next.next = new ListNode<>(7); 29 | 30 | ListNode head2 = new ListNode<>(2); 31 | head2.next= new ListNode<>(4); 32 | head2.next.next = new ListNode<>(6); 33 | head2.next.next.next = new ListNode<>(8); 34 | 35 | System.out.println(head1); 36 | System.out.println(head2); 37 | 38 | ListNode head = merge(head1,head2); 39 | System.out.println(head); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/_26/SubstructureInTree.java: -------------------------------------------------------------------------------- 1 | package _26; 2 | 3 | import structure.TreeNode; 4 | 5 | // 面试题26:树的子结构 6 | // 题目:输入两棵二叉树A和B,判断B是不是A的子结构。 7 | 8 | public class SubstructureInTree { 9 | public static boolean hasSubtree(TreeNode s, TreeNode t) { 10 | if (t == null) { 11 | return true; 12 | } 13 | if (s == null) { 14 | return false; 15 | } 16 | if (s.val == t.val) { 17 | if (isMatch(s, t)) { 18 | return true; 19 | } 20 | } 21 | return hasSubtree(s.left, t) || hasSubtree(s.right, t); 22 | } 23 | 24 | public static boolean isMatch(TreeNode s, TreeNode t) { 25 | if (t == null) { 26 | return true; 27 | } 28 | if (s == null) { 29 | return false; 30 | } 31 | if (s.val == t.val && isMatch(s.left, t.left) && isMatch(s.right, t.right)) { 32 | return true; 33 | } else { 34 | return false; 35 | } 36 | } 37 | 38 | public static void main(String[] args) { 39 | // 8 8 2 40 | // / \ / \ / \ 41 | // 8 7 9 2 4 3 42 | // / \ 43 | // 9 2 44 | // / \ 45 | // 4 7 46 | TreeNode root1 = new TreeNode(8); 47 | root1.left = new TreeNode(8); 48 | root1.right = new TreeNode(7); 49 | root1.left.left = new TreeNode(9); 50 | root1.left.right = new TreeNode(2); 51 | root1.left.right.left = new TreeNode(4); 52 | root1.left.right.right = new TreeNode(7); 53 | 54 | TreeNode root2 = new TreeNode(8); 55 | root2.left = new TreeNode(9); 56 | root2.right = new TreeNode(2); 57 | 58 | TreeNode root3 = new TreeNode(2); 59 | root3.left = new TreeNode(4); 60 | root3.right = new TreeNode(3); 61 | 62 | System.out.println(hasSubtree(root1, root2)); 63 | System.out.println(hasSubtree(root1, root3)); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/_27/MirrorOfBinaryTree.java: -------------------------------------------------------------------------------- 1 | package _27; 2 | 3 | import java.util.Stack; 4 | 5 | import structure.TreeNode; 6 | 7 | // 二叉树的镜像 8 | // 请完成一个函数,输入一个二叉树,该函数输出它的镜像。 9 | public class MirrorOfBinaryTree { 10 | public static void mirrorRecursively(TreeNode root) { 11 | if (root == null) { 12 | return; 13 | } 14 | if (root.left == null && root.right == null) { 15 | return; 16 | } 17 | 18 | TreeNode temp = root.left; 19 | root.left = root.right; 20 | root.right = temp; 21 | 22 | mirrorRecursively(root.left); 23 | mirrorRecursively(root.right); 24 | } 25 | 26 | public static void mirrorIteratively(TreeNode root) { 27 | if (root == null) { 28 | return; 29 | } 30 | 31 | Stack stack = new Stack<>(); 32 | stack.push(root); 33 | 34 | while (!stack.empty()) { 35 | TreeNode node = stack.pop(); 36 | 37 | TreeNode temp = node.left; 38 | node.left = node.right; 39 | node.right = temp; 40 | 41 | if (node.left != null) { 42 | stack.push(node.left); 43 | } 44 | 45 | if (node.right != null) { 46 | stack.push(node.right); 47 | } 48 | } 49 | } 50 | 51 | public static void main(String[] args) { 52 | // 8 53 | // 6 10 54 | // 5 7 9 11 55 | TreeNode root = new TreeNode(8); 56 | root.left = new TreeNode(6); 57 | root.right = new TreeNode(10); 58 | root.left.left = new TreeNode(5); 59 | root.left.right = new TreeNode(7); 60 | root.right.left = new TreeNode(9); 61 | root.right.right = new TreeNode(11); 62 | 63 | System.out.println(root); 64 | mirrorRecursively(root); 65 | System.out.println(root); 66 | mirrorIteratively(root); 67 | System.out.println(root); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/_28/SymmetricalBinaryTree.java: -------------------------------------------------------------------------------- 1 | package _28; 2 | 3 | import structure.TreeNode; 4 | 5 | // 对称的二叉树 6 | // 请实现一个函数,用来判断一棵二叉树是不是对称的。 7 | public class SymmetricalBinaryTree { 8 | public static boolean isSymmetrical(TreeNode root) { 9 | if (root == null) { 10 | return true; 11 | } 12 | return isSymmetrical(root.left, root.right); 13 | } 14 | 15 | public static boolean isSymmetrical(TreeNode r1, TreeNode r2) { 16 | if (r1 == null && r2 == null) { 17 | return true; 18 | } 19 | if (r1 == null || r2 == null) { 20 | return false; 21 | } 22 | if (r1.val != r2.val) { 23 | return false; 24 | } 25 | return isSymmetrical(r1.left, r2.right) && isSymmetrical(r1.right, r2.left); 26 | } 27 | 28 | public static void main(String[] args) { 29 | // 8 30 | // 6 6 31 | // 5 7 7 5 32 | TreeNode root = new TreeNode(8); 33 | root.left = new TreeNode(6); 34 | root.right = new TreeNode(6); 35 | root.left.left = new TreeNode(5); 36 | root.left.right = new TreeNode(7); 37 | root.right.left = new TreeNode(7); 38 | root.right.right = new TreeNode(5); 39 | System.out.println(isSymmetrical(root)); 40 | System.out.println(isSymmetrical(root.left)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/_30/MinInStack.java: -------------------------------------------------------------------------------- 1 | package _30; 2 | 3 | import java.util.Stack; 4 | 5 | public class MinInStack { 6 | static class MinStack { 7 | private int min; 8 | private Stack stack; 9 | 10 | public MinStack() { 11 | min = Integer.MAX_VALUE; 12 | stack = new Stack<>(); 13 | } 14 | 15 | public void push(Integer data) { 16 | if (data <= min) { 17 | stack.push(min); 18 | min = data; 19 | } 20 | stack.push(data); 21 | } 22 | 23 | public int pop() { 24 | int ret = stack.pop(); 25 | if (ret == min) { 26 | min = stack.pop(); 27 | } 28 | return ret; 29 | } 30 | 31 | public int min() { 32 | return min; 33 | } 34 | } 35 | 36 | public static void main(String[] args) { 37 | MinStack stack = new MinStack(); 38 | stack.push(3); 39 | stack.push(4); 40 | stack.push(2); 41 | stack.push(1); 42 | System.out.println(stack.min()); 43 | stack.pop(); 44 | System.out.println(stack.min()); 45 | stack.pop(); 46 | System.out.println(stack.min()); 47 | stack.pop(); 48 | System.out.println(stack.min()); 49 | stack.pop(); 50 | System.out.println(stack.min()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/_31/StackPushPopOrder.java: -------------------------------------------------------------------------------- 1 | package _31; 2 | 3 | import java.util.Stack; 4 | 5 | public class StackPushPopOrder { 6 | /** 7 | * 输入两个整数序列,第一个序列表示栈的压入顺序,判断第二个序列是否为该栈的弹出序序列。 8 | * 假设压入栈的所有数字均不相等。 9 | * 例如,压入序列为(1,2,3,4,5),序列(4,5,3,2,1)是它的弹出序列,而(4,3,5,1,2)不是。 10 | */ 11 | public static boolean isPopOrder(int[] pushSeq, int[] popSeq) { 12 | if (pushSeq == null || popSeq == null || pushSeq.length != popSeq.length) { 13 | return false; 14 | } 15 | 16 | Stack stack = new Stack<>(); 17 | int pushSeqIndex = 0, popSeqIndex = 0; 18 | while (popSeqIndex < popSeq.length) { 19 | if (stack.empty() || stack.peek() != popSeq[popSeqIndex]) { 20 | if (pushSeqIndex < pushSeq.length) { 21 | stack.push(pushSeq[pushSeqIndex++]); 22 | } else { 23 | return false; 24 | } 25 | } else { 26 | stack.pop(); 27 | popSeqIndex++; 28 | } 29 | } 30 | 31 | return true; 32 | } 33 | 34 | public static void main(String[] args) { 35 | int[] push = {1,2,3,4,5}; 36 | int[] pop1 = {4,5,3,2,1}; 37 | int[] pop2 = {4,3,5,1,2}; 38 | System.out.println(isPopOrder(push,pop1)); 39 | System.out.println(isPopOrder(push,pop2)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/_32/PrintTreeFromTopToBottom.java: -------------------------------------------------------------------------------- 1 | package _32; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | import structure.TreeNode; 7 | 8 | // 不分行从上往下打印二叉树 9 | // 从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。 10 | public class PrintTreeFromTopToBottom { 11 | public static void printFromTopToBottom(TreeNode root) { 12 | if (root == null) { 13 | return; 14 | } 15 | 16 | Queue queue = new LinkedList<>(); 17 | queue.offer(root); 18 | 19 | while (!queue.isEmpty()) { 20 | TreeNode node = queue.poll(); 21 | System.out.print(node.val); 22 | System.out.print('\t'); 23 | 24 | if (node.left != null) { 25 | queue.offer(node.left); 26 | } 27 | if (node.right != null) { 28 | queue.offer(node.right); 29 | } 30 | } 31 | } 32 | 33 | public static void main(String[] args) { 34 | // 1 35 | // / \ 36 | // 2 3 37 | // / \ / \ 38 | // 4 5 6 7 39 | TreeNode root = new TreeNode(1); 40 | root.left = new TreeNode(2); 41 | root.right = new TreeNode(3); 42 | root.left.left = new TreeNode(4); 43 | root.left.right = new TreeNode(5); 44 | root.right.left = new TreeNode(6); 45 | root.right.right = new TreeNode(7); 46 | 47 | printFromTopToBottom(root); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/_32/PrintTreesInLines.java: -------------------------------------------------------------------------------- 1 | package _32; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | import structure.TreeNode; 7 | 8 | // 分行从上到下打印二叉树 9 | // 从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行。 10 | public class PrintTreesInLines { 11 | public static void printInLines(TreeNode root) { 12 | if (root == null) { 13 | return; 14 | } 15 | 16 | Queue queue = new LinkedList<>(); 17 | queue.offer(root); 18 | 19 | while (!queue.isEmpty()) { 20 | for (int size = queue.size(); size > 0; size--) { 21 | TreeNode node = queue.poll(); 22 | System.out.print(node.val); 23 | System.out.print('\t'); 24 | 25 | if (node.left != null) { 26 | queue.offer(node.left); 27 | } 28 | if (node.right != null) { 29 | queue.offer(node.right); 30 | } 31 | } 32 | System.out.println(); 33 | } 34 | } 35 | 36 | public static void main(String[] args) { 37 | // 1 38 | // / \ 39 | // 2 3 40 | // / \ / \ 41 | // 4 5 6 7 42 | TreeNode root = new TreeNode(1); 43 | root.left = new TreeNode(2); 44 | root.right = new TreeNode(3); 45 | root.left.left = new TreeNode(4); 46 | root.left.right = new TreeNode(5); 47 | root.right.left = new TreeNode(6); 48 | root.right.right = new TreeNode(7); 49 | 50 | printInLines(root); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/_32/PrintTreesInZigzag.java: -------------------------------------------------------------------------------- 1 | package _32; 2 | 3 | import java.util.Stack; 4 | 5 | import structure.TreeNode; 6 | 7 | // 之字形打印二叉树 8 | // 请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺 9 | // 序打印,第二行按照从右到左的顺序打印,第三行再按照从左到右的顺序打印, 10 | // 其他行以此类推。 11 | public class PrintTreesInZigzag { 12 | public static void printInZigzag(TreeNode root) { 13 | if (root == null) { 14 | return; 15 | } 16 | 17 | Stack stack1 = new Stack<>(); 18 | Stack stack2 = new Stack<>(); 19 | stack1.push(root); 20 | 21 | while (!stack1.empty() || !stack2.empty()) { 22 | if (!stack1.empty()) { 23 | while (!stack1.empty()) { 24 | TreeNode node = stack1.pop(); 25 | System.out.print(node.val); 26 | System.out.print('\t'); 27 | 28 | if (node.left != null) { 29 | stack2.push(node.left); 30 | } 31 | if (node.right != null) { 32 | stack2.push(node.right); 33 | } 34 | } 35 | } else { 36 | while (!stack2.empty()) { 37 | TreeNode node = stack2.pop(); 38 | System.out.print(node.val); 39 | System.out.print('\t'); 40 | 41 | if (node.right != null) { 42 | stack1.push(node.right); 43 | } 44 | if (node.left != null) { 45 | stack1.push(node.left); 46 | } 47 | } 48 | } 49 | System.out.println(); 50 | } 51 | } 52 | 53 | public static void main(String[] args) { 54 | // 1 55 | // / \ 56 | // 2 3 57 | // / \ / \ 58 | // 4 5 6 7 59 | TreeNode root = new TreeNode(1); 60 | root.left = new TreeNode(2); 61 | root.right = new TreeNode(3); 62 | root.left.left = new TreeNode(4); 63 | root.left.right = new TreeNode(5); 64 | root.right.left = new TreeNode(6); 65 | root.right.right = new TreeNode(7); 66 | 67 | printInZigzag(root); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/_33/SequenceOfBST.java: -------------------------------------------------------------------------------- 1 | package _33; 2 | 3 | // 二叉搜索树的后序遍历序列 4 | // 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。 5 | // 如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。 6 | public class SequenceOfBST { 7 | public static boolean verifySquenceOfBST(int[] data) { 8 | if (data == null || data.length == 0) { 9 | return false; 10 | } 11 | return verifySquenceOfBST(data, 0, data.length - 1); 12 | } 13 | 14 | public static boolean verifySquenceOfBST(int[] data, int start, int end) { 15 | if (end - start <= 1) { 16 | return true; 17 | } 18 | 19 | int root = data[end]; 20 | int right = start; 21 | for (int i = start; i < end; i++) { 22 | if (data[i] > root) { 23 | right = i; 24 | break; 25 | } 26 | } 27 | 28 | for (int i = right; i < end; i++) { 29 | if (data[i] < root) { 30 | return false; 31 | } 32 | } 33 | 34 | return verifySquenceOfBST(data, start, right - 1) 35 | && verifySquenceOfBST(data, right, end - 1); 36 | } 37 | 38 | public static void main(String[] args) { 39 | // 8 40 | // / \ 41 | // 6 10 42 | // / \ / \ 43 | // 5 7 9 11 44 | int[] data1 = {5, 7, 6, 9, 11, 10, 8}; 45 | int[] data2 = {5, 7, 6, 9, 4, 10, 8}; 46 | System.out.println(verifySquenceOfBST(data1)); 47 | System.out.println(verifySquenceOfBST(data2)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/_34/PathInTree.java: -------------------------------------------------------------------------------- 1 | package _34; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import structure.TreeNode; 7 | 8 | // 二叉树中和为某一值的路径 9 | // 输入一棵二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所 10 | // 有路径。从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。 11 | public class PathInTree { 12 | public static void findPath(TreeNode root, int expectedSum) { 13 | if (root == null) { 14 | return; 15 | } 16 | List path = new ArrayList<>(); 17 | findPath(root, path, expectedSum, 0); 18 | } 19 | 20 | public static void findPath(TreeNode curNode, List path, 21 | int expectedSum, int currentSum) { 22 | path.add(curNode.val); 23 | currentSum += curNode.val; 24 | 25 | if (curNode.left != null) { 26 | findPath(curNode.left, path, expectedSum, currentSum); 27 | } 28 | if (curNode.right != null) { 29 | findPath(curNode.right, path, expectedSum, currentSum); 30 | } 31 | 32 | if (curNode.left == null && curNode.right == null && expectedSum == currentSum) { 33 | System.out.println(path); 34 | } 35 | 36 | path.remove(path.size() - 1); 37 | } 38 | 39 | public static void main(String[] args) { 40 | // 10 41 | // / \ 42 | // 5 12 43 | // / \ 44 | // 4 7 45 | TreeNode root = new TreeNode(10); 46 | root.left = new TreeNode(5); 47 | root.right = new TreeNode(12); 48 | root.left.left = new TreeNode(4); 49 | root.left.right = new TreeNode(7); 50 | findPath(root, 22); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/_37/SerializeBinaryTrees.java: -------------------------------------------------------------------------------- 1 | package _37; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | import java.util.Queue; 8 | 9 | import structure.TreeNode; 10 | 11 | // 序列化二叉树 12 | // 请实现两个函数,分别用来序列化和反序列化二叉树。 13 | public class SerializeBinaryTrees { 14 | public static String serialize(TreeNode root) { 15 | if (root == null) { 16 | return "[]"; 17 | } 18 | 19 | List list = new ArrayList<>(); 20 | Queue queue = new LinkedList<>(); 21 | queue.offer(root); 22 | 23 | while (!queue.isEmpty()) { 24 | TreeNode node = queue.poll(); 25 | 26 | if (node == null) { 27 | list.add("null"); 28 | continue; 29 | } else { 30 | list.add("" + node.val); 31 | } 32 | 33 | if (node.left != null) { 34 | queue.offer(node.left); 35 | } else { 36 | queue.offer(null); 37 | } 38 | 39 | if (node.right != null) { 40 | queue.offer(node.right); 41 | } else { 42 | queue.offer(null); 43 | } 44 | } 45 | 46 | // 移除末尾的 null 47 | for (int i = list.size() - 1; i >= 0; i--) { 48 | if (list.get(i).equals("null")) { 49 | list.remove(i); 50 | } else { 51 | break; 52 | } 53 | } 54 | 55 | StringBuilder sb = new StringBuilder(); 56 | sb.append('['); 57 | for (int i = 0; i < list.size(); i++) { 58 | sb.append(list.get(i)); 59 | if (i == list.size() - 1) { 60 | sb.append("]"); 61 | } else { 62 | sb.append(", "); 63 | } 64 | } 65 | 66 | return sb.toString(); 67 | } 68 | 69 | public static TreeNode deserialize(String data) { 70 | if (data == null || data.equals("[]") || data.length() <= 2) { 71 | return null; 72 | } 73 | 74 | String[] strArray = data.substring(1, data.length() - 1).split(","); 75 | Queue list = new LinkedList<>(); 76 | list.addAll(Arrays.asList(strArray)); 77 | 78 | Queue queue = new LinkedList<>(); 79 | TreeNode root = new TreeNode(Integer.valueOf(list.poll().trim())); 80 | queue.offer(root); 81 | 82 | while (!queue.isEmpty()) { 83 | TreeNode node = queue.poll(); 84 | 85 | String leftVal = list.poll(); 86 | if (leftVal == null || leftVal.trim().equals("null")) { 87 | node.left = null; 88 | } else { 89 | TreeNode leftNode = new TreeNode(Integer.valueOf(leftVal.trim())); 90 | node.left = leftNode; 91 | queue.offer(leftNode); 92 | } 93 | 94 | String rightVal = list.poll(); 95 | if (rightVal == null || rightVal.trim().equals("null")) { 96 | node.right = null; 97 | } else { 98 | TreeNode rightNode = new TreeNode(Integer.valueOf(rightVal.trim())); 99 | node.right = rightNode; 100 | queue.offer(rightNode); 101 | } 102 | } 103 | 104 | return root; 105 | } 106 | 107 | public static void main(String[] args) { 108 | // 1 109 | // / \ 110 | // 2 3 111 | // / / \ 112 | // 4 5 6 113 | TreeNode root = new TreeNode(1); 114 | root.left = new TreeNode(2); 115 | root.right = new TreeNode(3); 116 | root.left.left = new TreeNode(4); 117 | root.right.left = new TreeNode(5); 118 | root.right.right = new TreeNode(6); 119 | 120 | System.out.println(root); 121 | System.out.println(serialize(root)); 122 | System.out.println(deserialize(serialize(root))); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/_39/MoreThanHalfNumber.java: -------------------------------------------------------------------------------- 1 | package _39; 2 | 3 | public class MoreThanHalfNumber { 4 | /** 5 | * 找出数组中出现次数超过数组长度一半的数字。 6 | * 如输入{1,2,3,2,2,2,5,4,2},则输出2。 7 | * 问题转化为求数组的中位数。 8 | * 可以借助快排的分区函数来实现。 9 | */ 10 | public static int moreThanHalfNum(int[] data) { 11 | return partition(data, 0, data.length - 1); 12 | } 13 | 14 | public static int partition(int[] data, int low, int high) { 15 | int pivot = data[high]; 16 | int i = low; 17 | for (int j = low; j < high; j++) { 18 | if (data[j] < pivot) { 19 | swap(data, i, j); 20 | i++; 21 | } 22 | } 23 | swap(data, i, high); 24 | 25 | if (i == (data.length - 1)/2) { 26 | return data[i]; 27 | } else if (i > (data.length - 1)/2) { 28 | return partition(data, low, i - 1); 29 | } else { 30 | return partition(data, i + 1, high); 31 | } 32 | } 33 | 34 | public static void swap(int[] data, int i, int j) { 35 | int temp = data[i]; 36 | data[i] = data[j]; 37 | data[j] = temp; 38 | } 39 | 40 | public static void main(String[] args) { 41 | int[] data = {1,2,3,2,2,2,5,4,2}; 42 | System.out.println(moreThanHalfNum(data)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/_40/KLeastNumbers.java: -------------------------------------------------------------------------------- 1 | package _40; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.PriorityQueue; 6 | 7 | public class KLeastNumbers { 8 | /** 9 | * 找出 n 个整数中最小的 k 个数。 10 | * 例如输入 4,5,1,6,2,7,3,8,则最小的 4 个数字是 1,2,3,4。 11 | * 12 | * 维护一个长度为 k 的最大堆。 13 | */ 14 | public static int[] getLeastNumbers(int[] data, int k) { 15 | if (data == null || data.length == 0 || k <= 0) { 16 | return new int[0]; 17 | } 18 | 19 | PriorityQueue queue = new PriorityQueue<>(Collections.reverseOrder()); 20 | for (int i = 0; i < data.length; i++) { 21 | if (i < k) { 22 | queue.offer(data[i]); 23 | } else { 24 | if (data[i] < queue.peek()) { 25 | queue.poll(); 26 | queue.offer(data[i]); 27 | } 28 | } 29 | } 30 | 31 | int[] result = new int[k]; 32 | for (int i = k - 1; i >= 0; i--) { 33 | result[i] = queue.poll(); 34 | } 35 | 36 | return result; 37 | } 38 | 39 | public static void main(String[] args) { 40 | int[] data = {4,5,1,6,2,7,3,8}; 41 | int[] result = getLeastNumbers(data, 4); 42 | System.out.println(Arrays.toString(result)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/_41/StreamMedian.java: -------------------------------------------------------------------------------- 1 | package _41; 2 | 3 | import java.util.Collections; 4 | import java.util.PriorityQueue; 5 | 6 | public class StreamMedian { 7 | /** 8 | * 求数据流中的中位数。 9 | * 如果长度为奇数,求中间的那个数;如果长度为偶数,求中间两个数的均值。 10 | * 11 | * 使用一个大顶堆保存前半部分数据,一个小顶堆保存后半部分数据。 12 | * 保证两个堆的数据个数相同,或者大顶堆比小顶堆个数多一。 13 | * 中位数为两个堆顶的均值,或者大顶堆的堆顶。 14 | */ 15 | public static class MedianFinder { 16 | private PriorityQueue minHeap = new PriorityQueue<>(); 17 | private PriorityQueue maxHeap = new PriorityQueue<>(Collections.reverseOrder()); 18 | 19 | public void addNum(int num) { 20 | maxHeap.offer(num); 21 | minHeap.offer(maxHeap.poll()); 22 | if (maxHeap.size() < minHeap.size()) { 23 | maxHeap.offer(minHeap.poll()); 24 | } 25 | } 26 | 27 | public double findMedian() { 28 | if (maxHeap.size() == minHeap.size()) { 29 | return (maxHeap.peek() + minHeap.peek()) * 0.5; 30 | } else { 31 | return maxHeap.peek(); 32 | } 33 | } 34 | } 35 | 36 | public static void main(String[] args) { 37 | MedianFinder medianFinder = new MedianFinder(); 38 | medianFinder.addNum(1); 39 | medianFinder.addNum(2); 40 | medianFinder.addNum(3); 41 | medianFinder.addNum(4); 42 | System.out.println(medianFinder.findMedian()); 43 | medianFinder.addNum(5); 44 | System.out.println(medianFinder.findMedian()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/_42/GreatestSumOfSubArrays.java: -------------------------------------------------------------------------------- 1 | package _42; 2 | 3 | public class GreatestSumOfSubArrays { 4 | /** 5 | * 数组中一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。 6 | * 7 | * 如果 i = 0 或者 dp[i-1] <= 0,dp[i] = data[i]; 8 | * 否则,dp[i] = dp[i-1] + data[i] 9 | */ 10 | public static int findGreatestSumOfSumArrays(int[] data) { 11 | if (data == null || data.length == 0) { 12 | return 0; 13 | } 14 | 15 | int dp = data[0]; 16 | int max = dp; 17 | 18 | for (int i = 1; i < data.length; i++) { 19 | if (dp > 0) { 20 | dp += data[i]; 21 | } else { 22 | dp = data[i]; 23 | } 24 | if (dp > max) { 25 | max = dp; 26 | } 27 | } 28 | 29 | return max; 30 | } 31 | 32 | public static void main(String[] args) { 33 | int[] data = {1,-2,3,10,-4,7,2,-5}; 34 | System.out.println(findGreatestSumOfSumArrays(data)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/_45/SortArrayForMinNumber.java: -------------------------------------------------------------------------------- 1 | package _45; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Comparator; 5 | import java.util.List; 6 | 7 | public class SortArrayForMinNumber { 8 | /** 9 | * 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,使其为所有可能的拼接结果中最小的一个。 10 | * 例如输入 {3,32,321},则输出 321323。 11 | * 12 | * 使用自定义的排序规则对数组进行排序。 13 | */ 14 | public static String printMinNumber(int[] data) { 15 | if (data == null || data.length == 0) { 16 | return ""; 17 | } 18 | 19 | List list = new ArrayList<>(); 20 | for (int item : data) { 21 | list.add(item); 22 | } 23 | 24 | list.sort(new Comparator() { 25 | @Override 26 | public int compare(Integer o1, Integer o2) { 27 | return (o1 + "" + o2).compareTo(o2 + "" + o1); 28 | } 29 | }); 30 | 31 | StringBuilder sb = new StringBuilder(); 32 | for (int item : list) { 33 | sb.append(item); 34 | } 35 | return sb.toString(); 36 | } 37 | 38 | public static void main(String[] args) { 39 | int[] data = {3, 32, 321}; 40 | System.out.println(printMinNumber(data)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/_46/TranslateNumbersToStrings.java: -------------------------------------------------------------------------------- 1 | package _46; 2 | 3 | public class TranslateNumbersToStrings { 4 | /** 5 | * 给定一个数字,按照如下规则翻译成字符串: 6 | * 0翻译成“a”,1翻译成“b”...25翻译成“z”。 7 | * 实现一个函数,用来计算一个数字有多少种不同的翻译方法。 8 | * 9 | * f(r)表示以r为开始(r最小取0)到最右端所组成的数字能够翻译成字符串的种数。 10 | * f(r-2) = f(r-1)+g(r-2,r-1)*f(r) 11 | * 如果r-2,r-1能够翻译成字符,则g(r-2,r-1)=1,否则为0。 12 | */ 13 | public static int getTranslationCount(int number) { 14 | if (number < 0) { 15 | return 0; 16 | } 17 | if (number < 10) { 18 | return 1; 19 | } 20 | 21 | String str = String.valueOf(number); 22 | int prev = 0, count = 1; 23 | for (int i = str.length() - 2; i >= 0; i--) { 24 | int temp = count ; 25 | if (Integer.valueOf(str.substring(i, i+2)) < 26) { 26 | count = count + prev; 27 | } 28 | prev = temp; 29 | } 30 | 31 | return count; 32 | } 33 | 34 | public static void main(String[] args) { 35 | System.out.println(getTranslationCount(12258)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/_47/MaxValueOfGifts.java: -------------------------------------------------------------------------------- 1 | package _47; 2 | 3 | public class MaxValueOfGifts { 4 | /** 5 | * 在一个m*n的棋盘的每一个格都放有一个礼物,每个礼物都有一定价值(大于0)。 6 | * 从左上角开始拿礼物,每次向右或向下移动一格,直到右下角结束。 7 | * 给定一个棋盘,求拿到礼物的最大价值。 8 | * 9 | * dp[i][j] = data[i][j] + max(dp[i][j+1],dp[i+1][j]) 10 | */ 11 | public static int getMaxVaule(int[][] data) { 12 | if (data == null || data.length == 0 || data[0].length == 0) { 13 | return 0; 14 | } 15 | 16 | int rowMax = data.length; 17 | int colMax = data[0].length; 18 | int[][] dp = new int[rowMax + 2][colMax + 2]; 19 | 20 | for (int row = rowMax; row > 0; row--) { 21 | for (int col = colMax; col > 0; col--) { 22 | dp[row][col] = data[row - 1][col - 1] + Math.max(dp[row][col + 1], dp[row + 1][col]); 23 | } 24 | } 25 | 26 | return dp[1][1]; 27 | } 28 | 29 | public static void main(String[] args) { 30 | int[][] data = { 31 | {1,10,3,8}, 32 | {12,2,9,6}, 33 | {5,7,4,11}, 34 | {3,7,16,5} 35 | }; 36 | System.out.println(getMaxVaule(data)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/_48/LongestSubstringWithoutDup.java: -------------------------------------------------------------------------------- 1 | package _48; 2 | 3 | public class LongestSubstringWithoutDup { 4 | /** 5 | * 输入一个字符串(只包含a~z的字符),求其最长不含重复字符的子字符串的长度。 6 | * 例如对于arabcacfr,最长不含重复字符的子字符串为acfr,长度为4。 7 | * 8 | * dp[i]表示以下标为i的字符结尾不包含重复字符的最长子字符串长度。 9 | * dp[i] = 下标 i 和前面 dp[i-1] 个字符不重复的长度。 10 | * 由于每次可以根据 dp 的前一个状态推导出后一个状态,因此可以省略 dp 数组,使用一个变量即可。 11 | */ 12 | public static int longestSubstringWithoutDup(String str) { 13 | if (str == null || str.length() == 0) { 14 | return 0; 15 | } 16 | 17 | int dp = 1; 18 | int max = 1; 19 | 20 | for (int i = 1; i < str.length(); i++) { 21 | int j = i - 1; 22 | for (; j >= i - dp; j--) { 23 | if (str.charAt(i) == str.charAt(j)) { 24 | break; 25 | } 26 | } 27 | dp = i - j; 28 | if (dp > max) { 29 | max = dp; 30 | } 31 | } 32 | 33 | return max; 34 | } 35 | 36 | public static void main(String[] args) { 37 | System.out.println(longestSubstringWithoutDup("arabcacfr")); 38 | System.out.println(longestSubstringWithoutDup("abcdefaaa")); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/_50/FirstCharacterInStream.java: -------------------------------------------------------------------------------- 1 | package _50; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | public class FirstCharacterInStream { 7 | 8 | private Queue queue; 9 | public static final char DEFAULT_CHAR = '?'; 10 | 11 | public FirstCharacterInStream() { 12 | queue = new LinkedList<>(); 13 | } 14 | 15 | public void insert(char ch) { 16 | if (queue.isEmpty()) { 17 | queue.offer(ch); 18 | } else if (queue.contains(ch)) { 19 | queue.remove(ch); 20 | } else { 21 | queue.offer(ch); 22 | } 23 | } 24 | 25 | public char find() { 26 | if (queue.isEmpty()) { 27 | return DEFAULT_CHAR; 28 | } else { 29 | return queue.peek(); 30 | } 31 | } 32 | 33 | public static void main(String[] args) { 34 | FirstCharacterInStream instance = new FirstCharacterInStream(); 35 | String str = "google"; 36 | for (char ch : str.toCharArray()) { 37 | instance.insert(ch); 38 | System.out.println(instance.find()); 39 | } 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /src/_50/FirstNotRepeatingChar.java: -------------------------------------------------------------------------------- 1 | package _50; 2 | 3 | public class FirstNotRepeatingChar { 4 | 5 | public static char firstNotRepeatingChar(String str) { 6 | int[] count = new int[256]; 7 | for (char ch : str.toCharArray()) { 8 | count[ch]++; 9 | } 10 | for (char ch : str.toCharArray()) { 11 | if (count[ch] == 1) { 12 | return ch; 13 | } 14 | } 15 | return '?'; 16 | } 17 | 18 | public static void main(String[] args) { 19 | System.out.println(firstNotRepeatingChar("abaccdeff")); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/_51/InversePairs.java: -------------------------------------------------------------------------------- 1 | package _51; 2 | 3 | public class InversePairs { 4 | /** 5 | * 输入一个数组,求出这个数组中的逆序对总数。 6 | * 例如输入{7,5,6,4},一共有5个逆序对, 7 | * 分别是(7,6),(7,5),(7,4),(6,4),(5,4)。 8 | * 9 | * 采用分治算法,利用二路归并排序实现。 10 | */ 11 | public static int inversePairs(int[] data){ 12 | if (data == null || data.length < 2) { 13 | return 0; 14 | } 15 | return mergeSort(data, 0, data.length - 1); 16 | } 17 | 18 | public static int mergeSort(int[] data, int low, int high) { 19 | int count = 0; 20 | if (low < high) { 21 | int mid = low + (high - low)/2; 22 | count += mergeSort(data, low, mid); 23 | count += mergeSort(data, mid + 1, high); 24 | count += merge(data, low, mid, high); 25 | } 26 | return count; 27 | } 28 | 29 | public static int merge(int[] data, int low, int mid, int high) { 30 | int count = 0; 31 | int[] temp = new int[high - low + 1]; 32 | int left = low; 33 | int right = mid + 1; 34 | int index = 0; 35 | 36 | while (left <= mid && right <= high) { 37 | if (data[left] > data[right]) { 38 | // 合并两个有序数组过程中,right 存在逆序对数量为 left 到 mid 的元素数量 39 | count += mid - left + 1; 40 | temp[index++] = data[right++]; 41 | } else { 42 | temp[index++] = data[left++]; 43 | } 44 | } 45 | 46 | while (left <= mid) { 47 | temp[index++] = data[left++]; 48 | } 49 | 50 | while (right <= high) { 51 | temp[index++] = data[right++]; 52 | } 53 | 54 | for (int i = low; i <= high; i++) { 55 | data[i] = temp[i - low]; 56 | } 57 | 58 | return count; 59 | } 60 | 61 | public static void main(String[] args) { 62 | int[] data1 = {7,5,6,4}; 63 | System.out.println(inversePairs(data1)); 64 | 65 | int[] data2 = {5,6,7,8,1,2,3,4}; 66 | System.out.println(inversePairs(data2)); 67 | 68 | int[] data3 = {4,3,11,15,13,2,8}; 69 | System.out.println(inversePairs(data3)); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/_52/FirstCommonNodesInLists.java: -------------------------------------------------------------------------------- 1 | package _52; 2 | 3 | import structure.ListNode; 4 | 5 | public class FirstCommonNodesInLists { 6 | public static ListNode findFirstCommonNode(ListNode head1, ListNode head2) { 7 | ListNode node1 = head1; 8 | ListNode node2 = head2; 9 | int size1 = 0, size2 = 0; 10 | 11 | while (node1 != null) { 12 | node1 = node1.next; 13 | size1++; 14 | } 15 | 16 | while (node2 != null) { 17 | node2 = node2.next; 18 | size2++; 19 | } 20 | 21 | node1 = head1; 22 | node2 = head2; 23 | 24 | while (size1 > size2) { 25 | node1 = node1.next; 26 | size1--; 27 | } 28 | 29 | while (size2 > size1) { 30 | node2 = node2.next; 31 | size2--; 32 | } 33 | 34 | while (node1 != null) { 35 | if (node1 == node2) { 36 | break; 37 | } else { 38 | node1 = node1.next; 39 | node2 = node2.next; 40 | } 41 | } 42 | 43 | return node1; 44 | } 45 | 46 | public static void main(String[] args) { 47 | // 1->2->3->6->7 48 | // 4->5↗ 49 | ListNode node1 = new ListNode<>(1); 50 | ListNode node2 = new ListNode<>(2); 51 | ListNode node3 = new ListNode<>(3); 52 | ListNode node4 = new ListNode<>(4); 53 | ListNode node5 = new ListNode<>(5); 54 | ListNode node6 = new ListNode<>(6); 55 | ListNode node7 = new ListNode<>(7); 56 | node1.next = node2; 57 | node2.next = node3; 58 | node3.next = node6; 59 | node4.next = node5; 60 | node5.next = node6; 61 | node6.next = node7; 62 | ListNode commonNode = findFirstCommonNode(node1, node4); 63 | System.out.println(commonNode.val); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/_53/MissingNumber.java: -------------------------------------------------------------------------------- 1 | package _53; 2 | 3 | public class MissingNumber { 4 | /** 5 | * 一个长度为n的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n之内。 6 | * 在范围0~n内的n个数字有且只有一个数字不在该数组中,请找出。 7 | * 8 | * 用二分查找法找到数组中第一个数值不等于下标的数字。 9 | */ 10 | public static int getMissingNumber(int[] data) { 11 | int low = 0; 12 | int high = data.length - 1; 13 | while (low <= high) { 14 | int mid = low + (high - low)/2; 15 | if (data[mid] == mid) { 16 | low = mid + 1; 17 | } else { 18 | high = mid - 1; 19 | } 20 | } 21 | return low; 22 | } 23 | 24 | public static void main(String[] args) { 25 | int[] data1 = {0,1,2,3,4,5}; //6 26 | int[] data2 = {0,1,3,4,5}; //2 27 | int[] data3 = {1,2}; //0 28 | System.out.println(getMissingNumber(data1)); 29 | System.out.println(getMissingNumber(data2)); 30 | System.out.println(getMissingNumber(data3)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/_53/NumberOfK.java: -------------------------------------------------------------------------------- 1 | package _53; 2 | 3 | public class NumberOfK { 4 | /** 5 | * 统计一个数字在排序数组中出现的次数。 6 | * 7 | * 使用二分查找,找到第一个和最后一个出现该数字的索引相减加一就是出现的次数。 8 | */ 9 | public static int getNumberOfK(int[] data, int value) { 10 | int first = searchFirst(data, value); 11 | if (first == -1) { 12 | return 0; 13 | } 14 | int last = searchLast(data, value); 15 | return last - first + 1; 16 | } 17 | 18 | public static int searchFirst(int[] data, int value) { 19 | if (data == null || data.length == 0) { 20 | return -1; 21 | } 22 | 23 | int low = 0; 24 | int high = data.length - 1; 25 | 26 | while (low <= high) { 27 | int mid = low + (high - low)/2; 28 | if (data[mid] < value) { 29 | low = mid + 1; 30 | } else if (data[mid] > value) { 31 | high = mid - 1; 32 | } else { 33 | if (mid == 0 || data[mid - 1] != value) { 34 | return mid; 35 | } else { 36 | high = mid - 1; 37 | } 38 | } 39 | } 40 | 41 | return -1; 42 | } 43 | 44 | public static int searchLast(int[] data, int value) { 45 | if (data == null || data.length == 0) { 46 | return -1; 47 | } 48 | 49 | int low = 0; 50 | int high = data.length - 1; 51 | 52 | while (low <= high) { 53 | int mid = low + (high - low) / 2; 54 | if (data[mid] < value) { 55 | low = mid + 1; 56 | } else if (data[mid] > value) { 57 | high = mid - 1; 58 | } else { 59 | if (mid == data.length - 1 || data[mid + 1] != value) { 60 | return mid; 61 | } else { 62 | low = mid + 1; 63 | } 64 | } 65 | } 66 | 67 | return -1; 68 | } 69 | 70 | public static void main(String[] args) { 71 | int[] data1 = {1,2,3,3,3,3,5,6}; 72 | int[] data2 = {1,2,3,3,3,3,4,5}; 73 | int[] data3 = {3,3,3,3,3,3,3,3}; 74 | System.out.println(getNumberOfK(data1,4)); 75 | System.out.println(getNumberOfK(data2,3)); 76 | System.out.println(getNumberOfK(data3,3)); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/_54/KthNodeInBST.java: -------------------------------------------------------------------------------- 1 | package _54; 2 | 3 | import java.util.Stack; 4 | 5 | import structure.TreeNode; 6 | 7 | // 二叉搜索树的第 k 个结点 8 | // 给定一棵二叉搜索树,请找出其中的第 k 大的结点。 9 | public class KthNodeInBST { 10 | public static TreeNode kthNode(TreeNode root, int k) { 11 | Stack stack = new Stack(); 12 | TreeNode p = root; 13 | int count = 0; 14 | 15 | while (p != null || !stack.empty()) { 16 | while (p != null) { 17 | stack.push(p); 18 | p = p.left; 19 | } 20 | p = stack.pop(); 21 | count++; 22 | if (count == k) { 23 | return p; 24 | } 25 | p = p.right; 26 | } 27 | 28 | return null; 29 | } 30 | 31 | public static void main(String[] args) { 32 | // 5 33 | // / \ 34 | // 3 7 35 | // / \ / \ 36 | // 2 4 6 8 37 | TreeNode root = new TreeNode(5); 38 | root.left = new TreeNode(3); 39 | root.right = new TreeNode(7); 40 | root.left.left = new TreeNode(2); 41 | root.left.right = new TreeNode(4); 42 | root.right.left = new TreeNode(6); 43 | root.right.right = new TreeNode(8); 44 | System.out.println(kthNode(root, 3).val); //4 45 | System.out.println(kthNode(root, 6).val); //7 46 | System.out.println(kthNode(root, 8)); //null 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/_55/BalancedBinaryTree.java: -------------------------------------------------------------------------------- 1 | package _55; 2 | 3 | import structure.TreeNode; 4 | 5 | // 平衡二叉树 6 | // 输入一棵二叉树的根结点,判断该树是不是平衡二叉树。如果某二叉树中 7 | // 任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。 8 | public class BalancedBinaryTree { 9 | public static boolean isBalanced1(TreeNode root) { 10 | if (root == null) { 11 | return true; 12 | } 13 | 14 | int left = treeDepth(root.left); 15 | int right = treeDepth(root.right); 16 | int diff = left - right; 17 | if (diff > 1 || diff < -1) { 18 | return false; 19 | } 20 | 21 | return isBalanced1(root.left) && isBalanced1(root.right); 22 | } 23 | 24 | public static boolean isBalanced2(TreeNode root) { 25 | int[] depth = new int[]{0}; 26 | return isBalanced(root, depth); 27 | } 28 | 29 | public static boolean isBalanced(TreeNode root, int[] depth) { 30 | if (root == null) { 31 | depth[0] = 0; 32 | return true; 33 | } 34 | 35 | int[] left = new int[]{0}; 36 | int[] right = new int[]{0}; 37 | 38 | if (isBalanced(root.left, left) && isBalanced(root.right, right)) { 39 | int diff = left[0] - right[0]; 40 | if (diff <= 1 && diff >= -1) { 41 | depth[0] = 1 + ((left[0] > right[0]) ? left[0] : right[0]); 42 | return true; 43 | } 44 | } 45 | 46 | return false; 47 | } 48 | 49 | public static int treeDepth(TreeNode root) { 50 | if (root == null) { 51 | return 0; 52 | } 53 | int left = treeDepth(root.left); 54 | int right = treeDepth(root.right); 55 | return (left > right) ? left + 1 : right + 1; 56 | } 57 | 58 | public static void main(String[] args) { 59 | // 1 60 | // / \ 61 | // 2 3 62 | // /\ 63 | // 4 5 64 | // / 65 | // 6 66 | TreeNode root = new TreeNode(1); 67 | root.left = new TreeNode(2); 68 | root.right = new TreeNode(3); 69 | root.left.left = new TreeNode(4); 70 | root.left.right = new TreeNode(5); 71 | root.left.right.left = new TreeNode(6); 72 | System.out.println(isBalanced1(root)); 73 | System.out.println(isBalanced2(root)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/_55/TreeDepth.java: -------------------------------------------------------------------------------- 1 | package _55; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | import structure.TreeNode; 7 | 8 | // 二叉树的深度 9 | // 输入一棵二叉树的根结点,求该树的深度。从根结点到叶结点依次经过的 10 | // 结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。 11 | public class TreeDepth { 12 | public static int treeDepthRecursively(TreeNode root) { 13 | if (root == null) { 14 | return 0; 15 | } 16 | int left = treeDepthRecursively(root.left); 17 | int right = treeDepthRecursively(root.right); 18 | return (left > right) ? left + 1 : right + 1; 19 | } 20 | 21 | public static int treeDepthIteratively(TreeNode root) { 22 | if (root == null) { 23 | return 0; 24 | } 25 | 26 | Queue queue = new LinkedList<>(); 27 | queue.offer(root); 28 | int depth = 0; 29 | 30 | while (!queue.isEmpty()) { 31 | int size = queue.size(); 32 | for (int i = 0; i < size; i++) { 33 | TreeNode node = queue.poll(); 34 | if (node.left != null) { 35 | queue.offer(node.left); 36 | } 37 | if (node.right != null) { 38 | queue.offer(node.right); 39 | } 40 | } 41 | depth++; 42 | } 43 | 44 | return depth; 45 | } 46 | 47 | public static void main(String[] args) { 48 | // 1 49 | // / \ 50 | // 2 3 51 | // /\ \ 52 | // 4 5 6 53 | // / 54 | // 7 55 | TreeNode root = new TreeNode(1); 56 | root.left = new TreeNode(2); 57 | root.left.left = new TreeNode(4); 58 | root.left.right = new TreeNode(5); 59 | root.left.right.left = new TreeNode(7); 60 | root.right = new TreeNode(3); 61 | root.right.right = new TreeNode(6); 62 | System.out.println(treeDepthRecursively(root)); // 4 63 | System.out.println(treeDepthIteratively(root)); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/_56/NumbersAppearOnce.java: -------------------------------------------------------------------------------- 1 | package _56; 2 | 3 | public class NumbersAppearOnce { 4 | 5 | /** 6 | * 一个整数数组里除了两个数字出现一次,其他数字都出现两次。 7 | * 请找出这两个数字。要求时间复杂度为o(n),空间复杂度为o(1)。 8 | *

9 | * 实例分析(以2,4,3,6,3,2,5,5为例): 10 | * 相关数字的二进制表示为: 11 | * 2 = 0010 3 = 0011 4 = 0100 12 | * 5 = 0101 6 = 0110 13 | *

14 | * 步骤1 全体异或:2^4^3^6^3^2^5^5 = 4^6 = 0010 15 | * 步骤2 确定位置:对于0010,从右数的第二位为1,因此可以根据倒数第2位是否为1进行分组 16 | * 步骤3 进行分组:分成[2,3,6,3,2]和[4,5,5]两组 17 | * 步骤4 分组异或:2^3^6^3^2 = 6,4^5^5 = 4,因此结果为4,6。 18 | */ 19 | public static int[] findNumbersAppearOnce(int[] data) { 20 | int[] result = new int[2]; 21 | 22 | int temp = 0; 23 | for (int item : data) { 24 | temp ^= item; 25 | } 26 | 27 | // 只保留最右边一位 1,其余位置为 0 28 | temp = (temp & (temp - 1)) ^ temp; 29 | 30 | for (int item : data) { 31 | if ((item & temp) == 0) { 32 | result[0] ^= item; 33 | } else { 34 | result[1] ^= item; 35 | } 36 | } 37 | 38 | return result; 39 | } 40 | 41 | public static void main(String[] args) { 42 | int[] data1 = {2, 4, 3, 6, 3, 2, 5, 5}; 43 | int[] result = findNumbersAppearOnce(data1); 44 | System.out.println(result[0]); 45 | System.out.println(result[1]); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/_56/NumbersAppearingOnce.java: -------------------------------------------------------------------------------- 1 | package _56; 2 | 3 | public class NumbersAppearingOnce { 4 | /** 5 | * 在一个整数数组中除了一个数字只出现一次外,其他数字都出现三次。找出那个出现一次的数字。 6 | *

7 | * 异或操作可以看成两个数字的每一个二进制位对应进行加法后对2取模后的结果。 8 | * 按照这种思路,对于出现三次的数字,改成对3取模即可。 9 | *

10 | * 1. 申请一个长度为32(因为int占32bit)的int型数组,用于记录整型数字每一位出现1的次数。 11 | * 2. 将每个数字计入到数组中。 12 | * 3. 数组每一个元素对 3 取模。 13 | * 4. 把数组转成 32 位的整数,就是那个出现一次的数字。 14 | */ 15 | public static int findNumberAppearingOnce(int[] data) { 16 | int[] bitSum = new int[32]; 17 | for (int item : data) { 18 | for (int i = 31; i >= 0 && item != 0; i--) { 19 | if ((item & 1) != 0) { 20 | bitSum[i]++; 21 | } 22 | item = item >> 1; 23 | } 24 | } 25 | 26 | int result = 0; 27 | for (int i = 0; i < 32; i++) { 28 | result = result << 1; 29 | result += bitSum[i] % 3; 30 | } 31 | 32 | return result; 33 | } 34 | 35 | public static void main(String[] args) { 36 | int[] data = {10, 4, 5, 3, 5, 4, 3, 3, 4, 5}; 37 | System.out.println(findNumberAppearingOnce(data)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/_58/LeftRotateString.java: -------------------------------------------------------------------------------- 1 | package _58; 2 | 3 | public class LeftRotateString { 4 | /** 5 | * 实现一个函数完成字符串的左旋转功能。比如,输入 abcdefg 和数字 2,输出为 cdefgab。 6 | */ 7 | public static String leftRotateString(String str, int k) { 8 | int n = str.length(); 9 | k = k % n; 10 | if (k == 0) { 11 | return str; 12 | } 13 | 14 | StringBuilder sb = new StringBuilder(str); 15 | 16 | reverse(sb, 0, k - 1); 17 | reverse(sb, k, n - 1); 18 | reverse(sb, 0, n - 1); 19 | 20 | return sb.toString(); 21 | } 22 | 23 | public static void reverse(StringBuilder sb, int start, int end) { 24 | for(int i = start; i <= start + (end - start)/2; i++) { 25 | char temp = sb.charAt(i); 26 | sb.setCharAt(i, sb.charAt(end - i + start)); 27 | sb.setCharAt(end - i + start, temp); 28 | } 29 | } 30 | 31 | public static void main(String[] args) { 32 | System.out.println(leftRotateString("abcdefg", 2)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/_58/ReverseWordsInSentence.java: -------------------------------------------------------------------------------- 1 | package _58; 2 | 3 | public class ReverseWordsInSentence { 4 | /** 5 | * 输入一个英文句子,翻转单词顺序,单词内字符不翻转,标点符号和普通字母一样处理。 6 | * 例如输入输入“I am a student.”,则输出“student. a am I”。 7 | * 8 | * 首先字符串整体翻转,得到“.tneduts a ma I”; 9 | * 然后以空格作为分隔符进行切分,对于切分下来的每一部分再进行翻转, 10 | * 得到“student. a am I”。 11 | */ 12 | public static String reverse(String str) { 13 | StringBuilder sb = new StringBuilder(str); 14 | reverse(sb, 0, sb.length() - 1); 15 | 16 | int start = 0; 17 | int end = sb.indexOf(" "); 18 | while (start < sb.length() && end != -1) { 19 | reverse(sb, start, end - 1); 20 | start = end + 1; 21 | end = sb.indexOf(" ", start); 22 | } 23 | 24 | if (start < sb.length()) { 25 | reverse(sb, start, sb.length() - 1); 26 | } 27 | 28 | return sb.toString(); 29 | } 30 | 31 | public static void reverse(StringBuilder sb, int start, int end) { 32 | for(int i = start; i <= start + (end - start)/2; i++) { 33 | char temp = sb.charAt(i); 34 | sb.setCharAt(i, sb.charAt(end - i + start)); 35 | sb.setCharAt(end - i + start, temp); 36 | } 37 | } 38 | 39 | public static void main(String[] args) { 40 | System.out.println(reverse("I am a student.")); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/_59/MaxInSlidingWindow.java: -------------------------------------------------------------------------------- 1 | package _59; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.PriorityQueue; 6 | import java.util.Queue; 7 | 8 | public class MaxInSlidingWindow { 9 | /** 10 | * 给定一个数组和滑动窗口的大小,请找出所有滑动窗口的最大值。 11 | * 例如,输入数组{2,3,4,2,6,2,5,1}和数字3, 12 | * 那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}。 13 | */ 14 | public static int[] maxSlidingWindow(int[] nums, int k) { 15 | if (nums == null || k <= 0 || k > nums.length) { 16 | return new int[0]; 17 | } 18 | 19 | Queue queue = new PriorityQueue<>(Collections.reverseOrder()); 20 | int i = 0; 21 | for (; i < k; i++) { 22 | queue.offer(nums[i]); 23 | } 24 | 25 | int[] result = new int[nums.length - k + 1]; 26 | int index = 0; 27 | result[index++] = queue.peek(); 28 | 29 | for (; i < nums.length; i++) { 30 | queue.remove(nums[i - k]); 31 | queue.offer(nums[i]); 32 | result[index++] = queue.peek(); 33 | } 34 | 35 | return result; 36 | } 37 | 38 | public static void main(String[] args) { 39 | int[] data = {2, 3, 4, 2, 6, 2, 5, 1}; 40 | int[] result = maxSlidingWindow(data, 3); 41 | System.out.println(Arrays.toString(result)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/_65/AddTwoNumbers.java: -------------------------------------------------------------------------------- 1 | package _65; 2 | 3 | public class AddTwoNumbers { 4 | 5 | /** 6 | * 写一个函数,求两个正数之和,要求在函数体内不能使用四则运算符号。 7 | * 8 | * 以0011(即3)与0101(即5)相加为例说明 9 | * 1.两数进行异或: 0011^0101=0110 这个数字其实是把原数中不需进位的二进制位进行了组合 10 | * 2.两数进行与: 0011&0101=0001 这个数字为1的位置表示需要进位,而进位动作是需要向前一位进位 11 | * 3.左移一位: 0001<<1=0010 12 | * 13 | * 此时我们就完成0011 + 0101 = 0110 + 0010的转换 14 | * 15 | * 如此转换下去,直到其中一个数字为0时,另一个数字就是原来的两个数字的和 16 | */ 17 | public static int add(int a, int b) { 18 | int sum = a ^ b; 19 | int carry = (a & b) << 1; 20 | 21 | while (carry != 0) { 22 | int temp = sum; 23 | sum = sum ^ carry; 24 | carry = (temp & carry) << 1; 25 | } 26 | 27 | return sum; 28 | } 29 | 30 | public static void main(String[] args) { 31 | System.out.println(add(3, 5)); 32 | System.out.println(add(3, -5)); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/_65/ExchangeTwoNumbers.java: -------------------------------------------------------------------------------- 1 | package _65; 2 | 3 | public class ExchangeTwoNumbers { 4 | /** 5 | * 不使用新的变量完成交换两个原有变量的值。 6 | */ 7 | public static void main(String[] args) { 8 | int a = 3, b = 5; 9 | System.out.println("before swap: a = " + a + ", b = " + b); 10 | 11 | a = a ^ b; 12 | b = a ^ b; 13 | a = a ^ b; 14 | 15 | System.out.println("after swap: a = " + a + ", b = " + b); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/structure/BinaryTree.java: -------------------------------------------------------------------------------- 1 | package structure; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import java.util.Queue; 7 | import java.util.Stack; 8 | 9 | public class BinaryTree { 10 | public static List preorderIteratively(TreeNode root) { 11 | List list = new ArrayList<>(); 12 | Stack stack = new Stack<>(); 13 | TreeNode p = root; 14 | 15 | while (p != null || !stack.empty()) { 16 | while (p != null) { 17 | list.add(p.val); 18 | stack.push(p); 19 | p = p.left; 20 | } 21 | p = stack.pop(); 22 | p = p.right; 23 | } 24 | 25 | return list; 26 | } 27 | 28 | public static List inorderIteratively(TreeNode root) { 29 | List list = new ArrayList<>(); 30 | Stack stack = new Stack<>(); 31 | TreeNode p = root; 32 | 33 | while (p != null || !stack.empty()) { 34 | while (p != null) { 35 | stack.push(p); 36 | p = p.left; 37 | } 38 | p = stack.pop(); 39 | list.add(p.val); 40 | p = p.right; 41 | } 42 | 43 | return list; 44 | } 45 | 46 | public static List postorderIteratively(TreeNode root) { 47 | List list = new ArrayList<>(); 48 | Stack stack = new Stack<>(); 49 | TreeNode cur = root; 50 | TreeNode last = null; 51 | 52 | while (cur != null || !stack.empty()) { 53 | while (cur != null) { 54 | stack.push(cur); 55 | cur = cur.left; 56 | } 57 | cur = stack.peek(); 58 | if (cur.right == null || cur.right == last) { 59 | list.add(cur.val); 60 | stack.pop(); 61 | last = cur; 62 | cur = null; 63 | } else { 64 | cur = cur.right; 65 | } 66 | } 67 | 68 | return list; 69 | } 70 | 71 | public static List levelOrder(TreeNode root) { 72 | List list = new ArrayList<>(); 73 | if (root == null) { 74 | return list; 75 | } 76 | 77 | Queue queue = new LinkedList<>(); 78 | queue.offer(root); 79 | 80 | while (!queue.isEmpty()) { 81 | TreeNode node = queue.poll(); 82 | list.add(node.val); 83 | if (node.left != null) { 84 | queue.offer(node.left); 85 | } 86 | if (node.right != null) { 87 | queue.offer(node.right); 88 | } 89 | } 90 | 91 | return list; 92 | } 93 | 94 | public static void main(String[] args) { 95 | TreeNode node1 = new TreeNode(1); 96 | TreeNode node2 = new TreeNode(2); 97 | TreeNode node3 = new TreeNode(3); 98 | TreeNode node4 = new TreeNode(4); 99 | TreeNode node5 = new TreeNode(5); 100 | node1.left = node2; 101 | node1.right = node3; 102 | node2.left = node4; 103 | node2.right = node5; 104 | 105 | // 1 106 | // / \ 107 | // 2 3 108 | // / \ 109 | // 4 5 110 | 111 | System.out.println(preorderIteratively(node1)); // 1,2,4,5,3 112 | System.out.println(inorderIteratively(node1)); // 4,2,5,1,3 113 | System.out.println(postorderIteratively(node1));// 4,5,2,3,1 114 | System.out.println(levelOrder(node1)); // 1,2,3,4,5 115 | System.out.println(node1); // 1,2,3,4,5 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/structure/ListNode.java: -------------------------------------------------------------------------------- 1 | package structure; 2 | 3 | public class ListNode { 4 | public T val; 5 | public ListNode next; 6 | 7 | public ListNode(T val) { 8 | this.val = val; 9 | } 10 | 11 | @Override 12 | public String toString() { 13 | StringBuilder sb = new StringBuilder(); 14 | sb.append("["); 15 | for (ListNode p = this; p != null; p = p.next) { 16 | sb.append(p.val); 17 | if (p.next != null) { 18 | sb.append(","); 19 | } 20 | } 21 | sb.append("]"); 22 | return sb.toString(); 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /src/structure/TreeNode.java: -------------------------------------------------------------------------------- 1 | package structure; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import java.util.Queue; 7 | 8 | public class TreeNode { 9 | public int val; 10 | public TreeNode left; 11 | public TreeNode right; 12 | 13 | public TreeNode(int val) { 14 | this.val = val; 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | List list = new ArrayList<>(); 20 | Queue queue = new LinkedList<>(); 21 | queue.offer(this); 22 | 23 | while (!queue.isEmpty()) { 24 | TreeNode node = queue.poll(); 25 | if (node == null) { 26 | list.add("null"); 27 | continue; 28 | } else { 29 | list.add("" + node.val); 30 | } 31 | 32 | if (node.left != null) { 33 | queue.offer(node.left); 34 | } else { 35 | queue.offer(null); 36 | } 37 | 38 | if (node.right != null) { 39 | queue.offer(node.right); 40 | } else { 41 | queue.offer(null); 42 | } 43 | } 44 | 45 | for (int i = list.size() - 1; i >= 0; i--) { 46 | if (list.get(i).equals("null")) { 47 | list.remove(i); 48 | } else { 49 | break; 50 | } 51 | } 52 | 53 | StringBuilder sb = new StringBuilder(); 54 | sb.append("["); 55 | for (int i = 0; i < list.size(); i++) { 56 | sb.append(list.get(i)); 57 | if (i == list.size() - 1) { 58 | sb.append("]"); 59 | } else { 60 | sb.append(", "); 61 | } 62 | } 63 | 64 | return sb.toString(); 65 | } 66 | } 67 | --------------------------------------------------------------------------------