diff --git a/Week_01/id_14/LeetCode_20_14.java b/Week_01/id_14/LeetCode_20_14.java new file mode 100644 index 00000000..8ea9d07f --- /dev/null +++ b/Week_01/id_14/LeetCode_20_14.java @@ -0,0 +1,76 @@ +import java.util.Stack; + +/** +* https://leetcode-cn.com/problems/valid-parentheses/ +*
栈 stack +*
简单 +*/ +public class LeetCode_20_14 { + + public static void main(String[] args) { + Solution solution = new Solution(); + + String[] arrs = {"()" + , "()[]{}" + , "(]" + , "([)]" + , "{[]}"}; + boolean[] results = {true, true, false, false, true}; + for (int i = 0; i < arrs.length; i++) { + System.out.println(arrs[i] + ":" + (results[i] == solution.isValid(arrs[i]))); + } + } + + static class Solution { + private final static char[] A = {'(', '{', '[', ']', '}', ')'}; + + /** + * 利用java的Stack,遇到左括号,就入栈(push),遇到右括号就出栈(pop) + *
+ * 1. 如果需要出栈时,栈为空,无效表达式 + * 2. 左右括号的差值,只有1或2,直接使用当前byte和pop的做差值运算。不等于1或2,就不匹配 + * 3. 性能不太好 + *+ * @param s + * @return + */ + public boolean isValid(String s) { + if (s == null) { + return true; + } + Stack
+ * 40 (
+ * 41 )
+ * 91 [
+ * 93 ]
+ * 123 {
+ * 125 }
+ *
+ */
+ int tmp = chars[i] - stack.pop();
+ if (tmp != 1 && tmp != 2) {
+ return false;
+ }
+ }
+ }
+
+ return stack.empty();
+ }
+ }
+
+}
+/**
+ * 执行用时 : 7 ms, 在Valid Parentheses的Java提交中击败了79.22% 的用户
+ * 内存消耗 : 34 MB, 在Valid Parentheses的Java提交中击败了89.16% 的用户
+ */
diff --git a/Week_01/id_14/LeetCode_21_14.java b/Week_01/id_14/LeetCode_21_14.java
new file mode 100644
index 00000000..c285e3e0
--- /dev/null
+++ b/Week_01/id_14/LeetCode_21_14.java
@@ -0,0 +1,229 @@
+/**
+ * https://leetcode-cn.com/problems/merge-two-sorted-lists/submissions/
+ *
+ * 链表 + *
简单 + * + * @author Yunjian Liu + * @date 2019/04/17 + */ +public class LeetCode_21_14 { + public static void main(String[] args) { + Solution solution = new Solution(); + + ListNode listNode1 = new ListNode(1); + listNode1.next = new ListNode(2); + //listNode1.next.next = new ListNode(4); + listNode1.next.next = new ListNode(2); + listNode1.next.next.next = new ListNode(2); + listNode1.next.next.next.next = new ListNode(4); + listNode1.next.next.next.next.next = new ListNode(5); + listNode1.next.next.next.next.next.next = new ListNode(5); + + ListNode listNode2 = new ListNode(1); + listNode2.next = new ListNode(3); + listNode2.next.next = new ListNode(4); + + ListNode listNode3 = solution.mergeTwoLists(listNode1, listNode2); + + while (listNode3 != null) { + System.out.print(listNode3.val + "->"); + listNode3 = listNode3.next; + } + } +} + +class Solution { + /** + *
+ * +-----+ +-----+ +-----+ + * | 1 | --> | 2 | --> | 4 | + * +-----+ +-----+ +-----+ + * + * +-----+ +-----+ +-----+ + * | 1 | --> | 3 | --> | 4 | + * +-----+ +-----+ +-----+ + * + * cur + * | + * listNode + * | + * +-----+ +-----+ +-----+ + * | 1 | --> | 2 | --> | 4 | + * +-----+ +-----+ +-----+ + * p + * | + * +-----+ +-----+ +-----+ + * | 1 | --> | 3 | --> | 4 | + * +-----+ +-----+ +-----+ + * + * + * listNode tmp + * | | + * +-----+ +-----+ +-----+ + * | 1 | --> | 2 | --> | 4 | + * +-----+ +-----+ +-----+ + * cur + * | + * p + * | + * +-----+ +-----+ +-----+ + * | 1 | --> | 3 | --> | 4 | + * +-----+ +-----+ +-----+ + * + * listNode p + * | | + * +-----+ +-----+ +-----+ + * | 1 | | 2 | --> | 4 | + * +-----+ +-----+ +-----+ + * | + * | + * cur + * | + * +-----+ +-----+ +-----+ + * | 1 | --> | 3 | --> | 4 | + * +-----+ +-----+ +-----+ + * + * + * + * listNode p + * | | + * +-----+ +-----+ +-----+ + * | 1 | | 2 | --> | 4 | + * +-----+ +-----+ +-----+ + * | + * | + * cur tmp + * | | + * +-----+ +-----+ +-----+ + * | 1 | --> | 3 | --> | 4 | + * +-----+ +-----+ +-----+ + * + * listNode p + * | | + * +-----+ +-----+ +-----+ + * | 1 | | 2 | --> | 4 | + * +-----+ +-----+ +-----+ + * | ^ + * | | + * cur | tmp + * | | | + * +-----+ | +-----+ +-----+ + * | 1 | -->---- | 3 | --> | 4 | + * +-----+ +-----+ +-----+ + * + * + * listNode cur + * | | + * +-----+ +-----+ +-----+ + * | 1 | | 2 | --> | 4 | + * +-----+ +-----+ +-----+ + * | ^ + * | | + * cur | p + * | | | + * +-----+ | +-----+ +-----+ + * | 1 | -->---- | 3 | --> | 4 | + * +-----+ +-----+ +-----+ + * + * + * listNode cur tmp + * | | | + * +-----+ +-----+ +-----+ + * | 1 | | 2 | --> | 4 | + * +-----+ +-----+ +-----+ + * | ^ + * | | + * cur | p + * | | | + * +-----+ | +-----+ +-----+ + * | 1 | -->---- | 3 | --> | 4 | + * +-----+ +-----+ +-----+ + * + * + * listNode cur tmp + * | | | + * +-----+ +-----+ +-----+ + * | 1 | | 2 | -->----- | 4 | + * +-----+ +-----+ | +-----+ + * | ^ | + * | | | + * cur | p + * | | | + * +-----+ | +-----+ +-----+ + * | 1 | -->---- | 3 | --> | 4 | + * +-----+ +-----+ +-----+ + * + * + * listNode p + * | | + * +-----+ +-----+ +-----+ + * | 1 | | 2 | -->----- | 4 | + * +-----+ +-----+ | +-----+ + * | ^ cur + * | | | + * cur | | + * | | | + * +-----+ | +-----+ +-----+ + * | 1 | -->---- | 3 | --> | 4 | + * +-----+ +-----+ +-----+ + * + * + * listNode p + * | | + * +-----+ +-----+ +-----+ + * | 1 | | 2 | -->----- | 4 | + * +-----+ +-----+ | +-----+ + * | ^ | + * | | | + * cur | | cur + * | | | | + * +-----+ | +-----+ +-----+ + * | 1 | -->---- | 3 | --> | 4 | + * +-----+ +-----+ +-----+ + * + *+ * + * 思路: + *
+ * 用一个指针,指向当前节点(cur)。另一个指针(p)指向,另一个链还未合并进来的第一个位置。 + * 1. 比较p的cur的next,如果p更小,那么就把p接到合并链中。 + * + * 如果一个链已经比较完,把p链直接接到最后 + *+ *
会破坏原来的链表 + * @param l1 + * @param l2 + * @return + */ + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if(l1 == null) { + return l2; + } + if(l2 == null) { + return l1; + } + ListNode listNode = l1; + + ListNode p = l2; + if (l2.val < l1.val) { + listNode = l2; + p = l1; + } + ListNode cur = listNode; + + while (cur.next != null) { + if (p.val < cur.next.val) { + ListNode tmp = cur.next; + cur.next = p; + cur = p; + p = tmp; + } else { + cur = cur.next; + } + } + cur.next = p; + + return listNode; + } +} diff --git a/Week_01/id_14/LeetCode_242_14.java b/Week_01/id_14/LeetCode_242_14.java new file mode 100644 index 00000000..094e251c --- /dev/null +++ b/Week_01/id_14/LeetCode_242_14.java @@ -0,0 +1,104 @@ +import java.util.Arrays; + +/** + * https://leetcode-cn.com/problems/valid-anagram/ + *
数组 两个字符串是否是异位词 + *
简单 + */ +public class LeetCode_242_14 { + public static void main(String[] args) { + Solution solution = new Solution(); + Solution2 solution2 = new Solution2(); + + String s = "anagram"; + String t = "nagaram"; + + System.out.println(solution.isAnagram(s, t)); + System.out.println(solution2.isAnagram(s, t)); + System.out.println(solution.isAnagram("rat", "car")); + System.out.println(solution.isAnagram("", "")); + System.out.println(solution2.isAnagram("rat", "car")); + System.out.println(solution2.isAnagram("", "")); + } + + /** + * 假设字符串只包含小写字母,字母异位词。 + *
+ * 1. 异位就是所有的字母个数都是一样的,只是位置不同 + * 2. 只有小写字母。a-z (26)个字母。数组arr[26] + * 3. 看每个字母是否相等 + *+ */ + static class Solution2 { + + public boolean isAnagram(String s, String t) { + if (s == null || t == null) { + return false; + } + + if (s.length() != t.length()) { + return false; + } + + if (s.equals(t)) { + return true; + } + + int[] arr = new int[26]; + + for (int i : s.toCharArray()) { + arr[i - 'a']++; + } + for (int i : t.toCharArray()) { + arr[i - 'a']--; + } + + for (int i = 0; i < arr.length; i++) { + if (arr[i] != 0) { + return false; + } + } + + return true; + } + } + + /** + * 这种解法,先排序,再比较。效率低。其实是可以不排序的,日常开发、设计也需要注意 + * char数组排序直接用JDK实现的排序了。 这个可以尝试自己实现 + *
+ * 1. 先对两个字符串内部char数组排序。O(n)。 O(2n) + * 2. 再遍历对比每个char O(n) + * 3. 总体时间复杂度。O(2n)+O(n)=O(3n)=O(n) + *+ */ + static class Solution { + + public boolean isAnagram(String s, String t) { + if (s == null || t == null) { + return false; + } + + if (s.length() != t.length()) { + return false; + } + + if (s.equals(t)) { + return true; + } + + char[] ss = s.toCharArray(); + Arrays.sort(ss); + char[] ts = t.toCharArray(); + Arrays.sort(ts); + + for (int i = 0; i < ss.length; i++) { + if (ss[i] != ts[i]) { + return false; + } + } + + return true; + } + } +} diff --git a/Week_01/id_14/LeetCode_687_14.java b/Week_01/id_14/LeetCode_687_14.java new file mode 100644 index 00000000..525403e8 --- /dev/null +++ b/Week_01/id_14/LeetCode_687_14.java @@ -0,0 +1,101 @@ +/** +* https://leetcode-cn.com/problems/longest-univalue-path/ +*
递归 二叉树 +*
简单 +*/ +public class LeetCode_687_14 { + public static void main(String[] args) { + Solution solution = new Solution(); + + TreeNode root = new TreeNode(5); + root.left = new TreeNode(4); + root.left.left = new TreeNode(1); + root.left.right = new TreeNode(1); + + root.right = new TreeNode(5); + root.right.right = new TreeNode(5); + + System.out.println("2:" + solution.longestUnivaluePath(root)); + + TreeNode root2 = new TreeNode(-9); + root2.left = new TreeNode(5); + root2.left.left = new TreeNode(-2); + root2.left.right = new TreeNode(-6); + root2.left.left.left = new TreeNode(5); + root2.left.left.left.left = new TreeNode(-3); + root2.left.left.left.right = new TreeNode(6); + root2.left.left.left.left.left = new TreeNode(-5); + root2.left.left.left.left.left.left = new TreeNode(0); + + root2.right = new TreeNode(0); + + System.out.println("0:" + solution.longestUnivaluePath(root2)); + + TreeNode root3 = new TreeNode(5); + root3.left = new TreeNode(5); + root3.left.left = new TreeNode(5); + root3.left.right = new TreeNode(5); + root3.left.left.left = new TreeNode(5); + root3.left.left.left.left = new TreeNode(5); + + root3.right = new TreeNode(4); + + System.out.println("4:" + solution.longestUnivaluePath(root3)); + } + + /** + * 这道题开始的理解、思路都有问题。本身使用递归没有问题。 + *
+ * 1. 开始没有考虑多余一段最长路径的比较 + * 2. 最大值的保存,开始一直想用参数传递!!! Integer也无法引用传递?! 最后才使用成员变量,每次需要重置为0 + * 3. 下图的最长=4,而不是5 + * + * 5 + * /\ + * 5 4 + * /\ + * 5 5 + * | + * 5 + * / + * 5 + *+ */ + static class Solution { + private int max = 0; + + public int longestUnivaluePath(TreeNode root) { + //注意重置,对象会重用 + max = 0; + getMax(root); + return max; + } + + private int getMax(TreeNode root) { + if (root == null) { + return 0; + } + if (root.left == null && root.right == null) { + return 0; + } + + int left = getMax(root.left); + int right = getMax(root.right); + + int tmpLeft = 0; + if (root.left != null && root.val == root.left.val) { + tmpLeft = left + 1; + } + int tmpRight = 0; + if (root.right != null && root.val == root.right.val) { + tmpRight = right + 1; + } + + max = Math.max(tmpLeft + tmpRight, max); + + //返回左、右的大值,而不是相加的值 + return Math.max(tmpLeft, tmpRight); + + } + } +} diff --git a/Week_01/id_14/LeetCode_83_14.java b/Week_01/id_14/LeetCode_83_14.java new file mode 100644 index 00000000..98a65383 --- /dev/null +++ b/Week_01/id_14/LeetCode_83_14.java @@ -0,0 +1,50 @@ +/** +* https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/ +*
链表 +*
简单 +* +*
这个比较简单,但是正因为简单,所以大家使用的方法都类似,有什么优化发方案? +* @author Yunjian Liu +* @date 2019/04/17 +*/ +public class LeetCode_83_14 { + public static void main(String [] args) { + Solution solution = new Solution(); + + ListNode listNode1 = new ListNode(1); + listNode1.next = new ListNode(1); + //listNode1.next.next = new ListNode(4); + listNode1.next.next = new ListNode(2); + listNode1.next.next.next = new ListNode(2); + listNode1.next.next.next.next = new ListNode(4); + listNode1.next.next.next.next.next = new ListNode(5); + listNode1.next.next.next.next.next.next = new ListNode(5); + + ListNode listNode3 = solution.deleteDuplicates(listNode1); + + while (listNode3 != null) { + System.out.print(listNode3.val + "->"); + listNode3 = listNode3.next; + } + } + + static class Solution { + public ListNode deleteDuplicates(ListNode head) { + if(head == null) { + return head; + } + ListNode cur = head; + + while (cur.next != null) { + if(cur.val == cur.next.val) { + cur.next = cur.next.next; + }else { + cur = cur.next; + + } + } + + return head; + } + } +} diff --git a/Week_01/id_14/LeetCode_905_14.java b/Week_01/id_14/LeetCode_905_14.java new file mode 100644 index 00000000..15fe7fa8 --- /dev/null +++ b/Week_01/id_14/LeetCode_905_14.java @@ -0,0 +1,74 @@ +import java.util.Arrays; + +/** + * https://leetcode-cn.com/problems/sort-array-by-parity/submissions/ + * + *
数组 + *
简单 + * + * @author Yunjian Liu + * @date 2019/04/16 + */ +public class LeetCode_905_14{ + public static void main(String[] args) { + Solution solution = new Solution(); + + int[] a = {1, 23, 45, 66, 78, 53}; + System.out.println(Arrays.toString(a)); + int[] b = solution.sortArrayByParity(a); + System.out.println(Arrays.toString(b)); + } +} + +class Solution { + /** + * 使用双指针 + *
+ * 1. 低位,一直检测是否是偶数,是就一直往前走,直到遇到奇数或高位指针 + *+ * + * @param a + * @return + */ + public int[] sortArrayByParity(int[] a) { + int low = 0; + int high = a.length - 1; + high = Math.min(high, 5000); + + while (low < high) { + while ((a[low] & 1) == 0 && low < high) { + low++; + } + while ((a[high] & 1) == 1 && low < high) { + high--; + } + + if (low < high) { + int tmp = a[low]; + a[low] = a[high]; + a[high] = tmp; + low++; + high--; + } + } + + return a; + } +} +/** + *+ * 2. 高位,一直检测是否是期数,是就一直往前走,直到遇到偶数或地位指针 + *
+ * 3. 交换数据 + *
+ * 交换时,未使用 low++,high-- + * 执行用时 : 3 ms, 在Sort Array By Parity的Java提交中击败了99.80% 的用户 + * 内存消耗 : 42.8 MB, 在Sort Array By Parity的Java提交中击败了81.17% 的用户 + *+ *
+ * 不使用,每次交换后,需要多进行2次比较 + * 交换时,使用 low++,high-- + * 执行用时 : 3 ms, 在Sort Array By Parity的Java提交中击败了99.80% 的用户 + * 内存消耗 : 39.5 MB, 在Sort Array By Parity的Java提交中击败了93.62% 的用户 + *+ */ diff --git a/Week_01/id_14/LeetCode_922_14.java b/Week_01/id_14/LeetCode_922_14.java new file mode 100644 index 00000000..b3a43851 --- /dev/null +++ b/Week_01/id_14/LeetCode_922_14.java @@ -0,0 +1,120 @@ +import java.util.Arrays; + +/** + * https://leetcode-cn.com/problems/sort-array-by-parity-ii/submissions/ + * + *
数组 + *
简单 + * + * @author Yunjian Liu + * @date 2019/04/17 5:40 AM + */ +public class LeetCode_922_14 { + public static void main(String[] args) { + Solution solution = new Solution(); + + int[] a = {1, 23, 45, 66, 53, 78, 62, 8}; + System.out.println(Arrays.toString(a)); + int[] b = solution.sortArrayByParityII(a); + System.out.println(Arrays.toString(b)); + } +} + +class Solution { + /** + * 和905 类似的思路。 使用双指针 + *
+ * 1. 偶数下标,一直检测是否是偶数,是就一直往前走,直到遇到奇数 + *+ *+ * 2. 奇数下标,一直检测是否是奇数,是就一直往前走,直到遇到偶数 + *
+ * 3. 交换数据 + *
+ * even odd + * | | + * | | + * +----+----+----+----+----+----+----+----+ + * | 1 | 23 | 45 | 66 | 78 | 53 | 62 | 8 | + * +----+----+----+----+----+----+----+----+ + * 0 1 2 3 4 5 6 7 + * even odd + * | | + * | | + * +----+----+----+----+----+----+----+----+ + * | 1 | 23 | 45 | 66 | 78 | 53 | 62 | 8 | + * +----+----+----+----+----+----+----+----+ + * 0 1 2 3 4 5 6 7 + * even odd + * | | + * | | + * +----+----+----+----+----+----+----+----+ + * | 66 | 23 | 45 | 1 | 78 | 53 | 62 | 8 | + * +----+----+----+----+----+----+----+----+ + * 0 1 2 3 4 5 6 7 + * even odd + * | | + * | | + * +----+----+----+----+----+----+----+----+ + * | 66 | 23 | 45 | 1 | 78 | 53 | 62 | 8 | + * +----+----+----+----+----+----+----+----+ + * 0 1 2 3 4 5 6 7 + * even odd + * | | + * | | + * +----+----+----+----+----+----+----+----+ + * | 66 | 23 | 45 | 1 | 78 | 53 | 62 | 8 | + * +----+----+----+----+----+----+----+----+ + * 0 1 2 3 4 5 6 7 + * even odd + * | | + * | | + * +----+----+----+----+----+----+----+----+ + * | 66 | 23 | 8 | 1 | 78 | 53 | 62 | 45 | + * +----+----+----+----+----+----+----+----+ + * 0 1 2 3 4 5 6 7 + * even odd + * | | + * | | + * +----+----+----+----+----+----+----+----+ + * | 66 | 23 | 8 | 1 | 78 | 53 | 62 | 45 | + * +----+----+----+----+----+----+----+----+ + * 0 1 2 3 4 5 6 7 + *+ *
+ * 和905类似的思路
+ *
+ * @param a
+ * @return
+ **/
+ public int[] sortArrayByParityII(int[] a) {
+ int even = 0;
+ int odd = 1;
+ int len = a.length;
+ while (even < len - 1 && odd < len) {
+ while ((a[even] & 1) == 0) {
+ if (even == len - 2) {
+ return a;
+ }
+ even = even + 2;
+ }
+
+ while ((a[odd] & 1) == 1) {
+ if (odd == len - 1) {
+ return a;
+ }
+ odd = odd + 2;
+ }
+
+ if (even < len - 1 && odd < len) {
+ int tmp = a[even];
+ a[even] = a[odd];
+ a[odd] = tmp;
+ even = even + 2;
+ odd = odd + 2;
+ }
+ }
+
+ return a;
+ }
+}
diff --git a/Week_01/id_14/ListNode.java b/Week_01/id_14/ListNode.java
new file mode 100644
index 00000000..07c15719
--- /dev/null
+++ b/Week_01/id_14/ListNode.java
@@ -0,0 +1,6 @@
+public class ListNode {
+ int val;
+ ListNode next;
+
+ ListNode(int x) { val = x; }
+}
diff --git a/Week_01/id_14/NOTE.md b/Week_01/id_14/NOTE.md
index c684e62f..c38165b3 100644
--- a/Week_01/id_14/NOTE.md
+++ b/Week_01/id_14/NOTE.md
@@ -1 +1,47 @@
-# 学习笔记
\ No newline at end of file
+# 学习笔记
+### 04.19
+#### 基础
+
+数组
+ * 内存中连续的存储空间
+ * 适合指定下标获取元素
+ * 中间插入、删除后,移动后续的元素,都需要较高的时间成本
+ * 固定大小,需要扩容时,需要一块新的内存空间,而且需要复制元素的时间成本
+ * 无序数组,
+ * 有序数组,要使用二分查找,都必须是有序的数组,如果是不变化的数组,要多次查找,一般采用1次排序,多次查询
+ * 典型场景
+ > 固定范围(可以通过O(1)映射到具体的数组下标),比如只有小写字母的一个字符串,每个a-z的字符k,可以通过k-a直接映射到数组下标,再通过下标直接获取元素
+
+链表
+ * 每个节点,独立存在内存中(可以不连续),通过指针/引用建立节点之间的关系
+ * 插入、删除节点容易
+ * 如果指定一个节点value去删除一个元素,首先得通过遍历,查找到这个节点
+ * 如果指定一个节点的前序指针/应用,那么删除就不需要遍历查找(单链表,双链表都可以),
+ * 如果指定一个节点的指针/引用 ,单链表还是需要遍历找到该节点的前序节点,才能删除;这种情况双向链表就不再需要遍历查询的步骤
+
+栈
+ > 特殊的后进先出,常用的场景对栈的操作也比较简单,入栈push,出栈pop,查看栈顶元素peek,使用场景也比较特殊,比如常见的:表达式的合法性检查、浏览器的前进后退;基本也不会对栈进行排序、查找等操作。可以进一步自己使用数组、链表自己实现一个栈。(后面根据Leetcode的题练习一下其他的使用场景)
+
+递归
+ 有2点真的很重要
+ * 终止条件
+ * 思维上一定要"信任"下一层的递归结果,不用把自己带入下一层的逻辑中
+
+排序
+ > 以前学习排序,老是去记各种排序算法的具体实现,没有总结特殊、使用背景,一段时间就忘记。这次根据老师分析的时间复杂度、是否是稳定性排序、是否是原地排序;为什么要用稳定排序,像订单排序中,先用订单号(不重复)排序,再用金额(重复)排序,后面的用金额排序就需要用稳定排序。归并、快排都是利用分治思想,快排不稳定,归并不是原地排序,都需要根据场景来决定排序,不死记硬背。
+
+二分查找
+ > 基本都是使用在排序好的数组上?
+ * 有序的才有意义,否则不好比较
+ * 数组能快速容易的用下标折半定位
+
+进阶
+ * 更多的场景是有相同的元素,注意边界条件
+ * 大于某个数的第一个元素的查找等
+
+### 学习态度
+> 追求掌握,训练思维,有没学会自己最清楚;一定要动手实现
+
+
+### 04.10 test
+> 马上开课了
diff --git a/Week_01/id_14/README.md b/Week_01/id_14/README.md
new file mode 100644
index 00000000..dad27083
--- /dev/null
+++ b/Week_01/id_14/README.md
@@ -0,0 +1,7 @@
+* LeetCode_905_14.java array sort-array-by-parity
+* LeetCode_922_14.java array sort-array-by-parity-ii
+* LeetCode_242_14.java array valid-anagram 异位词
+* LeetCode_20_14.java stack valid-parentheses
+* LeetCode_21_14.java list merge-two-sorted-lists
+* LeetCode_83_14.java list remove-duplicates-from-sorted-list
+* LeetCode_687_14.java tree(binary tree)/recursion longest-univalue-path. use recursion
diff --git a/Week_01/id_14/TreeNode.java b/Week_01/id_14/TreeNode.java
new file mode 100644
index 00000000..1b9907a3
--- /dev/null
+++ b/Week_01/id_14/TreeNode.java
@@ -0,0 +1,16 @@
+public class TreeNode {
+ int val;
+ TreeNode left;
+ TreeNode right;
+
+ TreeNode(int x) { val = x; }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("val:").append(val)
+ .append(" -left:").append(left == null ? -1 : left.val)
+ .append(" -right:").append(right == null ? -1 : right.val);
+ return stringBuilder.toString();
+ }
+}
diff --git a/Week_01/id_14/insert_sort.c b/Week_01/id_14/insert_sort.c
new file mode 100644
index 00000000..47abed1c
--- /dev/null
+++ b/Week_01/id_14/insert_sort.c
@@ -0,0 +1,63 @@
+#include 二叉树
+ * 简单
+ *
+ * https://leetcode-cn.com/submissions/detail/17526993/
+ *
+ * @author aiter
+ * @date 2019/04/22 9:22 PM
+ */
+public class LeetCode_671_14 {
+
+ public static void main(String[] args) {
+ Solution solution = new Solution();
+
+ TreeNode root = new TreeNode(1);
+ root.left = new TreeNode(4);
+ root.left.left = new TreeNode(4);
+ root.left.right = new TreeNode(5);
+
+ root.right = new TreeNode(5);
+ root.right.left = new TreeNode(6);
+ root.right.right = new TreeNode(7);
+
+ System.out.println(solution.findSecondMinimumValue(root));
+ }
+
+ static class Solution {
+ private int second = -1;
+
+ /**
+ * 哈希表 + 链表
+ * 中等
+ *
+ * https://leetcode-cn.com/submissions/detail/17527494/
+ *
+ * @author aiter
+ * @date 2019/04/23 7:18 AM
+ */
+public class LeetCode_692_14 {
+
+ public static void main(String[] args) {
+ Solution solution = new Solution();
+
+ System.out.println("i".compareTo("love"));
+ System.out.println("love".compareTo("lpve"));
+ System.out.println("aa".compareTo("aaa"));
+ System.out.println("aaa".compareTo("aa"));
+
+ String[] words = {"i", "love", "leetcode", "i", "love", "coding"};
+ //String[] words = {"a", "aa", "aaa"};
+
+ int k = 5;
+ List
+ * 783. 二叉搜索树结点最小距离
+ *
+ * 简单
+ * 树 binary tree
+ *
+ * @author aiter
+ * @date 2019/04/26 6:42 AM
+ */
+public class LeetCode_783_14 {
+ public static void main(String[] args) {
+ Solution solution = new Solution();
+
+ TreeNode root = new TreeNode(4);
+ root.left = new TreeNode(2);
+ root.left.left = new TreeNode(1);
+ root.left.right = new TreeNode(3);
+
+ root.right = new TreeNode(6);
+
+ int ret = solution.minDiffInBST(root);
+
+ System.out.println(String.format("预期值:1,实际值:%d", ret));
+
+ Solution2 solution2 = new Solution2();
+ System.out.println(String.format("预期值:1,实际值:%d", solution2.minDiffInBST(root)));
+ }
+
+ /**
+ * 简单
+ * 二叉树
+ * DFS
+ *
+ * @author aiter
+ * @date 2019/05/04 8:54 AM
+ */
+public class LeetCode_104_14 {
+ public static void main(String[] args) {
+ Solution solution = new Solution();
+ Solution2 solution2 = new Solution2();
+
+ /**
+ * 简单
+ * N叉树
+ *
+ * @author aiter
+ * @date 2019/05/04 7:51 PM
+ */
+public class LeetCode_429_14 {
+ public static void main(String[] args) {
+ Solution solution = new Solution();
+ Node root = new Node(1, new ArrayList
+ * 第K大元素
+ *
+ * 简单
+ * 堆
+ *
+ * @author aiter
+ * @date 2019/05/03 8:20 PM
+ */
+public class LeetCode_703_14 {
+
+ public static void main(String[] args) {
+ int k = 3;
+ int[] arr = {4, 5, 8, 2};
+ KthLargest3 kthLargest = new KthLargest3(k, arr);
+ System.out.println(String.format("添加%d , 期望值:4,实际值:%d", 3, kthLargest.add(3))); // returns 4
+ System.out.println(String.format("添加%d , 期望值:5,实际值:%d", 5, kthLargest.add(5))); // returns 5
+ System.out.println(String.format("添加%d , 期望值:5,实际值:%d", 10, kthLargest.add(10))); // returns 5
+ System.out.println(String.format("添加%d , 期望值:8,实际值:%d", 9, kthLargest.add(9))); // returns 8
+ System.out.println(String.format("添加%d , 期望值:8,实际值:%d", 4, kthLargest.add(4))); // returns 8
+ }
+
+ /**
+ * 利用java本身的优先级队列(堆)。一定要注意是只维护top K大小的堆。
+ * 简单
+ * 图
+ *
+ * @author aiter
+ * @date 2019/04/30 6:32 AM
+ */
+public class LeetCode_997_14 {
+ public static void main(String[] args) {
+ Solution solution = new Solution();
+
+ int N = 3;
+ int[][] trust = {{1, 3}, {2, 3}};
+
+ int r = solution.findJudge(N, trust);
+
+ System.out.println(String.format("期望值:3,实际值:%d", r));
+
+ Solution2 solution2 = new Solution2();
+
+ System.out.println(String.format("期望值:3,实际值:%d", solution2.findJudge(N, trust)));
+ }
+
+ /**
+ * 分发饼干
+ * 简单
+ * 贪心算法
+ *
+ * @author aiter
+ * @date 2019/05/10 7:39 AM
+ */
+public class LeetCode_455_14 {
+
+ public static void main(String[] args) {
+ Solution2 solution = new Solution2();
+
+ System.out.println(String.format("期望值:%d,实际值:%d",
+ 1, solution.findContentChildren(new int[] {1, 2, 3}, new int[] {1, 1})));
+
+ System.out.println(String.format("期望值:%d,实际值:%d",
+ 2, solution.findContentChildren(new int[] {1, 2}, new int[] {1, 2, 3})));
+
+ System.out.println(String.format("期望值:%d,实际值:%d",
+ 1, solution.findContentChildren(new int[] {1, 2, 3}, new int[] {3})));
+ }
+
+ static class Solution2 {
+ /**
+ * @param g 孩子
+ * @param s 饼干
+ * @return 满足的孩子的数量
+ */
+ public int findContentChildren(int[] g, int[] s) {
+ int count = 0;
+
+ //O(n)
+ Arrays.sort(g);
+ //O(m)
+ Arrays.sort(s);
+
+ int i = 0, j = 0;
+ while (i < g.length && j < s.length) {
+ //满足
+ if (g[i] <= s[j]) {
+ count++;
+ i++;
+ j++;
+ } else {
+ j++;
+ }
+ }
+ return count;
+ }
+ }
+
+ static class Solution {
+ /**
+ * @param g 孩子
+ * @param s 饼干
+ * @return 满足的孩子的数量
+ */
+ public int findContentChildren(int[] g, int[] s) {
+ int count = 0;
+
+ //O(n)
+ Arrays.sort(g);
+ //O(m)
+ Arrays.sort(s);
+
+ //O(m*n)
+ for (int i = 0; i < s.length; i++) {
+ for (int j = count; j < g.length; j++) {
+ //满足
+ if (g[j] <= s[i]) {
+ count++;
+ }
+
+ //满足,不满足,都需要看更大的饼干
+ break;
+ }
+ }
+
+ return count;
+ }
+ }
+}
+
diff --git a/Week_04/id_14/LeetCode_720_14.java b/Week_04/id_14/LeetCode_720_14.java
new file mode 100644
index 00000000..316473cb
--- /dev/null
+++ b/Week_04/id_14/LeetCode_720_14.java
@@ -0,0 +1,213 @@
+import java.util.*;
+
+/**
+ * https://leetcode-cn.com/problems/longest-word-in-dictionary/
+ *
+ * 简单
+ * trie树
+ *
+ * @author aiter
+ * @date 2019/05/08 7:12 AM
+ */
+public class LeetCode_720_14 {
+ public static void main(String[] args) {
+ Solution solution = new Solution();
+ //solution.use = 1;
+
+ System.out.println(String.format("期望值:world,实际值:%s",
+ solution.longestWord(new String[] {"w", "wo", "wor", "worl", "world"})));
+ System.out.println(String.format("期望值:apple,实际值:%s",
+ solution.longestWord(new String[] {"a", "banana", "app", "appl", "ap", "apply", "apple"})));
+
+ System.out.println(String.format("期望值:ap,实际值:%s",
+ solution.longestWord(new String[] {"a", "banana", "appl", "ap", "apply", "apple"})));
+
+ System.out.println(String.format("期望值:latte,实际值:%s",
+ solution.longestWord(
+ new String[] {"m", "mo", "moc", "moch", "mocha", "l", "la", "lat", "latt", "latte", "c", "ca",
+ "cat"})));
+
+ System.out.println(String.format("期望值:eyj,实际值:%s",
+ solution.longestWord(
+ new String[] {"ogz", "eyj", "e", "ey", "hmn", "v", "hm", "ogznkb", "ogzn", "hmnm", "eyjuo", "vuq",
+ "ogznk", "og", "eyjuoi", "d"})));
+
+ }
+
+ /**
+ * 最长
+ *
+ * 有时不愿意用递归
+ */
+ static class Solution {
+ private TrieNode root;
+ private String longest;
+ //辅助变量,用于选择执行逻辑
+ int use = 0;
+
+ public String longestWord(String[] words) {
+ if (words.length == 0) {
+ return "";
+ }
+ //初始化trie树
+ root = new TrieNode("");
+ for (String word : words) {
+ insert(word);
+ }
+
+ //查找
+ if (use == 0) {
+ longest = root.val;
+ longestWordByRecursion(root, 0);
+ return longest;
+ } else {
+ return longestWordByIteration();
+ }
+ }
+
+ /**
+ * 递归实现。每到一层,就和已有最长串比较。
+ *
+ * @param root
+ * @param n
+ */
+ private void longestWordByRecursion(TrieNode root, int n) {
+ if (!root.isEnd && n > 0) {
+ return;
+ }
+
+ if (n > longest.length()) {
+ longest = root.val;
+ } else if (n == longest.length() && root.val.compareTo(longest) < 0) {
+ longest = root.val;
+ }
+
+ Map 简单
+ * dynamic programming
+ * 爬楼梯,只能爬一梯或者二梯
+ *
+ * @author aiter
+ * @date 2019/05/10 8:29 AM
+ */
+public class LeetCode_746_14 {
+ public static void main(String[] args) {
+ Solution solution = new Solution();
+ //Solution2 solution = new Solution2();
+
+ System.out.println(String.format("期望值:%d,实际值:%d",
+ 6, solution.minCostClimbingStairs(new int[] {1, 100, 1, 1, 1, 100, 1, 1, 100, 1})));
+ System.out.println(String.format("期望值:%d,实际值:%d",
+ 15, solution.minCostClimbingStairs(new int[] {10, 15, 20})));
+
+ System.out.println(String.format("期望值:%d,实际值:%d",
+ 0, solution.minCostClimbingStairs(new int[] {0, 0, 0, 0})));
+
+ System.out.println(String.format("期望值:%d,实际值:%d",
+ 0, solution.minCostClimbingStairs(new int[] {0, 0, 1, 0})));
+
+ System.out.println(String.format("期望值:%d,实际值:%d",
+ 1, solution.minCostClimbingStairs(new int[] {0, 0, 1, 1})));
+ }
+
+ static class Solution2 {
+ public int minCostClimbingStairs(int[] cost) {
+ int[] dp = new int[cost.length + 1];
+ dp[0] = 0;
+ dp[1] = 0;
+ for (int i = 2; i <= cost.length; i++) {
+ dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
+ }
+
+ return dp[cost.length];
+
+ }
+ }
+
+ /**
+ * 被动态规划,搞疯了。{@link Solution2#minCostClimbingStairs(int[])} 使用的是状态转移方程? 而我费时费力用的是状态转移表?
+ */
+ static class Solution {
+
+ public int minCostClimbingStairs(int[] cost) {
+ int n = cost.length;//楼梯数量
+ int[][] status = new int[n][2];
+
+ for (int i = 0; i < n; i++) {
+ status[i][0] = -1;
+ status[i][1] = -1;
+ }
+
+ status[0][0] = 0;
+ status[0][1] = cost[0];
+
+ for (int i = 1; i < n; i++) {
+ //上一梯没走,这一梯必须走。上一梯没走,那么上上一梯,肯定是走了的。
+ if (i == 1 || status[i - 1][0] == status[i - 2][1]) {
+ if (status[i][1] >= 0) {
+ status[i][1] = Math.min(status[i][1], status[i - 1][0] + cost[i]);
+ } else {
+ status[i][1] = status[i - 1][0] + cost[i];
+ }
+ }
+
+ //上一梯走了。
+ if (status[i - 1][1] >= 0) {
+ //不走这一梯
+ status[i][0] = status[i - 1][1];
+
+ //走这一梯
+ if (status[i][1] >= 0) {
+ status[i][1] = Math.min(status[i][1], status[i - 1][1] + cost[i]);
+ } else {
+ status[i][1] = status[i - 1][1] + cost[i];
+ }
+ }
+
+ System.out.println(i + ":" + Arrays.toString(status[i]));
+ }
+ return status[n - 1][0] < status[n - 1][1] ? status[n - 1][0] : status[n - 1][1];
+ }
+ }
+}
+
diff --git a/Week_04/id_14/LeetCode_784_14.java b/Week_04/id_14/LeetCode_784_14.java
new file mode 100644
index 00000000..22057aad
--- /dev/null
+++ b/Week_04/id_14/LeetCode_784_14.java
@@ -0,0 +1,102 @@
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * https://leetcode-cn.com/problems/letter-case-permutation/
+ *
+ * 简单
+ * backtracking
+ * S 的长度不超过12。 S 仅由数字和字母组成。
+ *
+ * @author aiter
+ * @date 2019/05/10 6:37 AM
+ */
+public class LeetCode_784_14 {
+ public static void main(String[] args) {
+ Solution solution = new Solution();
+ Solution2 solution2 = new Solution2();
+
+ System.out.println(String.format("输出值:%s", solution.letterCasePermutation("a1b2")));
+ System.out.println(String.format("输出值:%s", solution2.letterCasePermutation("a1b2")));
+ System.out.println(String.format("输出值:%s", solution.letterCasePermutation("a12b")));
+ System.out.println(String.format("输出值:%s", solution2.letterCasePermutation("a12b")));
+ System.out.println(String.format("输出值:%s", solution.letterCasePermutation("a1b2c3")));
+ System.out.println(String.format("输出值:%s", solution2.letterCasePermutation("a1b2c3")));
+ System.out.println(String.format("输出值:%s", solution.letterCasePermutation("3z4")));
+ System.out.println(String.format("输出值:%s", solution2.letterCasePermutation("3z4")));
+ System.out.println(String.format("输出值:%s", solution.letterCasePermutation("12345")));
+ System.out.println(String.format("输出值:%s", solution2.letterCasePermutation("12345")));
+ }
+
+ /**
+ * 这种方式更优雅一下。终止条件的地方添加list元素
+ */
+ static class Solution2 {
+ public List
+ * 1. 非空的二叉树
+ * 2. 都是正数
+ * 3. 子节点数量:0/2
+ * 4. 有子节点。 value <= 子节点value
+ *
+ *
+ * @param root
+ * @return 第2小的值,或者-1
+ */
+ public int findSecondMinimumValue(TreeNode root) {
+ second = -1;
+ getNum(root);
+ return second;
+ }
+
+ /**
+ * @param node
+ * @return 返回当前节点及子节点中的最小值
+ */
+ private int getNum(TreeNode node) {
+ if (node == null) {
+ return -1;
+ }
+
+ int left = getNum(node.left);
+ int right = getNum(node.right);
+
+ /**
+ * 只需要判断左子树, 子节点要么是2,要么是0
+ */
+ if (left == -1) {
+ return node.val;
+ }
+
+ if (left == right) {
+ if (node.val < left) {
+ second = second == -1 ? left : Math.min(left, second);
+ }
+ } else {
+ if (left < right) {
+ if (node.val < left) {
+ second = second == -1 ? left : Math.min(left, second);
+ } else {
+ second = second == -1 ? right : Math.min(right, second);
+ }
+ } else {
+ if (node.val < right) {
+ second = second == -1 ? right : Math.min(right, second);
+ } else {
+ second = second == -1 ? left : Math.min(left, second);
+ }
+ }
+ }
+
+ return node.val;
+ }
+ }
+}
diff --git a/Week_02/id_14/LeetCode_692_14.java b/Week_02/id_14/LeetCode_692_14.java
new file mode 100644
index 00000000..24eff437
--- /dev/null
+++ b/Week_02/id_14/LeetCode_692_14.java
@@ -0,0 +1,130 @@
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * https://leetcode-cn.com/problems/top-k-frequent-words/submissions/
+ *
+ *
+ * 要求:
+ * 任意两节点的差的最小值
+ * 开始理解为父子节点的差值
+ * 二叉搜索树:
+ * 1. 是有序的
+ * 2.1 中序遍历,就是一个有序的数列,再求相邻数组元素之间的最小差值
+ * 2.2 每个节点,查找他的中序遍历前序、后序节点,最小值只会出现在这里
+ *
+ *
+ * 2.1 结果,为什么?中序遍历O(n)+遍历求值O(n)。总:O(n)
+ * 执行用时 : 27 ms, 在Minimum Distance Between BST Nodes的Java提交中击败了5.25% 的用户
+ * 内存消耗 : 35.1 MB, 在Minimum Distance Between BST Nodes的Java提交中击败了55.36% 的用户
+ * https://leetcode-cn.com/submissions/detail/17726878/
+ *
+ * 2.2
+ * 执行用时 : 1 ms, 在Minimum Distance Between BST Nodes的Java提交中击败了100.00% 的用户
+ * 内存消耗 : 34.6 MB, 在Minimum Distance Between BST Nodes的Java提交中击败了74.41% 的用户
+ *
+ */
+ static class Solution2 {
+ private final static int MAX = 100;
+
+ public int minDiffInBST(TreeNode root) {
+ if (root == null) {
+ return MAX;
+ }
+
+ int left = -1;
+ // 如果有左子树,那么最大值,一定是左子节点或左子树的最右节点
+ if (root.left != null) {
+ left = root.left.val;
+ TreeNode cur = root.left.right;
+ while (cur != null) {
+ left = cur.val;
+ cur = cur.right;
+ }
+ }
+
+ int min = MAX;
+ if (left > 0) {
+ min = Math.min(min, root.val - left);
+ }
+
+ int right = -1;
+ // 如果有右子树,那么最小值,一定是右子节点或右子树的最左节点
+ if (root.right != null) {
+ right = root.right.val;
+ TreeNode cur = root.right.left;
+ while (cur != null) {
+ right = cur.val;
+ cur = cur.left;
+ }
+ }
+ if (right > 0) {
+ min = Math.min(min, right - root.val);
+ }
+
+ //递归计算左子树、右子树的最小值k,在比较k与min的最小值
+ return Math.min(min, Math.min(minDiffInBST(root.left), minDiffInBST(root.right)));
+
+ }
+
+ }
+
+ static class Solution {
+ private final static int MAX = 100;
+
+ public int minDiffInBST(TreeNode root) {
+
+ DListNode inorderNode = new DListNode(root.val);
+
+ inorder(root, inorderNode);
+
+ DListNode cur = inorderNode;
+ System.out.println("-" + cur.val);
+ int min = MAX;
+ while (cur.pre != null) {
+
+ min = Math.min(min, Math.abs(cur.val - cur.pre.val));
+ cur = cur.pre;
+ System.out.println("pre-" + cur.val);
+ }
+ cur = inorderNode;
+ System.out.println("-" + cur.val);
+ while (cur.next != null) {
+
+ min = Math.min(min, Math.abs(cur.val - cur.next.val));
+ cur = cur.next;
+ System.out.println("next-" + cur.val);
+ }
+ return min;
+ }
+
+ private void inorder(TreeNode root, DListNode inorderNode) {
+ if (root == null) {
+ return;
+ }
+
+ if (root.left != null) {
+ DListNode pre = inorderNode.pre;
+ inorderNode.pre = new DListNode(root.left.val);
+ inorderNode.pre.next = inorderNode;
+ if (pre != null) {
+ inorderNode.pre.pre = pre;
+ pre.next = inorderNode.pre;
+ }
+ inorder(root.left, inorderNode.pre);
+ }
+ if (root.right != null) {
+ DListNode next = inorderNode.next;
+ inorderNode.next = new DListNode(root.right.val);
+ inorderNode.next.pre = inorderNode;
+ if (next != null) {
+ inorderNode.next.next = next;
+ next.pre = inorderNode.next;
+ }
+ inorder(root.right, inorderNode.next);
+ }
+ }
+ }
+
+ static class DListNode {
+ int val;
+ DListNode pre;
+ DListNode next;
+
+ DListNode(int x) {
+ val = x;
+ }
+ }
+}
diff --git a/Week_02/id_14/NOTE.md b/Week_02/id_14/NOTE.md
index c684e62f..22c51df8 100644
--- a/Week_02/id_14/NOTE.md
+++ b/Week_02/id_14/NOTE.md
@@ -1 +1,55 @@
-# 学习笔记
\ No newline at end of file
+# 学习笔记
+> 本周重点:跳表、散列表、哈希算法、二叉树、红黑树
+
+本周主要还是练习,课程学习相对少一些。
+* 二叉树& 二叉搜索树
+ * binary tree 本身很基础,使用也是最多的一种。本身限定为二叉,0、1、2个子节点都符合要求,运用于实际时,可能是更多的限定,比如:
+ * 完全二叉树,那么只有1个子节点时,必须是左子字节。
+ * leetcode上的求第二小的数字。限定子节点只能是0或2,不能是1
+ * 为了避免二叉树的高度太高,退化成链表,这样就基本失去了树的特征,这又引出了:
+ * 平衡二叉树,左右子树的高度不能“相差太多”
+ * 完全二叉树,严格的平衡二叉树,左右高度相差最多为1。而且1个子节点时,必须是左子节点
+ * 满二叉树,一种特殊的完全二叉树。所有的非叶子节点数都是2
+ * 红黑树,比较难,后面再详细学习
+```
+ 2 2 2 2
+ / \ / \ / \ / \
+ 2 5 2 5 2 5 2 5
+ / \ / \ / \ / / \ / \
+ 5 7 5 7 5 7 6 5 7 6 7
+ /
+ 5
+ 二叉树 平衡二叉树 完全二叉树 满二叉树
+```
+ > 都是二叉树,2、3、4都是平衡二叉树, 3、4都是完成二叉树。4是满二叉树
+ * 堆,就是一种完全二叉树。外加了一条,节点值大/小于左、右子节点值,分别就是大、小顶堆
+ * 二叉搜索树
+ * 本身是有序的,左子节点的值小于节点值,右子节点值大于节点值
+ * 基于上一条,中序遍历后,就是一个有序的序列
+ * leetcode上《783. 二叉搜索树结点最小距离》,就是典型的应用。开始笔者使用了中序遍历成一个有序的双向链表序列,再遍历链表,求相邻数值的最小差值,这样时间复杂度比较高(中序遍历O(n)+遍历链表求差值O(n)???)。后面利用二叉搜索树,任何节点的中序遍历前序节点要么是左子节点,要么是左子树的最右节点。后序节点同样的道理。最小距离肯定出现在当前节点与前序、后序节点的差值中。
+```
+ 4 4
+ / \ / \
+ 2 6 2 6
+ / \ ^ / \
+ 1 3 | 5 8
+ ^
+ |
+```
+ * 未完成:前、中、后序、层次遍历的实现
+* top k frequent words
+ > 使用了hash表+双向链表的实现
+ * hash表,主要是O(1)时间复杂度定位对应的元素(也是双向链表中的节点)
+ * 把当前节点,从链中移除
+ * 再从链表头进行比较,选择插入的位置
+ * 最后从链表头,输出top K的
+* 利用队列实现广度优先搜索(BFS ,Breadth First Search)
+* 利用栈实现深度优先搜索(DFS ,Depth First Search)
+* 插入排序实现
+* 归并排序实现
+* 堆及堆排序
+上面几种实现本身没什么特别, 也是参考例子去实现的,有一点比较重要,以前都是学习理论,没有动手自己去实现。理解上还是不太深,自己实现一遍,加深了理解。比如:
+ * 广度优先,没实现前,记得当时的一个图,一层层去遍历,也记得有个队列。自己实现是走迷宫,实际实现就是从当前点,依次查看当前点的右、下、左、上是否可走,可走的话,就把右、下、左、上的点,加入队尾,然后从队头中取一个元素作为当前点,再重复这个过程。利用队列的先进先出(FIFO),就实现了"层层推进"的效果。
+ * 而深度优先,则是采用栈的后进先出(LIFO)特性。实现了"一条路走到黑"的效果,只有真正没路可走了,而且还没走出迷宫,这时才能回到"岔路口"从另一条路再这样"一条路走到黑",每个岔路口,都是这样干的。这就是回溯(Backtrack)?
+
+> * 跳表:本周未涉及,周末有时间可以实现一下
diff --git a/Week_02/id_14/TreeNode.java b/Week_02/id_14/TreeNode.java
new file mode 100644
index 00000000..1b9907a3
--- /dev/null
+++ b/Week_02/id_14/TreeNode.java
@@ -0,0 +1,16 @@
+public class TreeNode {
+ int val;
+ TreeNode left;
+ TreeNode right;
+
+ TreeNode(int x) { val = x; }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("val:").append(val)
+ .append(" -left:").append(left == null ? -1 : left.val)
+ .append(" -right:").append(right == null ? -1 : right.val);
+ return stringBuilder.toString();
+ }
+}
diff --git a/Week_03/id_14/LeetCode_104_14.java b/Week_03/id_14/LeetCode_104_14.java
new file mode 100644
index 00000000..56ed78bd
--- /dev/null
+++ b/Week_03/id_14/LeetCode_104_14.java
@@ -0,0 +1,102 @@
+import java.util.HashMap;
+import java.util.Stack;
+
+/**
+ * https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
+ *
+ *
+ * 1
+ * / \
+ * 4 5
+ * / \ / \
+ * 4 5 6 7
+ * / \
+ * 12 5
+ *
+ */
+ TreeNode root = new TreeNode(1);
+ root.left = new TreeNode(4);
+ root.left.left = new TreeNode(4);
+ root.left.right = new TreeNode(5);
+ root.left.left.left = new TreeNode(12);
+ root.left.left.right = new TreeNode(5);
+
+ root.right = new TreeNode(5);
+ root.right.left = new TreeNode(6);
+ root.right.right = new TreeNode(7);
+
+ System.out.println(String.format("期望值:4,实际值:%d", solution.maxDepth(root)));
+ System.out.println(String.format("期望值:4,实际值:%d", solution2.maxDepth(root)));
+ }
+
+ /**
+ * 难得遇到一道送分题!
+ */
+ static class Solution {
+ public int maxDepth(TreeNode root) {
+ if (root == null) {
+ return 0;
+ }
+
+ int left = maxDepth(root.left);
+ int right = maxDepth(root.right);
+
+ return ((left >= right) ? left : right) + 1;
+
+ }
+ }
+
+ /**
+ * 用stack和哈希表,实现一下。
+ * 哈希表记录当前节点的深度
+ */
+ static class Solution2 {
+
+ public int maxDepth(TreeNode root) {
+ if (root == null) {
+ return 0;
+ }
+
+ int max = 0;
+
+ Stack> list = solution.levelOrder(root);
+ System.out.println(list);
+ System.out.println(new Solution2().levelOrder(root));
+ }
+
+ /**
+ * 使用递归的方式。
+ * 递归的方式,无论是效率还是代码清晰度都比较好。
+ */
+ static class Solution2 {
+ public List
> levelOrder(Node root) {
+ List
> list = new ArrayList<>();
+ getList(list, root, 0);
+
+ return list;
+
+ }
+
+ private void getList(List
> list, Node root, int l) {
+ if (root == null) {
+ return;
+ }
+ if (l >= list.size()) {
+ list.add(new ArrayList<>());
+ }
+ List
+ * 1. 队列记录层次的元素
+ *
+ */
+ static class Solution {
+ public List> levelOrder(Node root) {
+ List
> list = new ArrayList<>();
+ LinkedList
+ * 不到k,就直接插入
+ * 大于等于k,而且插入元素大于堆顶元素,先删除堆顶,再插入
+ *
+ */
+ static class KthLargest3 {
+ private PriorityQueue
+ * 如果堆大小还不到 k的大小,最后位置插入元素,并从下到上堆化
+ * 如果堆大小已经k的大小。
+ * 1. 插入值,小于等于堆顶元素,直接返回堆顶元素
+ * 2. 插入值,大于堆顶元素。直接替换堆顶元素,并从上到下堆化(使用java优先队列,这一步需要先删堆顶,再添加元素,2次堆化)
+ *
+ */
+ static class KthLargest {
+ private int k = 0;
+ private int size;
+ private int[] items;
+
+ //nums 的长度≥ k-1 且k ≥ 1。
+ public KthLargest(int k, int[] nums) {
+ this.k = k;
+ this.items = new int[k];
+ for (int i = 0; i < nums.length; i++) {
+ add(nums[i]);
+ }
+ }
+
+ public int add(int val) {
+ if (size >= k) {
+ if (items[0] < val) {
+ items[0] = val;
+ siftDown(items, size, 0);
+ }
+ return items[0];
+ } else {
+ items[size++] = val;
+
+ siftup(size - 1, items[size - 1]);
+
+ return items[0];
+ }
+ }
+
+ void printArray(int arr[]) {
+ int n = arr.length;
+ for (int i = 0; i < n; ++i) {
+ System.out.print(arr[i] + " ");
+ }
+ System.out.println();
+ }
+
+ /**
+ * 从下往上堆化(小顶堆)
+ *
+ * @param t 下标值
+ * @param key 下标元素值
+ */
+ void siftup(int t, int key) {
+ while (t > 0) {
+ int parent = (t - 1) >>> 1;
+ //System.out.println(t + ":" + key + ":" + parent);
+ int e = items[parent];
+ if (e <= key) { break; }
+ items[t] = e;
+ t = parent;
+ }
+ items[t] = key;
+ }
+
+ /**
+ * 从上往下堆化(小顶堆)
+ *
+ * @param arr 数组
+ * @param n 数组大小
+ * @param i 下标值
+ */
+ void siftDown(int arr[], int n, int i) {
+ // 初始化i为最小值
+ int smallest = i;
+ // 左节点 = 2*i + 1
+ int l = 2 * i + 1;
+ // 右节点 = 2*i + 2
+ int r = 2 * i + 2;
+
+ // 左节点比当前节点小
+ if (l < n && arr[l] < arr[smallest]) { smallest = l; }
+
+ // 右节点更小
+ if (r < n && arr[r] < arr[smallest]) { smallest = r; }
+
+ // 如果,最小值不是当前节点(左、右),就交换。并继续堆化
+ if (smallest != i) {
+ int swap = arr[i];
+ arr[i] = arr[smallest];
+ arr[smallest] = swap;
+
+ // Recursively heapify the affected sub-tree
+ siftDown(arr, n, smallest);
+ }
+ }
+ }
+
+}
+
diff --git a/Week_03/id_14/LeetCode_997_14.java b/Week_03/id_14/LeetCode_997_14.java
new file mode 100644
index 00000000..67b1d01f
--- /dev/null
+++ b/Week_03/id_14/LeetCode_997_14.java
@@ -0,0 +1,115 @@
+/**
+ * https://leetcode-cn.com/problems/find-the-town-judge/
+ *
+ *
+ * 需求描述:
+ * 1. 小镇的法官不相信任何人。
+ * 没有指向的顶点。 出度=0
+ * 2. 每个人(除了小镇法官外)都信任小镇的法官。
+ * 其他的点,都指向这个顶点。秘密的法官的 入度=N-1
+ * 3. 只有一个人同时满足属性 1 和属性 2 。
+ * 只能有一个顶点的。出度=0,入度=N-1
+ *
+ * +-----+----+
+ * |入度 |出度 |
+ * +-----+----+
+ * | N-1 | 0 | --> 秘密法官
+ * +-----+----+
+ * |0.N-1| >0 | --> 其他
+ * +-----+----+
+ *
+ *
+ */
+ static class Solution {
+ public int findJudge(int N, int[][] trust) {
+ //这种方法可以不判断,persons二维数组遍历时,N=1时,也能满足
+ //if (N == 1 && trust.length == 0) {
+ // return 1;
+ //}
+ int[][] persons = new int[N + 1][2];
+
+ for (int[] items : trust) {
+ //统计入度
+ persons[items[1]][0] = persons[items[1]][0] + 1;
+ //统计出度
+ persons[items[0]][1] = persons[items[0]][1] + 1;
+ }
+
+ int judgeCnt = 0;
+ int idx = 0;
+ for (int i = 1; i < persons.length; i++) {
+ int[] items = persons[i];
+ //入度=N-1 && 出度=0
+ if (items[0] == N - 1 && items[1] == 0) {
+ judgeCnt++;
+ idx = i;
+ }
+ }
+ if (judgeCnt == 1) {
+ return idx;
+ }
+
+ return -1;
+ }
+ }
+
+ static class Solution2 {
+ public int findJudge(int N, int[][] trust) {
+ //这个条件开始没注意
+ if (N == 1 && trust.length == 0) {
+ return 1;
+ }
+ int[][] persons = new int[N + 1][2];
+
+ int judgeCnt = 0;
+ int idx = 0;
+ for (int[] items : trust) {
+ //统计入度
+ persons[items[1]][0] = persons[items[1]][0] + 1;
+ if (persons[items[1]][0] == N - 1) {
+ //入度=N-1 && 出度=0 就是法官
+ if (persons[items[1]][1] == 0) {
+ judgeCnt++;
+ idx = items[1];
+ }
+ }
+ //统计出度
+ persons[items[0]][1] = persons[items[0]][1] + 1;
+ //被选中的法官,有出度了,就不是法官
+ if (items[0] == idx) {
+ judgeCnt--;
+ idx = 0;
+ }
+ }
+
+ if (judgeCnt == 1) {
+ return idx;
+ }
+
+ return -1;
+ }
+ }
+}
diff --git a/Week_03/id_14/NOTE.md b/Week_03/id_14/NOTE.md
index c684e62f..7c855207 100644
--- a/Week_03/id_14/NOTE.md
+++ b/Week_03/id_14/NOTE.md
@@ -1 +1,46 @@
-# 学习笔记
\ No newline at end of file
+# 学习笔记
+> 递归树、堆和排序、图、深度和广度优先搜索、字符串匹配
+
+递归树
+> 主要就是用来分析递归代码的时间复杂度?
+
+堆
+> 很重要的一种数据结构,日常工作中使用率也比较高。比如:常用的优先级队列、堆排序。
+一些理解点:
+ * 本身是一棵完全二叉树(除最后一层,其他层节点都是满的,最后一层如果只有一个节点,必须考左)
+ * 一般用数组来存储,而且可以利用数组下标快速的方法定位父节点((i-1)/2)、左右子节点(l=2i*-1,r=2i*2)
+ * 大顶堆,当前节点值,大于等于左右节点值。小顶堆,当前节点值,小于等于左右节点值。
+> 一个大顶堆,存储它的数组是有序的吗?
+```
+ 67
+ / \
+ 56 23
+ / \ / \
+ 45 11 7 13
+ / \ /
+ 12 5 6
+ +----+----+----+----+----+----+----+----+----+----+
+ | 67 | 56 | 23 | 45 | 11 | 7 | 13 | 12 | 5 | 6 |
+ +----+----+----+----+----+----+----+----+----+----+
+ 这个一个大顶堆,下面是数组的存储情况。 显然,存储它的数组不是有序的。
+```
+> 基于上一点的特性,我们取堆中的top k按大小顺序的元素,要么不断的删除堆顶元素,然后再次堆化;要么将堆排序输出,其实也是,不断的删除堆顶元素,然后在0...n-1的范围内堆化。动态的数据,要是把堆顶元素删除了,元素就不存在了,如果是top k问题,其实是使用小顶堆。
+建堆& 动态操作:
+ * 原始数组的堆化,一种从前往后(插入,也是从下往上堆化?);一种从后往前(只需要从n/2-1的节点开始,往前遍历建堆)
+ * 堆排序:建堆后,迭代删除堆顶,并堆化剩余的N-1的堆
+ * 删除堆顶&插入新元素:删除一般采用:用n-1位置的元素放入下标为0的堆顶位置,然后向下堆化。插入到n-1的位置,然后向上堆化。
+
+图:
+> 无向图、有向图、带权图、无向/有向带权图
+
+注意跟进实际场景,选择图的存储方式,是使用邻接矩阵还是邻接表。比如:顶点比较多,但是顶点间关系(边)不多的,邻接表更适合。可以把王争老师说的微信、微博这些社交关系的仔细推导、实现一下。
+BFS & DFS
+> 图的搜索遍历。上周也简单总结了一下。整体的感觉:离融会贯通还有很长的距离,现在很多点,还是各自游离状态。
+```
+ 广度优先,没实现前,记得当时的一个图,一层层去遍历,也记得有个队列。自己实现是走迷宫,实际实现就是从当前点,依次查看当前点的右、下、左、上是否可走,可走的话,就把右、下、左、上的点,加入队尾,然后从队头中取一个元素作为当前点,再重复这个过程。利用队列的先进先出(FIFO),就实现了"层层推进"的效果。
+ 深度优先,则是采用栈的后进先出(LIFO)特性。实现了"一条路走到黑"的效果,只有真正没路可走了,而且还没走出迷宫,这时才能回到"岔路口"从另一条路再这样"一条路走到黑",每个岔路口,都是这样干的。这就是回溯(Backtrack)?
+```
+
+字符串匹配
+> BF当然是最好理解,但是由于效率低。出现了RK算法。本质上是:RK利用哈希表,来提高字符串比较的效率。
+> BM/KMP,思路上主要也是,减少字符串比较的次数。有机会多滑动几位,就可以减少模式串和主串的比较次数。KMP的next数组还没看明白:(
diff --git a/Week_03/id_14/TreeNode.java b/Week_03/id_14/TreeNode.java
new file mode 100644
index 00000000..79021550
--- /dev/null
+++ b/Week_03/id_14/TreeNode.java
@@ -0,0 +1,17 @@
+public class TreeNode {
+ int val;
+ TreeNode left;
+ TreeNode right;
+
+ TreeNode(int x) { val = x; }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("val:").append(val)
+ .append(" -left:").append(left == null ? -1 : left.val)
+ .append(" -right:").append(right == null ? -1 : right.val);
+ return stringBuilder.toString();
+ }
+}
+
diff --git a/Week_04/id_14/LeetCode_455_14.java b/Week_04/id_14/LeetCode_455_14.java
new file mode 100644
index 00000000..bd071cf9
--- /dev/null
+++ b/Week_04/id_14/LeetCode_455_14.java
@@ -0,0 +1,88 @@
+import java.util.Arrays;
+
+/**
+ * https://leetcode-cn.com/problems/assign-cookies/
+ *
+ *