From bd11ddfa054f5a2468b487d7c03437e152c4d14c Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Tue, 23 Sep 2014 16:14:26 -0700 Subject: [PATCH 01/66] KthSort --- KthSort.java | 43 +++ ListNodeDemo.java | 676 ---------------------------------------------- PostOrder.java | 3 - 3 files changed, 43 insertions(+), 679 deletions(-) create mode 100644 KthSort.java delete mode 100644 ListNodeDemo.java diff --git a/KthSort.java b/KthSort.java new file mode 100644 index 0000000..bb97cf1 --- /dev/null +++ b/KthSort.java @@ -0,0 +1,43 @@ +package Algorithms; + +import java.util.HashMap; + +public class KthSort { + public static class Graph { + String name; + HashMap subs; + public Graph(String name) { + this.name = name; + } + } + + public static void main(String[] strs) { +// int[] input = new int[]{1,2,4,3,9,11,0}; +// sort(input); +// for(int n: input) { +// System.out.print(n + " "); +// } + Graph c1 = new Graph("c1"); + + //for() + } + + public static void sort(int[] input) { + if (input == null) { + return; + } + + int len = input.length; + for (int i = 1; i < len; i++) { + int cur = input[i]; + int j = i - 1; + while (j >= 0 && input[j] > cur) { + input[j + 1] = input[j]; + j--; + } + + input[j + 1] = cur; + } + } + +} diff --git a/ListNodeDemo.java b/ListNodeDemo.java deleted file mode 100644 index 48bdae6..0000000 --- a/ListNodeDemo.java +++ /dev/null @@ -1,676 +0,0 @@ -package Algorithms; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Stack; - -/** - * REFS: - * http://blog.csdn.net/fightforyourdream/article/details/16353519 - * http://blog.csdn.net/luckyxiaoqiang/article/details/7393134 轻松搞定面试中的链表题目 - * http://www.cnblogs.com/jax/archive/2009/12/11/1621504.html 算法大全(1)单链表 - * - * 目录: - * 1. 求单链表中结点的个数: getListLength - * 2. 将单链表反转: reverseList(遍历),reverseListRec(递归) - * 3. 查找单链表中的倒数第K个节点(k > 0): reGetKthNode - * 4. 查找单链表的中间结点: getMiddleNode - * 5. 从尾到头打印单链表: reversePrintListStack,reversePrintListRec(递归) - * 6. 已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序: mergeSortedList, mergeSortedListRec - * 7. 判断一个单链表中是否有环: hasCycle - * 8. 判断两个单链表是否相交: isIntersect - * 9. 求两个单链表相交的第一个节点: getFirstCommonNode - * 10. 已知一个单链表中存在环,求进入环中的第一个节点: detectCycle, getFirstNodeInCycleHashMap - * 11. 给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted: delete - * - */ - -public class ListNodeDemo { - - // create the link Node class. - // why use static: - // http://duqiangcise.iteye.com/blog/697476 - private static class ListNode { - int val; - ListNode next; - public ListNode(int val) { - this.val = val; - this.next = null; - } - - } - - public static void main(String[] args) { - ListNode n1 = new ListNode(1); - ListNode n2 = new ListNode(2); - ListNode n3 = new ListNode(3); - ListNode n4 = new ListNode(4); - ListNode n5 = new ListNode(5); - ListNode n6 = new ListNode(6); - - ListNode m1 = new ListNode(5); - ListNode m2 = new ListNode(8); - ListNode m3 = new ListNode(9); - m1.next = m2; - m2.next = m3; - - ListNode c1 = new ListNode(1); - ListNode c2 = new ListNode(12); - c1.next = c2; - c2.next = n1; - - //ListNode mergeNode = mergeSortedListRec(m1, c1); - //ListNode mergeNode = mergeSortedList(m1, c1); - //printList(mergeNode); - - n1.next = n2; - n2.next = n3; - n3.next = n4; - n4.next = n5; - - printList(n1); - - Delete(n1, n5); - - printList(n1); - - // create a cycle - //n5.next = n3; - //n5.next = n6; - //n6.next = n4; - -// System.out.println(hasCycle(n1)); -// System.out.println(getListLength(n1)); -// printList(n1); -// -// //n1 = reverseList(n1); -// n1 = reverseListRec(n1); -// printList(n1); - -// ListNode ret = reGetKthNode(n1, 7); -// if (ret != null) { -// System.out.println(ret.val); -// } else { -// System.out.println("null"); -// } - - //reGetKthNodeRec(n1, 1); -// reGetKthNodeRec2(n1, 3); -// ListNode ret = getMiddleNode(n1); -// -// if (ret != null) { -// System.out.println(ret.val); -// } -// -// reversePrintListStackRec(n1); -// reversePrintListStack(n1); -// reversePrintListRev(n1); - - //printList(n1); - - System.out.println(isIntersect(n1, c1)); - - ListNode cross = getFirstCommonNode(n1, c1); - if (cross == null) { - System.out.println("null"); - } else { - System.out.println(cross.val); - } - - ListNode cross2 = getFirstNodeInCycleHashMap(c1); - if (cross2 == null) { - System.out.println("null"); - } else { - System.out.println(cross2.val); - } - } - - public static void printList(ListNode head) { - while (head != null) { - System.out.print(head.val + " "); - head = head.next; - } - - System.out.println(); - } - - // 获得ListNode 的长度 - public static int getListLength(ListNode head) { - if (head == null) { - return 0; - } - - int len = 0; - while (head != null) { - len++; - head = head.next; - } - - return len; - } - - /* - * 反转链表 - * 此算法亮点是:一次只需要处理把下一个节点指向curr, - * 不断循环,即可完成任务 - * */ - public static ListNode reverseList(ListNode head) { - if (head == null) { - return null; - } - - ListNode next = head.next; - ListNode curr = head; - - // 先把头节点的下一个指定. - curr.next = null; - - // 每次只需要将curr的next指向curr即可, - // 终止条件是:next是null 表示我们将所有的节点进行了翻转 - while (next != null) { - ListNode tmp = next.next; - next.next = curr; - curr = next; - next = tmp; - } - - return curr; - } - - // 翻转递归(递归) - // 递归的精髓在于你就默认reverseListRec已经成功帮你解决了子问题了!但别去想如何解决的 - // 现在只要处理当前node和子问题之间的关系。最后就能圆满解决整个问题。 - /* - head - 1 -> 2 -> 3 -> 4 - - head - 1-------------- - | - 4 -> 3 -> 2 // Node reHead = reverseListRec(head.next); - reHead head.next - - 4 -> 3 -> 2 -> 1 // head.next.next = head; - reHead - - 4 -> 3 -> 2 -> 1 -> null // head.next = null; - reHead - */ - public static ListNode reverseListRec(ListNode head) { - // if there is no node, or only one node, just return; - if (head == null || head.next == null) { - return head; - } - - ListNode reHead = reverseListRec(head.next); // 先求解子问题。 - head.next.next = head; // 将head 与被解决的子串的尾部相连。 - head.next = null; // head的下一个必须指向 null,因为head 是新的尾部. - - return reHead; - } - - /** - * 查找单链表中的倒数第K个结点(k > 0) - * 最普遍的方法是,先统计单链表中结点的个数,然后再找到第(n-k)个结点。注意链表为空,k为0,k为1,k大于链表中节点个数时的情况 - * 。时间复杂度为O(n)。代码略。 这里主要讲一下另一个思路,这种思路在其他题目中也会有应用。 - * 主要思路就是使用两个指针,先让前面的指针走到正向第k个结点 - * ,这样前后两个指针的距离差是k,之后前后两个指针一起向前走,前面的指针走到空时,后面指针所指结点就是倒数第k个结点 - * when k = 1, it should be the last node. - */ - public static ListNode reGetKthNode(ListNode head, int k) { - if (head == null) { - return null; - } - - ListNode fast = head; - - // 使fast and slow之间差 k - while (k > 0) { - if (fast == null) { - // 发生这种情况,说明k > sizeOfList. - return null; - } - fast = fast.next; - k--; - } - - while (fast != null) { - fast = fast.next; - head = head.next; - } - - return head; - } - - /* - * 递归打印出倒数第k个节点。 - * */ - static int level = 0; - public static void reGetKthNodeRec(ListNode head, int k) { - if (head == null) { - return; - } - - reGetKthNodeRec(head.next, k); - level++; - if (level == k) { - System.out.println(head.val); - } - } - - /* - * 递归打印出倒数第k个节点。 - * return: the length of the link. - * 此为改进的递归算法,使用此算法,不需要加入辅助变量。 - * */ - public static int reGetKthNodeRec2(ListNode head, int k) { - if (head == null) { - return 0; - } - - int len = reGetKthNodeRec2(head.next, k); - if (len == k - 1) { - System.out.println(head.val); - } - - return len + 1; - } - - /** - * 判断一个单链表中是否有环 - * 这里也是用到两个指针。如果一个链表中有环,也就是说用一个指针去遍历,是永远走不到头的。因此,我们可以用两个指针去遍历,一个指针一次走两步 - * ,一个指针一次走一步,如果有环,两个指针肯定会在环中相遇。时间复杂度为O(n) - */ - public static boolean hasCycle(ListNode head) { - ListNode slow = head; // 快指针每次前进两步 - ListNode fast = head; // 慢指针每次前进一步 - - // 如果fast没有到达尾部,那么slow也不会。所以不需要判定slow是不是null - while (fast != null && fast.next != null) { - fast = fast.next.next; - slow = slow.next; - if (slow == fast) { // 相遇,存在环 - return true; - } - } - - return false; - - } - - /* - * 4. 查找单链表的中间结点: getMiddleNode - * 这里只处理n个数为 奇数的情况 - * 我们可以设置2个 指针,一个快,一个慢 - * 1-2-3-null - * 当fast前进2n时,它到达3,链表长度是2n + 1 - * 中间节点应为(2n+1)/2 + 1 = n + 1; - * 所以,slow节点前进n恰好可以到达中间。 - * - * 边界: - * n = 1时,一开始就可以退出,仍然可以满足 - * 此算法特点: - * 1->2->3->4 - * 返回2 - */ - public static ListNode getMiddleNode(ListNode head) { - if (head == null) { - return null; - } - - ListNode fast = head; - ListNode slow = head; - - while (fast != null && fast.next != null && fast.next.next != null) { - fast = fast.next.next; - slow = slow.next; - } - - return slow; - } - - /** - * 5. 从尾到头打印单链表: reversePrintListStack,reversePrintListRec(递归) - * @param head - * @return - */ - public static void reversePrintListStackRec(ListNode head) { - if (head == null) { - return; - } - - // print the next first. - reversePrintListStackRec(head.next); - System.out.print(head.val + " "); - } - - /** - * 从尾到头打印单链表 - * 对于这种颠倒顺序的问题,我们应该就会想到栈,后进先出。所以,这一题要么自己使用栈,要么让系统使用栈,也就是递归。注意链表为空的情况 - * 。时间复杂度为O(n) - * - * 还有一种做法,是可以把链表反转,我们也可以从头到尾打印。 - */ - public static void reversePrintListStack(ListNode head) { - if (head == null) { - return; - } - - System.out.println(); - - Stack s = new Stack(); - while (head != null) { - s.push(head.val); - head = head.next; - } - - // print the next first. - while (!s.isEmpty()) { - System.out.print(s.pop() + " "); - } - } - - /** - * 从尾到头打印单链表 - * 是可以把链表反转,我们也可以从头到尾打印。 为了不影响原有的链表,可以再反转回来 - */ - public static void reversePrintListRev(ListNode head) { - if (head == null) { - return; - } - - ListNode rev = reverseList(head); - - System.out.println(); - - // print the next first. - ListNode curr = rev; - while (curr != null) { - System.out.print(rev.val + " "); - curr = curr.next; - } - - System.out.println(); - - //printList(rev); - reverseList(rev); - } - - /* - * 6. 已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序: mergeSortedList, mergeSortedListRec - * - * 与merge sort思想类似. - * */ - public static ListNode mergeSortedList(ListNode head1, ListNode head2) { - if (head1 == null) { - return head2; - } else if (head2 == null) { - return head1; - } - - // 作为头节点的前一个节点 - ListNode dummyNode = new ListNode(0); - ListNode curr = dummyNode; - while (head1 != null && head2 != null) { - if (head1.val < head2.val) { - curr.next = head1; - head1 = head1.next; - } else { - curr.next = head2; - head2 = head2.next; - } - - curr = curr.next; - } - - // 把没有取完的链直接接在结果上即可。 - if (head1 != null) { - curr.next = head1; - } else { - curr.next = head2; - } - - return dummyNode.next; - } - - /* - * 先完成的算法,应该会简单一点儿。 - * 简直是优雅的算法啊!太棒了!只不过 为什么自己很难想出这么棒的算法呢? - * 虽然递归的原理每个人都懂,但是写出漂亮的递归真的是考验功底呢。 - * - * 精髓就是: 在每一次的Merge的处理时,只需要考虑merge一个元素,也就是提取出一个元素,而下一步的merge,交给下一步的recursion - * 来处理。 - */ - public static ListNode mergeSortedListRec(ListNode head1, ListNode head2) { - if (head1 == null) { - return head2; - } - - if (head2 == null) { - return head1; - } - - ListNode headMerge = null; - if (head1.val < head2.val) { - headMerge = head1; - head1.next = mergeSortedListRec(head1.next, head2); - } else { - headMerge = head2; - head2.next = mergeSortedListRec(head1, head2.next); - } - - return headMerge; - } - - - // http://fisherlei.blogspot.com/2013/11/leetcode-linked-list-cycle-ii-solution.html - // 更进一步,寻找环的起点,实际上,2点相遇后,我们再将某点放回起点,让它再走X的距离(X为起点到环的交点的距离), - // 即可让2个点相交在环的点处。 - public static ListNode detectCycle(ListNode head) { - ListNode slow = head; - ListNode fast = head; - - while (fast != null && fast.next != null) { - fast = fast.next.next; - slow = slow.next; - if (slow == fast) { - ListNode n1 = head; - while (true) { - if (n1 == slow) { // 注意,要选判断,再移动, - return n1; // because 环的起点有可能就在开始的地方。 - } - n1 = n1.next; - slow = slow.next; - } - } - } - - return null; - } - - /* - * * 8. 判断两个单链表是否相交: isIntersect - * http://blog.csdn.net/yunzhongguwu005/article/details/11527675 - * 求两个单链表是否相交分三种情况讨论: - * 1,如果两个链表一个有环,一个无环则一定不相交 - * 2.如果都没有环,则判断两个链表的最后节点是否相同,如果相同则相交,不相同则不相交。 - * 3.如果都有环,则判断一个链表环里的节点是否是另一个链表环里的节点。如果是则相交,如果不是则不相交。 - * - * 步骤如下: - * 1. 先判断2个链表有没有环。 - * 2. 如果都没有环,查最后节点是否相同 - * 3. 如果都有环,则将b链的环节点跑一圈,如果遇到A链中的节点,则返回true - */ - public static boolean isIntersect(ListNode head1, ListNode head2) { - if (head1 == null || head2 == null) { - return false; - } - - ListNode head1C = hasCycleRetNode(head1); - ListNode head2C = hasCycleRetNode(head2); - - // 两个链表都是有环的。 - if (head1C != null && head2C != null) { - ListNode tmp = head1C; - do { - // 放在前面判断,因为有可能当前节点就是要求的结果 - if (head1C == head2C) { - return true; - } - - // 跑一圈来找是不是同一个圈。 - head1C = head1C.next; - } while (tmp != head1C); - - return false; - // 两个链表都是没有环的 - } else if (head1C == null && head2C == null){ - while (head1.next != null) { - head1 = head1.next; - } - - while (head2.next != null) { - head2 = head2.next; - } - - // 无环的话,应该具有相同的尾节点. - return head1 == head2; - } else { - return false; - } - } - - /** - * 如果有环,返回在环内的某节点。否则返回null - */ - public static ListNode hasCycleRetNode(ListNode head) { - if (head == null) { - return head; - } - - ListNode s = head; - ListNode f = head; - - while (f != null && f.next != null) { - f = f.next.next; - s = s.next; - if (f == s) { - return f; - } - } - - return null; - } - - /* - * * 9. 求两个单链表相交的第一个节点: getFirstCommonNode - * 分为2种情况: - * - * 1. 没有环的情况. - * 求两个单链表相交的第一个节点 对第一个链表遍历,计算长度len1,同时保存最后一个节点的地址。 - * 对第二个链表遍历,计算长度len2,同时检查最后一个节点是否和第一个链表的最后一个节点相同,若不相同,不相交,结束。 - * 两个链表均从头节点开始,假设len1大于len2 - * ,那么将第一个链表先遍历len1-len2个节点,此时两个链表当前节点到第一个相交节点的距离就相等了,然后一起向后遍历,直到两个节点的地址相同。 - * 时间复杂度,O(len1+len2) - * - * ---- len2 - * |__________ - * | - * --------- len1 - * |---|<- len1-len2 - * - * 2. 有环的情况 - * (1). 交点在环上 - * 这样子的话,实际上我们可以求出2个交点。我们只要判断2个交点是不是相等。不相等,把2个交点返回任何一个。 - * (2). 交点不在环上,则计算出环的交点,然后len1 = 起点至环的交点,len2 = 起点至环的交点,然后如方法1相同的做法。 - */ - public static ListNode getFirstCommonNode(ListNode head1, ListNode head2) { - if (head1 == null || head2 == null) { - return null; - } - - ListNode cross1 = detectCycle(head1); - ListNode cross2 = detectCycle(head2); - - // There is no CIRCLE - if (cross1 == null && cross2 == null) { - int len1 = getListLength(head1); - int len2 = getListLength(head2); - - //将长的链截短 - if (len1 > len2) { - while (len1 > len2) { - head1 = head1.next; - len1--; - } - } else { - while (len2 > len1) { - head2 = head2.next; - len2--; - } - } - - while (head1 != null) { - if (head1.next == head2.next) { - return head1.next; - } - } - - return null; - } else if (cross1 != null && cross2 != null) { - return cross1; - } - - return null; - } - - /** - * 求进入环中的第一个节点 用HashSet做 一个无环的链表,它每个结点的地址都是不一样的。 - * 但如果有环,指针沿着链表移动,那这个指针最终会指向一个已经出现过的地址 以地址为哈希表的键值,每出现一个地址, - 只要出现重复的元素,就找到了环的交点. - */ - public static ListNode getFirstNodeInCycleHashMap(ListNode head) { - if (head == null) { - return null; - } - - HashSet h = new HashSet(); - while (head != null) { - if (h.contains(head)) { - return head; - } else { - h.add(head); - } - head = head.next; - } - - return null; - } - - /* - * 对于删除节点,我们普通的思路就是让该节点的前一个节点指向该节点的下一个节点,这种情况需要遍历找到该节点的前一个节点, - * 时间复杂度为O(n)。对于链表,链表中的每个节点结构都是一样的,所以我们可以把该节点的下一个节点的数据复制到该节点, - * 然后删除下一个节点即可。要注意最后一个节点的情况,这个时候只能用常见的方法来操作,先找到前一个节点, - * 但总体的平均时间复杂度还是O(1)。参考代码如下: - * */ - public static void Delete(ListNode head, ListNode toBeDeleted) { - if (head == null) { - return; - } - - if (toBeDeleted.next != null) { - toBeDeleted.val = toBeDeleted.next.val; - toBeDeleted.next = toBeDeleted.next.next; - } else { - while (head != null) { - if (head.next == toBeDeleted) { - head.next = toBeDeleted.next; - return; - } - head = head.next; - } - } - - return; - } -} diff --git a/PostOrder.java b/PostOrder.java index 491b9b9..22ccb70 100644 --- a/PostOrder.java +++ b/PostOrder.java @@ -14,9 +14,6 @@ public class PostOrder { * TreeNode(int x) { val = x; } * } */ - - - public ArrayList postorderTraversal(TreeNode root) { ArrayList result = new ArrayList(); From 841e1670609c3bb25349b5f7e13cc939b7cdff84 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Tue, 23 Sep 2014 16:17:36 -0700 Subject: [PATCH 02/66] add the demos --- GraphDemo.java | 103 +++++++ ListNodeDemo.java | 716 ++++++++++++++++++++++++++++++++++++++++++++++ TreeDemo.java | 571 ++++++++++++++++++++++++++++++++++++ 3 files changed, 1390 insertions(+) create mode 100644 GraphDemo.java create mode 100644 ListNodeDemo.java create mode 100644 TreeDemo.java diff --git a/GraphDemo.java b/GraphDemo.java new file mode 100644 index 0000000..241d5ca --- /dev/null +++ b/GraphDemo.java @@ -0,0 +1,103 @@ +package Algorithms; + +import java.util.ArrayList; + +public class GraphDemo { + private static int M = Integer.MAX_VALUE; // 表示此路不可通 + + // http://www.geeksforgeeks.org/greedy-algorithms-set-6-dijkstras-shortest-path-algorithm/ + // 以上为不能再优美的C语言实现。 + public static void main(String[] args) { + int[][] w = { // 用邻接表矩阵表示的无向图 + {0, 3, 2000, 7, M}, + {3, 0, 4, 2, M}, + {M, 4, 0, 5, 4}, + {7, 2, 5, 0, 6}, + {M, M , 4, 6, 0} + }; + + int[][] w2 = { // 用邻接表矩阵表示的无向图 + {0, 10, M, 30, 100}, + {M, 0, 50, M, M}, + {M, M, 0, M, 10}, + {M, M, 20, 0, 60}, + {M, M, M, M, 0} + }; + + int start = 0; + + int[] shortPath = dijkstra(w2, start); + + for (int i = 0; i < shortPath.length; i++) { + System.out.println("The shortest path length from start to " + i + " is:" + shortPath[i]); + } + } + + public static int[] dijkstra(int[][] graph, int src) { + if (graph == null || graph.length == 0 || graph[0].length == 0) { + return null; + } + + // get to know the number of the vertexs. + int v = graph.length; + + // We need a indicator to know if we have visited the vertex. + boolean visit[] = new boolean[v]; + + // record the length result. + int[] pathLen = new int[v]; + + // record the path. + ArrayList> path = new ArrayList>(); + for (int i = 0; i < v; i++) { + path.add(new ArrayList()); + path.get(i).add(0); + path.get(i).add(i); + } + + // setup the source vertex; + visit[0] = true; + pathLen[0] = 0; + + // stop when all the vertices has been added into the result set. + for (int i = 0; i < v - 1; i++) { + + int minLen = M; + int minIndex = -1; + for (int j = 0; j < v; j++) { + // sometimes there is no route, so just let equal also return. + // so we use graph[src][j] <= minLen + if (!visit[j] && graph[src][j] <= minLen) { + minLen = graph[src][j]; + minIndex = j; + } + } + + // get the new shortest path, add it into the solution set. + visit[minIndex] = true; + pathLen[minIndex] = graph[src][minIndex]; + + // update all the neighbors of the new vertex. + for (int k = 0; k < v; k++) { + // if the path which pass the minIndex is shorter than the former path, + // just update it. + if (!visit[k] + && graph[src][minIndex] != M + && graph[minIndex][k] != M + && graph[src][minIndex] + graph[minIndex][k] < graph[src][k]) { + graph[src][k] = graph[src][minIndex] + graph[minIndex][k]; + + path.set(k, new ArrayList(path.get(minIndex))); + path.get(k).add(k); + } + } + } + + for (ArrayList array: path) { + System.out.println(array.toString()); + } + + return pathLen; + } + +} diff --git a/ListNodeDemo.java b/ListNodeDemo.java new file mode 100644 index 0000000..f23327d --- /dev/null +++ b/ListNodeDemo.java @@ -0,0 +1,716 @@ +package Algorithms; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Stack; + +/** + * REFS: + * http://blog.csdn.net/fightforyourdream/article/details/16353519 + * http://blog.csdn.net/luckyxiaoqiang/article/details/7393134 轻松搞定面试中的链表题目 + * http://www.cnblogs.com/jax/archive/2009/12/11/1621504.html 算法大全(1)单链表 + * + * 目录: + * 1. 求单链表中结点的个数: getListLength + * 2. 将单链表反转: reverseList(遍历),reverseListRec(递归) + * 3. 查找单链表中的倒数第K个节点(k > 0): reGetKthNode + * 4. 查找单链表的中间结点: getMiddleNode + * 5. 从尾到头打印单链表: reversePrintListStack,reversePrintListRec(递归) + * 6. 已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序: mergeSortedList, mergeSortedListRec + * 7. 判断一个单链表中是否有环: hasCycle + * 8. 判断两个单链表是否相交: isIntersect + * 9. 求两个单链表相交的第一个节点: getFirstCommonNode + * 10. 已知一个单链表中存在环,求进入环中的第一个节点: detectCycle, getFirstNodeInCycleHashMap + * 11. 给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted: delete + * + */ + +public class ListNodeDemo { + + // create the link Node class. + // why use static: + // http://duqiangcise.iteye.com/blog/697476 + private static class ListNode { + int val; + ListNode next; + public ListNode(int val) { + this.val = val; + this.next = null; + } + + } + + public static void main(String[] args) { + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(2); + ListNode n3 = new ListNode(3); + ListNode n4 = new ListNode(4); + ListNode n5 = new ListNode(5); + ListNode n6 = new ListNode(6); + + ListNode m1 = new ListNode(5); + ListNode m2 = new ListNode(8); + ListNode m3 = new ListNode(9); + m1.next = m2; + m2.next = m3; + + ListNode c1 = new ListNode(1); + ListNode c2 = new ListNode(12); + c1.next = c2; + //c2.next = n1; + + ListNode mergeNode = mergeLink(m1, c1); + //ListNode mergeNode2 = mergeLink(m1, c1); + //ListNode mergeNode = mergeSortedList(m1, c1); + printList(mergeNode); + //printList(mergeNode2); + + System.out.println(); + + n1.next = n2; + n2.next = n3; + n3.next = n4; + n4.next = n5; + + printList(n1); + + Delete(n1, n5); + + printList(n1); + + // create a cycle + //n5.next = n3; + //n5.next = n6; + //n6.next = n4; + +// System.out.println(hasCycle(n1)); +// System.out.println(getListLength(n1)); +// printList(n1); +// +// //n1 = reverseList(n1); +// n1 = reverseListRec(n1); +// printList(n1); + +// ListNode ret = reGetKthNode(n1, 7); +// if (ret != null) { +// System.out.println(ret.val); +// } else { +// System.out.println("null"); +// } + + //reGetKthNodeRec(n1, 1); +// reGetKthNodeRec2(n1, 3); +// ListNode ret = getMiddleNode(n1); +// +// if (ret != null) { +// System.out.println(ret.val); +// } +// +// reversePrintListStackRec(n1); +// reversePrintListStack(n1); +// reversePrintListRev(n1); + + //printList(n1); + + System.out.println(isIntersect(n1, c1)); + + ListNode cross = getFirstCommonNode(n1, c1); + if (cross == null) { + System.out.println("null"); + } else { + System.out.println(cross.val); + } + + ListNode cross2 = getFirstNodeInCycleHashMap(c1); + if (cross2 == null) { + System.out.println("null"); + } else { + System.out.println(cross2.val); + } + } + + public static void printList(ListNode head) { + while (head != null) { + System.out.print(head.val + " "); + head = head.next; + } + + System.out.println(); + } + + // 获得ListNode 的长度 + public static int getListLength(ListNode head) { + if (head == null) { + return 0; + } + + int len = 0; + while (head != null) { + len++; + head = head.next; + } + + return len; + } + + /* + * 反转链表 + * 此算法亮点是:一次只需要处理把下一个节点指向curr, + * 不断循环,即可完成任务 + * */ + public static ListNode reverseList(ListNode head) { + if (head == null) { + return null; + } + + ListNode next = head.next; + ListNode curr = head; + + // 先把头节点的下一个指定. + curr.next = null; + + // 每次只需要将curr的next指向curr即可, + // 终止条件是:next是null 表示我们将所有的节点进行了翻转 + while (next != null) { + ListNode tmp = next.next; + next.next = curr; + curr = next; + next = tmp; + } + + return curr; + } + + // 翻转递归(递归) + // 递归的精髓在于你就默认reverseListRec已经成功帮你解决了子问题了!但别去想如何解决的 + // 现在只要处理当前node和子问题之间的关系。最后就能圆满解决整个问题。 + /* + head + 1 -> 2 -> 3 -> 4 + + head + 1-------------- + | + 4 -> 3 -> 2 // Node reHead = reverseListRec(head.next); + reHead head.next + + 4 -> 3 -> 2 -> 1 // head.next.next = head; + reHead + + 4 -> 3 -> 2 -> 1 -> null // head.next = null; + reHead + */ + public static ListNode reverseListRec(ListNode head) { + // if there is no node, or only one node, just return; + if (head == null || head.next == null) { + return head; + } + + ListNode reHead = reverseListRec(head.next); // 先求解子问题。 + head.next.next = head; // 将head 与被解决的子串的尾部相连。 + head.next = null; // head的下一个必须指向 null,因为head 是新的尾部. + + return reHead; + } + + /** + * 查找单链表中的倒数第K个结点(k > 0) + * 最普遍的方法是,先统计单链表中结点的个数,然后再找到第(n-k)个结点。注意链表为空,k为0,k为1,k大于链表中节点个数时的情况 + * 。时间复杂度为O(n)。代码略。 这里主要讲一下另一个思路,这种思路在其他题目中也会有应用。 + * 主要思路就是使用两个指针,先让前面的指针走到正向第k个结点 + * ,这样前后两个指针的距离差是k,之后前后两个指针一起向前走,前面的指针走到空时,后面指针所指结点就是倒数第k个结点 + * when k = 1, it should be the last node. + */ + public static ListNode reGetKthNode(ListNode head, int k) { + if (head == null) { + return null; + } + + ListNode fast = head; + + // 使fast and slow之间差 k + while (k > 0) { + if (fast == null) { + // 发生这种情况,说明k > sizeOfList. + return null; + } + fast = fast.next; + k--; + } + + while (fast != null) { + fast = fast.next; + head = head.next; + } + + return head; + } + + /* + * 递归打印出倒数第k个节点。 + * */ + static int level = 0; + public static void reGetKthNodeRec(ListNode head, int k) { + if (head == null) { + return; + } + + reGetKthNodeRec(head.next, k); + level++; + if (level == k) { + System.out.println(head.val); + } + } + + /* + * 递归打印出倒数第k个节点。 + * return: the length of the link. + * 此为改进的递归算法,使用此算法,不需要加入辅助变量。 + * */ + public static int reGetKthNodeRec2(ListNode head, int k) { + if (head == null) { + return 0; + } + + int len = reGetKthNodeRec2(head.next, k); + if (len == k - 1) { + System.out.println(head.val); + } + + return len + 1; + } + + /** + * 判断一个单链表中是否有环 + * 这里也是用到两个指针。如果一个链表中有环,也就是说用一个指针去遍历,是永远走不到头的。因此,我们可以用两个指针去遍历,一个指针一次走两步 + * ,一个指针一次走一步,如果有环,两个指针肯定会在环中相遇。时间复杂度为O(n) + */ + public static boolean hasCycle(ListNode head) { + ListNode slow = head; // 快指针每次前进两步 + ListNode fast = head; // 慢指针每次前进一步 + + // 如果fast没有到达尾部,那么slow也不会。所以不需要判定slow是不是null + while (fast != null && fast.next != null) { + fast = fast.next.next; + slow = slow.next; + if (slow == fast) { // 相遇,存在环 + return true; + } + } + + return false; + + } + + /* + * 4. 查找单链表的中间结点: getMiddleNode + * 这里只处理n个数为 奇数的情况 + * 我们可以设置2个 指针,一个快,一个慢 + * 1-2-3-null + * 当fast前进2n时,它到达3,链表长度是2n + 1 + * 中间节点应为(2n+1)/2 + 1 = n + 1; + * 所以,slow节点前进n恰好可以到达中间。 + * + * 边界: + * n = 1时,一开始就可以退出,仍然可以满足 + * 此算法特点: + * 1->2->3->4 + * 返回2 + */ + public static ListNode getMiddleNode(ListNode head) { + if (head == null) { + return null; + } + + ListNode fast = head; + ListNode slow = head; + + while (fast != null && fast.next != null && fast.next.next != null) { + fast = fast.next.next; + slow = slow.next; + } + + return slow; + } + + /** + * 5. 从尾到头打印单链表: reversePrintListStack,reversePrintListRec(递归) + * @param head + * @return + */ + public static void reversePrintListStackRec(ListNode head) { + if (head == null) { + return; + } + + // print the next first. + reversePrintListStackRec(head.next); + System.out.print(head.val + " "); + } + + /** + * 从尾到头打印单链表 + * 对于这种颠倒顺序的问题,我们应该就会想到栈,后进先出。所以,这一题要么自己使用栈,要么让系统使用栈,也就是递归。注意链表为空的情况 + * 。时间复杂度为O(n) + * + * 还有一种做法,是可以把链表反转,我们也可以从头到尾打印。 + */ + public static void reversePrintListStack(ListNode head) { + if (head == null) { + return; + } + + System.out.println(); + + Stack s = new Stack(); + while (head != null) { + s.push(head.val); + head = head.next; + } + + // print the next first. + while (!s.isEmpty()) { + System.out.print(s.pop() + " "); + } + } + + /** + * 从尾到头打印单链表 + * 是可以把链表反转,我们也可以从头到尾打印。 为了不影响原有的链表,可以再反转回来 + */ + public static void reversePrintListRev(ListNode head) { + if (head == null) { + return; + } + + ListNode rev = reverseList(head); + + System.out.println(); + + // print the next first. + ListNode curr = rev; + while (curr != null) { + System.out.print(rev.val + " "); + curr = curr.next; + } + + System.out.println(); + + //printList(rev); + reverseList(rev); + } + + /* + * 6. 已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序: mergeSortedList, mergeSortedListRec + * + * 与merge sort思想类似. + * */ + public static ListNode mergeSortedList(ListNode head1, ListNode head2) { + if (head1 == null) { + return head2; + } else if (head2 == null) { + return head1; + } + + // 作为头节点的前一个节点 + ListNode dummyNode = new ListNode(0); + ListNode curr = dummyNode; + while (head1 != null && head2 != null) { + if (head1.val < head2.val) { + curr.next = head1; + head1 = head1.next; + } else { + curr.next = head2; + head2 = head2.next; + } + + curr = curr.next; + } + + // 把没有取完的链直接接在结果上即可。 + if (head1 != null) { + curr.next = head1; + } else { + curr.next = head2; + } + + return dummyNode.next; + } + + static class Node { + Node next; + int val; + Node (int val) { + this.val = val; + } + } + + public static ListNode mergeLink (ListNode aLink, ListNode bLink) { + ListNode dummy = new ListNode(0); + + ListNode root = dummy; + + while (aLink != null && bLink != null) { + if (aLink.val < bLink.val) { + dummy.next = aLink; + dummy = aLink; + aLink = aLink.next; + + } else { + dummy.next = bLink; + dummy = bLink; + bLink = bLink.next; + + } + } + + if (aLink != null) { + dummy.next = aLink; + } else { + dummy.next = bLink; + } + + return root.next; + } + + /* + * 先完成的算法,应该会简单一点儿。 + * 简直是优雅的算法啊!太棒了!只不过 为什么自己很难想出这么棒的算法呢? + * 虽然递归的原理每个人都懂,但是写出漂亮的递归真的是考验功底呢。 + * + * 精髓就是: 在每一次的Merge的处理时,只需要考虑merge一个元素,也就是提取出一个元素,而下一步的merge,交给下一步的recursion + * 来处理。 + */ + public static ListNode mergeSortedListRec(ListNode head1, ListNode head2) { + if (head1 == null) { + return head2; + } + + if (head2 == null) { + return head1; + } + + ListNode headMerge = null; + if (head1.val < head2.val) { + headMerge = head1; + head1.next = mergeSortedListRec(head1.next, head2); + } else { + headMerge = head2; + head2.next = mergeSortedListRec(head1, head2.next); + } + + return headMerge; + } + + + // http://fisherlei.blogspot.com/2013/11/leetcode-linked-list-cycle-ii-solution.html + // 更进一步,寻找环的起点,实际上,2点相遇后,我们再将某点放回起点,让它再走X的距离(X为起点到环的交点的距离), + // 即可让2个点相交在环的点处。 + public static ListNode detectCycle(ListNode head) { + ListNode slow = head; + ListNode fast = head; + + while (fast != null && fast.next != null) { + fast = fast.next.next; + slow = slow.next; + if (slow == fast) { + ListNode n1 = head; + while (true) { + if (n1 == slow) { // 注意,要选判断,再移动, + return n1; // because 环的起点有可能就在开始的地方。 + } + n1 = n1.next; + slow = slow.next; + } + } + } + + return null; + } + + /* + * * 8. 判断两个单链表是否相交: isIntersect + * http://blog.csdn.net/yunzhongguwu005/article/details/11527675 + * 求两个单链表是否相交分三种情况讨论: + * 1,如果两个链表一个有环,一个无环则一定不相交 + * 2.如果都没有环,则判断两个链表的最后节点是否相同,如果相同则相交,不相同则不相交。 + * 3.如果都有环,则判断一个链表环里的节点是否是另一个链表环里的节点。如果是则相交,如果不是则不相交。 + * + * 步骤如下: + * 1. 先判断2个链表有没有环。 + * 2. 如果都没有环,查最后节点是否相同 + * 3. 如果都有环,则将b链的环节点跑一圈,如果遇到A链中的节点,则返回true + */ + public static boolean isIntersect(ListNode head1, ListNode head2) { + if (head1 == null || head2 == null) { + return false; + } + + ListNode head1C = hasCycleRetNode(head1); + ListNode head2C = hasCycleRetNode(head2); + + // 两个链表都是有环的。 + if (head1C != null && head2C != null) { + ListNode tmp = head1C; + do { + // 放在前面判断,因为有可能当前节点就是要求的结果 + if (head1C == head2C) { + return true; + } + + // 跑一圈来找是不是同一个圈。 + head1C = head1C.next; + } while (tmp != head1C); + + return false; + // 两个链表都是没有环的 + } else if (head1C == null && head2C == null){ + while (head1.next != null) { + head1 = head1.next; + } + + while (head2.next != null) { + head2 = head2.next; + } + + // 无环的话,应该具有相同的尾节点. + return head1 == head2; + } else { + return false; + } + } + + /** + * 如果有环,返回在环内的某节点。否则返回null + */ + public static ListNode hasCycleRetNode(ListNode head) { + if (head == null) { + return head; + } + + ListNode s = head; + ListNode f = head; + + while (f != null && f.next != null) { + f = f.next.next; + s = s.next; + if (f == s) { + return f; + } + } + + return null; + } + + /* + * * 9. 求两个单链表相交的第一个节点: getFirstCommonNode + * 分为2种情况: + * + * 1. 没有环的情况. + * 求两个单链表相交的第一个节点 对第一个链表遍历,计算长度len1,同时保存最后一个节点的地址。 + * 对第二个链表遍历,计算长度len2,同时检查最后一个节点是否和第一个链表的最后一个节点相同,若不相同,不相交,结束。 + * 两个链表均从头节点开始,假设len1大于len2 + * ,那么将第一个链表先遍历len1-len2个节点,此时两个链表当前节点到第一个相交节点的距离就相等了,然后一起向后遍历,直到两个节点的地址相同。 + * 时间复杂度,O(len1+len2) + * + * ---- len2 + * |__________ + * | + * --------- len1 + * |---|<- len1-len2 + * + * 2. 有环的情况 + * (1). 交点在环上 + * 这样子的话,实际上我们可以求出2个交点。我们只要判断2个交点是不是相等。不相等,把2个交点返回任何一个。 + * (2). 交点不在环上,则计算出环的交点,然后len1 = 起点至环的交点,len2 = 起点至环的交点,然后如方法1相同的做法。 + */ + public static ListNode getFirstCommonNode(ListNode head1, ListNode head2) { + if (head1 == null || head2 == null) { + return null; + } + + ListNode cross1 = detectCycle(head1); + ListNode cross2 = detectCycle(head2); + + // There is no CIRCLE + if (cross1 == null && cross2 == null) { + int len1 = getListLength(head1); + int len2 = getListLength(head2); + + //将长的链截短 + if (len1 > len2) { + while (len1 > len2) { + head1 = head1.next; + len1--; + } + } else { + while (len2 > len1) { + head2 = head2.next; + len2--; + } + } + + while (head1 != null) { + if (head1.next == head2.next) { + return head1.next; + } + } + + return null; + } else if (cross1 != null && cross2 != null) { + return cross1; + } + + return null; + } + + /** + * 求进入环中的第一个节点 用HashSet做 一个无环的链表,它每个结点的地址都是不一样的。 + * 但如果有环,指针沿着链表移动,那这个指针最终会指向一个已经出现过的地址 以地址为哈希表的键值,每出现一个地址, + 只要出现重复的元素,就找到了环的交点. + */ + public static ListNode getFirstNodeInCycleHashMap(ListNode head) { + if (head == null) { + return null; + } + + HashSet h = new HashSet(); + while (head != null) { + if (h.contains(head)) { + return head; + } else { + h.add(head); + } + head = head.next; + } + + return null; + } + + /* + * 对于删除节点,我们普通的思路就是让该节点的前一个节点指向该节点的下一个节点,这种情况需要遍历找到该节点的前一个节点, + * 时间复杂度为O(n)。对于链表,链表中的每个节点结构都是一样的,所以我们可以把该节点的下一个节点的数据复制到该节点, + * 然后删除下一个节点即可。要注意最后一个节点的情况,这个时候只能用常见的方法来操作,先找到前一个节点, + * 但总体的平均时间复杂度还是O(1)。参考代码如下: + * */ + public static void Delete(ListNode head, ListNode toBeDeleted) { + if (head == null) { + return; + } + + if (toBeDeleted.next != null) { + toBeDeleted.val = toBeDeleted.next.val; + toBeDeleted.next = toBeDeleted.next.next; + } else { + while (head != null) { + if (head.next == toBeDeleted) { + head.next = toBeDeleted.next; + return; + } + head = head.next; + } + } + + return; + } +} diff --git a/TreeDemo.java b/TreeDemo.java new file mode 100644 index 0000000..4982693 --- /dev/null +++ b/TreeDemo.java @@ -0,0 +1,571 @@ +package Algorithms; + + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Stack; + + +public class TreeDemo { + /* + 1 + / \ + 2 3 + / \ \ + 4 5 6 + */ + public static void main(String[] args) { +// TreeNode r1 = new TreeNode(1); +// TreeNode r2 = new TreeNode(2); +// TreeNode r3 = new TreeNode(3); +// TreeNode r4 = new TreeNode(4); +// TreeNode r5 = new TreeNode(5); +// TreeNode r6 = new TreeNode(6); + +/* + 10 + / \ + 6 14 + / \ \ + 4 8 16 +*/ + TreeNode r1 = new TreeNode(10); + TreeNode r2 = new TreeNode(6); + TreeNode r3 = new TreeNode(14); + TreeNode r4 = new TreeNode(4); + TreeNode r5 = new TreeNode(8); + TreeNode r6 = new TreeNode(16); + + TreeNode r7 = new TreeNode(0); + + r1.left = r2; + r1.right = r3; + r2.left = r4; + r2.right = r5; + r3.right = r6; + + r4.left = r7; + +// System.out.println(getNodeNumRec(null)); +// System.out.println(getNodeNum(r1)); +// System.out.println(getDepthRec(r1)); +// System.out.println(getDepth(r1)); +// +// preorderTraversalRec(r1); +// System.out.println(); +// preorderTraversal(r1); +// System.out.println(); +// inorderTraversalRec(r1); +// +// System.out.println(); + inorderTraversal(r1); +// postorderTraversalRec(r1); +// System.out.println(); +// postorderTraversal(r1); +// System.out.println(); +// levelTraversal(r1); +// +// System.out.println(); +// levelTraversalRec(r1); + +// TreeNode ret = convertBST2DLLRec(r1); +// while (ret != null) { +// System.out.print(ret.val + " "); +// ret = ret.right; +// } + +// TreeNode ret2 = convertBST2DLL(r1); +// while (ret2.right != null) { +// ret2 = ret2.right; +// } +// +// while (ret2 != null) { +// System.out.print(ret2.val + " "); +// ret2 = ret2.left; +// } +// +// TreeNode ret = convertBST2DLL(r1); +// while (ret != null) { +// System.out.print(ret.val + " "); +// ret = ret.right; +// } + + System.out.println(); + System.out.println(findLongest(r1)); + System.out.println(); + System.out.println(findLongest2(r1)); + + } + + private static class TreeNode{ + int val; + TreeNode left; + TreeNode right; + public TreeNode(int val){ + this.val = val; + left = null; + right = null; + } + } + + /* + * null返回0,然后把左右子树的size加上即可。 + * */ + public static int getNodeNumRec(TreeNode root) { + if (root == null) { + return 0; + } + + return getNodeNumRec(root.left) + getNodeNumRec(root.right) + 1; + } + + /** + * 求二叉树中的节点个数迭代解法O(n):基本思想同LevelOrderTraversal, + * 即用一个Queue,在Java里面可以用LinkedList来模拟 + */ + public static int getNodeNum(TreeNode root) { + if (root == null) { + return 0; + } + + Queue q = new LinkedList(); + q.offer(root); + + int cnt = 0; + while (!q.isEmpty()) { + TreeNode node = q.poll(); + if (node.left != null) { + q.offer(node.left); + } + + if (node.right != null) { + q.offer(node.right); + } + + cnt++; + } + + return cnt; + } + + public static int getDepthRec(TreeNode root) { + if (root == null) { + return 0; + } + + return Math.max(getDepthRec(root.left), getDepthRec(root.right)) + 1; + } + + /* + * 可以用 level LevelOrderTraversal 来实现,我们用一个dummyNode来分隔不同的层,这样即可计算出实际的depth. + * 1 + / \ + 2 3 + / \ \ + 4 5 6 + * + * 在队列中如此排列: 1, dummy, 2, 3, dummy, 4, 5, 5, dummy + * + */ + public static int getDepth(TreeNode root) { + if (root == null) { + return 0; + } + + TreeNode dummy = new TreeNode(0); + Queue q = new LinkedList(); + q.offer(root); + q.offer(dummy); + + int depth = 0; + while (!q.isEmpty()) { + TreeNode curr = q.poll(); + if (curr == dummy) { + depth++; + if (!q.isEmpty()) { // 使用DummyNode来区分不同的层, 如果下一层不是为空,则应该在尾部加DummyNode. + q.offer(dummy); + } + } + + if (curr.left != null) { + q.offer(curr.left); + } + if (curr.right != null) { + q.offer(curr.right); + } + } + + return depth; + } + + /* + * 3. 前序遍历,中序遍历,后序遍历: preorderTraversalRec, preorderTraversal, inorderTraversalRec, postorderTraversalRec + * (https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_2) + * */ + public static void preorderTraversalRec(TreeNode root) { + if (root == null) { + return; + } + + System.out.print(root.val + " "); + preorderTraversalRec(root.left); + preorderTraversalRec(root.right); + } + + /* + * 前序遍历,Iteration 算法. 把根节点存在stack中。 + * */ + public static void preorderTraversal(TreeNode root) { + if (root == null) { + return; + } + + Stack s = new Stack(); + s.push(root); + + while (!s.isEmpty()) { + TreeNode node = s.pop(); + System.out.print(node.val + " "); + if (node.right != null) { // + s.push(node.right); + } + + // 我们需要先压入右节点,再压入左节点,这样就可以先弹出左节点。 + if (node.left != null) { + s.push(node.left); + } + } + } + + /* + * 中序遍历 + * */ + public static void inorderTraversalRec(TreeNode root) { + if (root == null) { + return; + } + + inorderTraversalRec(root.left); + System.out.print(root.val + " "); + inorderTraversalRec(root.right); + } + + /** + * 中序遍历迭代解法 ,用栈先把根节点的所有左孩子都添加到栈内, + * 然后输出栈顶元素,再处理栈顶元素的右子树 + * http://www.youtube.com/watch?v=50v1sJkjxoc + * + * 还有一种方法能不用递归和栈,基于线索二叉树的方法,较麻烦以后补上 + * http://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion-and-without-stack/ + */ + public static void inorderTraversal(TreeNode root) { + if (root == null) { + return; + } + + Stack s = new Stack(); + + TreeNode cur = root; + + while(true) { + // 把当前节点的左节点都push到栈中. + while (cur != null) { + s.push(cur); + cur = cur.left; + } + + if (s.isEmpty()) { + break; + } + + // 因为此时已经没有左孩子了,所以输出栈顶元素 + cur = s.pop(); + System.out.print(cur.val + " "); + + // 准备处理右子树 + cur = cur.right; + } + } + + // 后序遍历 + /* + * 1 + / \ + 2 3 + / \ \ + 4 5 6 + + if put into the stack directly, then it should be: + 1, 2, 4, 5, 3, 6 in the stack. + when pop, it should be: 6, 3, 5, 4, 2, 1 + + if I + * */ + + public static void postorderTraversalRec(TreeNode root) { + if (root == null) { + return; + } + + postorderTraversalRec(root.left); + postorderTraversalRec(root.right); + System.out.print(root.val + " "); + } + + /** + * 后序遍历迭代解法 + * http://www.youtube.com/watch?v=hv-mJUs5mvU + * http://blog.csdn.net/tang_jin2015/article/details/8545457 + * 从左到右的后序 与从右到左的前序的逆序是一样的,所以就简单喽! 哈哈 + * 用另外一个栈进行翻转即可喽 + */ + public static void postorderTraversal(TreeNode root) { + if (root == null) { + return; + } + + Stack s = new Stack(); + Stack out = new Stack(); + + s.push(root); + while(!s.isEmpty()) { + TreeNode cur = s.pop(); + out.push(cur); + + if (cur.left != null) { + s.push(cur.left); + } + if (cur.right != null) { + s.push(cur.right); + } + } + + while(!out.isEmpty()) { + System.out.print(out.pop().val + " "); + } + } + + /* + * 分层遍历二叉树(按层次从上往下,从左往右)迭代 + * 其实就是广度优先搜索,使用队列实现。队列初始化,将根节点压入队列。当队列不为空,进行如下操作:弹出一个节点 + * ,访问,若左子节点或右子节点不为空,将其压入队列 + * */ + public static void levelTraversal(TreeNode root) { + if (root == null) { + return; + } + + Queue q = new LinkedList(); + q.offer(root); + + while (!q.isEmpty()) { + TreeNode cur = q.poll(); + + System.out.print(cur.val + " "); + if (cur.left != null) { + q.offer(cur.left); + } + if (cur.right != null) { + q.offer(cur.right); + } + } + } + + public static void levelTraversalRec(TreeNode root) { + ArrayList> ret = new ArrayList>(); + levelTraversalVisit(root, 0, ret); + System.out.println(ret); + } + + /** + * 分层遍历二叉树(递归) + * 很少有人会用递归去做level traversal + * 基本思想是用一个大的ArrayList,里面包含了每一层的ArrayList。 + * 大的ArrayList的size和level有关系 + * + * http://discuss.leetcode.com/questions/49/binary-tree-level-order-traversal#answer-container-2543 + */ + public static void levelTraversalVisit(TreeNode root, int level, ArrayList> ret) { + if (root == null) { + return; + } + + // 如果ArrayList的层数不够用, 则新添加一层 + // when size = 3, level: 0, 1, 2 + if (level >= ret.size()) { + ret.add(new ArrayList()); + } + + // visit 当前节点 + ret.get(level).add(root.val); + + // 将左子树, 右子树添加到对应的层。 + levelTraversalVisit(root.left, level + 1, ret); + levelTraversalVisit(root.right, level + 1, ret); + } + + /* + * 题目要求:将二叉查找树转换成排序的双向链表,不能创建新节点,只调整指针。 + 查找树的结点定义如下: + 既然是树,其定义本身就是递归的,自然用递归算法处理就很容易。将根结点的左子树和右子树转换为有序的双向链表, + 然后根节点的left指针指向左子树结果的最后一个结点,同时左子树最后一个结点的right指针指向根节点; + 根节点的right指针指向右子树结果的第一个结点, + 同时右子树第一个结点的left指针指向根节点。 + * */ + public static TreeNode convertBST2DLLRec(TreeNode root) { + return convertBST2DLLRecHelp(root)[0]; + } + + /* + * ret[0] 代表左指针 + * ret[1] 代表右指针 + * */ + public static TreeNode[] convertBST2DLLRecHelp(TreeNode root) { + TreeNode[] ret = new TreeNode[2]; + ret[0] = null; + ret[1] = null; + + if (root == null) { + return ret; + } + + if (root.left != null) { + TreeNode left[] = convertBST2DLLRecHelp(root.left); + left[1].right = root; // 将左子树的尾节点连接到根 + root.left = left[1]; + + ret[0] = left[0]; + } else { + ret[0] = root; // 左节点返回root. + } + + if (root.right != null) { + TreeNode right[] = convertBST2DLLRecHelp(root.right); + right[0].left = root; // 将右子树的头节点连接到根 + root.right = right[0]; + + ret[1] = right[1]; + } else { + ret[1] = root; // 右节点返回root. + } + + return ret; + } + + /** + * 将二叉查找树变为有序的双向链表 迭代解法 + * 类似inOrder traversal的做法 + */ + public static TreeNode convertBST2DLL(TreeNode root) { + while (root == null) { + return null; + } + + TreeNode pre = null; + Stack s = new Stack(); + TreeNode cur = root; + TreeNode head = null; // 链表头 + + while (true) { + while (cur != null) { + s.push(cur); + cur = cur.left; + } + + // if stack is empty, just break; + if (s.isEmpty()) { + break; + } + + cur = s.pop(); + if (head == null) { + head = cur; + } + + // link pre and cur. + cur.left = pre; + if (pre != null) { + pre.right = cur; + } + + // 左节点已经处理完了,处理右节点 + cur = cur.right; + pre = cur; + } + + return root; + } + + /* + * 第一种解法: + * 返回左边最长,右边最长,及左子树最长,右子树最长。 + * */ + public static int findLongest(TreeNode root) { + if (root == null) { + return -1; + } + + TreeNode l = root; + int cntL = 0; + while (l.left != null) { + cntL++; + l = l.left; + } + + TreeNode r = root; + int cntR = 0; + while (r.right != null) { + cntR++; + r = r.right; + } + + int lmax = findLongest(root.left); + int rmax = findLongest(root.right); + + int max = Math.max(lmax, rmax); + max = Math.max(max, cntR); + max = Math.max(max, cntL); + + return max; + } + + /* 1 + * 2 3 + * 3 4 + * 6 1 + * 7 + * 9 + * 11 + * 2 + * 14 + * */ + public static int findLongest2(TreeNode root) { + int [] maxVal = new int[1]; + maxVal[0] = -1; + findLongest2Help(root, maxVal); + return maxVal[0]; + } + + // ret: + // 0: the left side longest, + // 1: the right side longest. + static int maxLen = -1; + static int[] findLongest2Help(TreeNode root, int[] maxVal) { + int[] ret = new int[2]; + if (root == null) { + ret[0] = -1; + ret[1] = -1; + return ret; + } + + ret[0] = findLongest2Help(root.left, maxVal)[0] + 1; + ret[1] = findLongest2Help(root.right, maxVal)[1] + 1; + //maxLen = Math.max(maxLen, ret[0]); + //maxLen = Math.max(maxLen, ret[1]); + maxVal[0] = Math.max(maxVal[0], ret[0]); + maxVal[0] = Math.max(maxVal[0], ret[1]); + + return ret; + } +} \ No newline at end of file From dabfdb726c78860b3472e8713c9c88dc94dd0acd Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Wed, 24 Sep 2014 20:39:58 -0700 Subject: [PATCH 03/66] min cut --- MinCut.java | 35 +++++++++++++ TreeDemo.java | 135 +++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 163 insertions(+), 7 deletions(-) create mode 100644 MinCut.java diff --git a/MinCut.java b/MinCut.java new file mode 100644 index 0000000..97c8e3c --- /dev/null +++ b/MinCut.java @@ -0,0 +1,35 @@ +package Algorithms; + +public class MinCut { + public int minCut(String s) { + if (s == null || s.length() == 0) { + return 0; + } + + int len = s.length(); + int[] D = new int[len]; + + boolean[][] isPalid = new boolean[len][len]; + + for (int i = len - 1; i >= 0; i--) { + // the worst case is divide the word one by one. + D[i] = len - 1 -i; + for (int j = i; j <= len - 1; j++) { + // init it to be false; + isPalid[i][j] = false; + + if (s.charAt(i) == s.charAt(j) && (j - i <= 1 || isPalid[i + 1][j - 1])) { + isPalid[i][j] = true; + if (j == len - 1) { + D[i] = 0; + } else { + // 如果前半部分是回文,那么我们可以分解为第一个回文 + 后半部分的最小分割数 + D[i] = Math.min(D[i], D[j + 1] + 1); + } + } + } + } + + return D[0]; + } +} diff --git a/TreeDemo.java b/TreeDemo.java index 4982693..8d50afb 100644 --- a/TreeDemo.java +++ b/TreeDemo.java @@ -1,11 +1,36 @@ package Algorithms; - import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue; import java.util.Stack; +/** + * REF: http://blog.csdn.net/fightforyourdream/article/details/16843303 + * + * http://blog.csdn.net/luckyxiaoqiang/article/details/7518888 轻松搞定面试中的二叉树题目 + * http://www.cnblogs.com/Jax/archive/2009/12/28/1633691.html 算法大全(3) 二叉树 + * + * 1. 求二叉树中的节点个数: getNodeNumRec(递归),getNodeNum(迭代) + * 2. 求二叉树的深度: getDepthRec(递归),getDepth + * 3. 前序遍历,中序遍历,后序遍历: preorderTraversalRec, preorderTraversal, inorderTraversalRec, postorderTraversalRec + * (https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_2) + * 4.分层遍历二叉树(按层次从上往下,从左往右): levelTraversal, levelTraversalRec(递归解法!) + * 5. 将二叉查找树变为有序的双向链表: convertBST2DLLRec, convertBST2DLL + * 6. 求二叉树第K层的节点个数:getNodeNumKthLevelRec, getNodeNumKthLevel + * + * 7. 求二叉树中叶子节点的个数:getNodeNumLeafRec, getNodeNumLeaf + * 8. 判断两棵二叉树是否相同的树:isSameRec, isSame + * 9. 判断二叉树是不是平衡二叉树:isAVLRec + * 10. 求二叉树的镜像(破坏和不破坏原来的树两种情况):mirrorRec, mirrorCopyRec + * 10.1 判断两个树是否互相镜像:isMirrorRec + * 11. 求二叉树中两个节点的最低公共祖先节点:getLastCommonParent, getLastCommonParentRec, getLastCommonParentRec2 + * 12. 求二叉树中节点的最大距离:getMaxDistanceRec + * 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec + * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec + * 15. 找出二叉树中最长连续子串(即全部往左的连续节点,或是全部往右的连续节点) + * + */ public class TreeDemo { /* @@ -28,7 +53,9 @@ public static void main(String[] args) { / \ 6 14 / \ \ - 4 8 16 + 4 8 16 + / + 0 */ TreeNode r1 = new TreeNode(10); TreeNode r2 = new TreeNode(6); @@ -47,6 +74,8 @@ public static void main(String[] args) { r4.left = r7; + System.out.println(getNodeNumKthLevelRec(r1, 5)); + // System.out.println(getNodeNumRec(null)); // System.out.println(getNodeNum(r1)); // System.out.println(getDepthRec(r1)); @@ -59,7 +88,7 @@ public static void main(String[] args) { // inorderTraversalRec(r1); // // System.out.println(); - inorderTraversal(r1); +// inorderTraversal(r1); // postorderTraversalRec(r1); // System.out.println(); // postorderTraversal(r1); @@ -91,10 +120,10 @@ public static void main(String[] args) { // ret = ret.right; // } - System.out.println(); - System.out.println(findLongest(r1)); - System.out.println(); - System.out.println(findLongest2(r1)); +// System.out.println(); +// System.out.println(findLongest(r1)); +// System.out.println(); +// System.out.println(findLongest2(r1)); } @@ -496,6 +525,98 @@ public static TreeNode convertBST2DLL(TreeNode root) { return root; } + +/* + * * 6. 求二叉树第K层的节点个数:getNodeNumKthLevelRec, getNodeNumKthLevel + * */ + public static int getNodeNumKthLevel(TreeNode root, int k) { + if (root == null || k <= 0) { + return 0; + } + + int level = 0; + + Queue q = new LinkedList(); + q.offer(root); + + TreeNode dummy = new TreeNode(0); + int cnt = 0; // record the size of the level. + + q.offer(dummy); + while (!q.isEmpty()) { + TreeNode node = q.poll(); + + if (node == dummy) { + level++; + if (level == k) { + return cnt; + } + cnt = 0; // reset the cnt; + if (q.isEmpty()) { + break; + } + q.offer(dummy); + continue; + } + + cnt++; + if (node.left != null) { + q.offer(node.left); + } + + if (node.right != null) { + q.offer(node.right); + } + } + + return 0; + } + + /* + * * 6. 求二叉树第K层的节点个数:getNodeNumKthLevelRec, getNodeNumKthLevel + * */ + public static int getNodeNumKthLevelRec(TreeNode root, int k) { + if (root == null || k <= 0) { + return 0; + } + + if (k == 1) { + return 1; + } + + // 将左子树及右子树在K层的节点个数相加. + return getNodeNumKthLevelRec(root.left, k - 1) + getNodeNumKthLevelRec(root.right, k - 1); + } + + /* + * 把左子树和右子树的叶子节点加在一起即可 + * */ + public static int getNodeNumLeafRec(TreeNode root) { + if (root == null) { + return 0; + } + + if (root.left == null && root.right == null) { + return 1; + } + + return getNodeNumLeafRec(root.left) + getNodeNumLeafRec(root.right); + } + + /* + * 把左子树和右子树的叶子节点加在一起即可 + * */ + public static int getNodeNumLeaf(TreeNode root) { + if (root == null) { + return 0; + } + + if (root.left == null && root.right == null) { + return 1; + } + + return getNodeNumLeafRec(root.left) + getNodeNumLeafRec(root.right); + } /* * 第一种解法: From 762dcade3a72bcb8d99c5dd8b1b9015ef98356d5 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 25 Sep 2014 15:26:09 -0700 Subject: [PATCH 04/66] Create README.md --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..b75b1ec --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +LeetCode_algorithm +================== + +About the Tree: +full binary tree: A binary tree in which each node has exactly zero or two children. +Perfect binary tree: A binary tree with all leaf nodes at the same depth. All internal nodes have degree 2 [1] + +The difference between Full Binary Tree & Complete Binary Tree: +(1). a binary tree T is full if each node is either a leaf or possesses exactly two child nodes. +(2). a binary tree T with n levels is complete if all levels except possibly the last are completely full, and the last level has all its +nodes to the left side. [2] + +AVL Trees: AVL trees are self-balancing binary search trees. These trees are named after their two +inventors G.M. Adel’son-Vel’skii and E.M. Landis. [3] + +The height/depth of a tree: +The height of a node is the length of the longest downward path to a leaf from that node. +The height of the root is the height of the tree. The depth of a node is the length of the path to its root (i.e., its root path). +This is commonly needed in the manipulation of the various self-balancing trees, +AVL Trees in particular. The root node has depth zero, leaf nodes have height zero, +and a tree with only a single node (hence both a root and leaf) has depth and height zero. +Conventionally, an empty tree (tree with no nodes, if such are allowed) has depth and height −1. + + +REF: +[1] http://xlinux.nist.gov/dads//HTML/perfectBinaryTree.html +[2] http://courses.cs.vt.edu/~cs3114/Fall09/wmcquain/Notes/T03a.BinaryTreeTheorems. +[3] http://courses.csail.mit.edu/6.006/fall09/lecture_notes/lecture04.pdf From ce3384ea27c30ba7de5d2bc93be4c07b098f89bf Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 25 Sep 2014 15:46:28 -0700 Subject: [PATCH 05/66] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b75b1ec..65aebd8 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,11 @@ The height of the root is the height of the tree. The depth of a node is the len This is commonly needed in the manipulation of the various self-balancing trees, AVL Trees in particular. The root node has depth zero, leaf nodes have height zero, and a tree with only a single node (hence both a root and leaf) has depth and height zero. -Conventionally, an empty tree (tree with no nodes, if such are allowed) has depth and height −1. +Conventionally, an empty tree (tree with no nodes, if such are allowed) has depth and height −1.[4] REF: [1] http://xlinux.nist.gov/dads//HTML/perfectBinaryTree.html [2] http://courses.cs.vt.edu/~cs3114/Fall09/wmcquain/Notes/T03a.BinaryTreeTheorems. [3] http://courses.csail.mit.edu/6.006/fall09/lecture_notes/lecture04.pdf +[4] http://www.cs.cmu.edu/~adamchik/15-121/lectures/Trees/trees.html From 078baa78466003dfde1deff503afd639e29b9334 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 25 Sep 2014 21:08:51 -0700 Subject: [PATCH 06/66] modify the directors --- TreeDemo.java | 455 +++++++++++++++++- .../ReverseLinkedList2.java | 4 +- LCA.java => tree/LCA.java | 4 +- Level_Order.java => tree/Level_Order.java | 4 +- 4 files changed, 442 insertions(+), 25 deletions(-) rename ReverseLinkedList2.java => list/ReverseLinkedList2.java (96%) rename LCA.java => tree/LCA.java (98%) rename Level_Order.java => tree/Level_Order.java (97%) diff --git a/TreeDemo.java b/TreeDemo.java index 8d50afb..02db229 100644 --- a/TreeDemo.java +++ b/TreeDemo.java @@ -5,30 +5,32 @@ import java.util.Queue; import java.util.Stack; -/** - * REF: http://blog.csdn.net/fightforyourdream/article/details/16843303 - * - * http://blog.csdn.net/luckyxiaoqiang/article/details/7518888 轻松搞定面试中的二叉树题目 - * http://www.cnblogs.com/Jax/archive/2009/12/28/1633691.html 算法大全(3) 二叉树 +/** + * REFS: + * http://blog.csdn.net/fightforyourdream/article/details/16843303 面试大总结之二:Java搞定面试中的二叉树题目 + * http://blog.csdn.net/luckyxiaoqiang/article/details/7518888 轻松搞定面试中的二叉树题目 + * http://www.cnblogs.com/Jax/archive/2009/12/28/1633691.html 算法大全(3) 二叉树 * * 1. 求二叉树中的节点个数: getNodeNumRec(递归),getNodeNum(迭代) * 2. 求二叉树的深度: getDepthRec(递归),getDepth * 3. 前序遍历,中序遍历,后序遍历: preorderTraversalRec, preorderTraversal, inorderTraversalRec, postorderTraversalRec * (https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_2) - * 4.分层遍历二叉树(按层次从上往下,从左往右): levelTraversal, levelTraversalRec(递归解法!) + * 4.分层遍历二叉树(按层次从上往下,从左往右): levelTraversal, levelTraversalRec(递归解法) * 5. 将二叉查找树变为有序的双向链表: convertBST2DLLRec, convertBST2DLL * 6. 求二叉树第K层的节点个数:getNodeNumKthLevelRec, getNodeNumKthLevel - * * 7. 求二叉树中叶子节点的个数:getNodeNumLeafRec, getNodeNumLeaf - * 8. 判断两棵二叉树是否相同的树:isSameRec, isSame + * 8. 判断两棵二叉树是否相同的树:isSameRec, isSame * 9. 判断二叉树是不是平衡二叉树:isAVLRec - * 10. 求二叉树的镜像(破坏和不破坏原来的树两种情况):mirrorRec, mirrorCopyRec - * 10.1 判断两个树是否互相镜像:isMirrorRec + * 10. 求二叉树的镜像(破坏和不破坏原来的树两种情况): + * mirrorRec, mirrorCopyRec + * mirror, mirrorCopy + * 10.1 判断两个树是否互相镜像:isMirrorRec isMirror + * * 11. 求二叉树中两个节点的最低公共祖先节点:getLastCommonParent, getLastCommonParentRec, getLastCommonParentRec2 * 12. 求二叉树中节点的最大距离:getMaxDistanceRec * 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec - * 15. 找出二叉树中最长连续子串(即全部往左的连续节点,或是全部往右的连续节点) + * 15. 找出二叉树中最长连续子串(即全部往左的连续节点,或是全部往右的连续节点)findLongest * */ @@ -70,15 +72,53 @@ public static void main(String[] args) { r1.right = r3; r2.left = r4; r2.right = r5; - r3.right = r6; + //r3.right = r6; r4.left = r7; - System.out.println(getNodeNumKthLevelRec(r1, 5)); + TreeNode t1 = new TreeNode(10); + TreeNode t2 = new TreeNode(6); + TreeNode t3 = new TreeNode(14); + TreeNode t4 = new TreeNode(4); + TreeNode t5 = new TreeNode(8); + TreeNode t6 = new TreeNode(16); + + TreeNode t7 = new TreeNode(0); + + t1.left = t2; + t1.right = t3; + t2.left = t4; + t2.right = t5; + t3.right = t6; + + t4.left = t7; + + //System.out.println(isSame(r1, t1)); + + System.out.println(isAVLRec(r1)); + + preorderTraversalRec(r1); + //mirrorRec(r1); + //TreeNode r1Mirror = mirror(r1); + + TreeNode r1MirrorCopy = mirrorCopy(r1); + System.out.println(); + //preorderTraversalRec(r1Mirror); + preorderTraversalRec(r1MirrorCopy); + + System.out.println(); + + System.out.println(isMirrorRec(r1, r1MirrorCopy)); + System.out.println(isMirror(r1, r1MirrorCopy)); + + + //System.out.println(getNodeNumKthLevelRec(r1, 5)); + + //System.out.println(getNodeNumLeaf(r1)); // System.out.println(getNodeNumRec(null)); // System.out.println(getNodeNum(r1)); -// System.out.println(getDepthRec(r1)); + //System.out.println(getDepthRec(null)); // System.out.println(getDepth(r1)); // // preorderTraversalRec(r1); @@ -125,6 +165,7 @@ public static void main(String[] args) { // System.out.println(); // System.out.println(findLongest2(r1)); + } private static class TreeNode{ @@ -180,7 +221,7 @@ public static int getNodeNum(TreeNode root) { public static int getDepthRec(TreeNode root) { if (root == null) { - return 0; + return -1; } return Math.max(getDepthRec(root.left), getDepthRec(root.right)) + 1; @@ -207,7 +248,7 @@ public static int getDepth(TreeNode root) { q.offer(root); q.offer(dummy); - int depth = 0; + int depth = -1; while (!q.isEmpty()) { TreeNode curr = q.poll(); if (curr == dummy) { @@ -589,7 +630,7 @@ public static int getNodeNumKthLevelRec(TreeNode root, int k) { } /* - * 把左子树和右子树的叶子节点加在一起即可 + * 7. getNodeNumLeafRec 把左子树和右子树的叶子节点加在一起即可 * */ public static int getNodeNumLeafRec(TreeNode root) { if (root == null) { @@ -603,22 +644,392 @@ public static int getNodeNumLeafRec(TreeNode root) { return getNodeNumLeafRec(root.left) + getNodeNumLeafRec(root.right); } - /* - * 把左子树和右子树的叶子节点加在一起即可 + /* 7. getNodeNumLeaf + * 随便使用一种遍历方法都可以,比如,中序遍历。 + * inorderTraversal,判断是不是叶子节点。 * */ public static int getNodeNumLeaf(TreeNode root) { if (root == null) { return 0; } - if (root.left == null && root.right == null) { - return 1; + int cnt = 0; + + // we can use inorderTraversal travesal to do it. + Stack s = new Stack(); + TreeNode cur = root; + + while (true) { + while (cur != null) { + s.push(cur); + cur = cur.left; + } + + if (s.isEmpty()) { + break; + } + + // all the left child has been put into the stack, let's deal with the + // current node. + cur = s.pop(); + if (cur.left == null && cur.right == null) { + cnt++; + } + cur = cur.right; } - return getNodeNumLeafRec(root.left) + getNodeNumLeafRec(root.right); + return cnt; + } + + /* + * 8. 判断两棵二叉树是否相同的树。 + * 递归解法: + * (1)如果两棵二叉树都为空,返回真 + * (2)如果两棵二叉树一棵为空,另一棵不为空,返回假 + * (3)如果两棵二叉树都不为空,如果对应的左子树和右子树都同构返回真,其他返回假 + * */ + public static boolean isSameRec(TreeNode r1, TreeNode r2) { + // both are null. + if (r1 == null && r2 == null) { + return true; + } + + // one is null. + if (r1 == null || r2 == null) { + return false; + } + + // 1. the value of the root should be the same; + // 2. the left tree should be the same. + // 3. the right tree should be the same. + return r1.val == r2.val && + isSameRec(r1.left, r2.left) && isSameRec(r1.right, r2.right); + } + + /* + * 8. 判断两棵二叉树是否相同的树。 + * 迭代解法 + * 我们直接用中序遍历来比较就好啦 + * */ + public static boolean isSame(TreeNode r1, TreeNode r2) { + // both are null. + if (r1 == null && r2 == null) { + return true; + } + + // one is null. + if (r1 == null || r2 == null) { + return false; + } + + Stack s1 = new Stack(); + Stack s2 = new Stack(); + + TreeNode cur1 = r1; + TreeNode cur2 = r2; + + while (true) { + while (cur1 != null && cur2 != null) { + s1.push(cur1); + s2.push(cur2); + cur1 = cur1.left; + cur2 = cur2.left; + } + + if (cur1 != null || cur2 != null) { + return false; + } + + if (s1.isEmpty() && s2.isEmpty()) { + break; + } + + cur1 = s1.pop(); + cur2 = s2.pop(); + if (cur1.val != cur2.val) { + return false; + } + + cur1 = cur1.right; + cur2 = cur2.right; + } + + return true; + } + +/* + * + * 9. 判断二叉树是不是平衡二叉树:isAVLRec + * 1. 左子树,右子树的高度差不能超过1 + * 2. 左子树,右子树都是平衡二叉树。 + * + */ + public static boolean isAVLRec(TreeNode root) { + if (root == null) { + return true; + } + + // 左子树,右子树都必须是平衡二叉树。 + if (!isAVLRec(root.left) || !isAVLRec(root.right)) { + return false; + } + + int dif = Math.abs(getDepthRec(root.left) - getDepthRec(root.right)); + if (dif > 1) { + return false; + } + + return true; + } + + /** + * 10. 求二叉树的镜像 递归解法: + * + * (1) 破坏原来的树 + * + * 1 1 + * / \ + * 2 -----> 2 + * \ / + * 3 3 + * */ + public static TreeNode mirrorRec(TreeNode root) { + if (root == null) { + return null; + } + + // 先把左右子树分别镜像,并且交换它们 + TreeNode tmp = root.right; + root.right = mirrorRec(root.left); + root.left = mirrorRec(tmp); + + return root; + } + + /** + * 10. 求二叉树的镜像 Iterator解法: + * + * (1) 破坏原来的树 + * + * 1 1 + * / \ + * 2 -----> 2 + * \ / + * 3 3 + * + * 应该可以使用任何一种Traversal 方法。 + * 我们现在可以试看看使用最简单的前序遍历。 + * */ + public static TreeNode mirror(TreeNode root) { + if (root == null) { + return null; + } + + Stack s = new Stack(); + s.push(root); + + while (!s.isEmpty()) { + TreeNode cur = s.pop(); + + // 交换当前节点的左右节点 + TreeNode tmp = cur.left; + cur.left = cur.right; + cur.right = tmp; + + // traversal 左节点,右节点。 + if (cur.right != null) { + s.push(cur.right); + } + + if (cur.left != null) { + s.push(cur.left); + } + } + + return root; + } + + /** + * 10. 求二叉树的镜像 Iterator解法: + * + * (2) 创建一个新的树 + * + * 1 1 + * / \ + * 2 -----> 2 + * \ / + * 3 3 + * + * 应该可以使用任何一种Traversal 方法。 + * 我们现在可以试看看使用最简单的前序遍历。 + * 前序遍历我们可以立刻把新建好的左右节点创建出来,比较方便 + * */ + public static TreeNode mirrorCopy(TreeNode root) { + if (root == null) { + return null; + } + + Stack s = new Stack(); + Stack sCopy = new Stack(); + s.push(root); + + TreeNode rootCopy = new TreeNode(root.val); + sCopy.push(rootCopy); + + while (!s.isEmpty()) { + TreeNode cur = s.pop(); + TreeNode curCopy = sCopy.pop(); + + // traversal 左节点,右节点。 + if (cur.right != null) { + + // copy 在这里做比较好,因为我们可以容易地找到它的父节点 + TreeNode leftCopy = new TreeNode(cur.right.val); + curCopy.left = leftCopy; + s.push(cur.right); + sCopy.push(curCopy.left); + } + + if (cur.left != null) { + // copy 在这里做比较好,因为我们可以容易地找到它的父节点 + TreeNode rightCopy = new TreeNode(cur.left.val); + curCopy.right = rightCopy; + s.push(cur.left); + sCopy.push(curCopy.right); + } + } + + return rootCopy; + } + + /** + * 10. 求二叉树的镜像 递归解法: + * + * (1) 不破坏原来的树,新建一个树 + * + * 1 1 + * / \ + * 2 -----> 2 + * \ / + * 3 3 + * */ + public static TreeNode mirrorCopyRec(TreeNode root) { + if (root == null) { + return null; + } + + // 先把左右子树分别镜像,并且把它们连接到新建的root节点。 + TreeNode rootCopy = new TreeNode(root.val); + rootCopy.left = mirrorCopyRec(root.right); + rootCopy.right = mirrorCopyRec(root.left); + + return rootCopy; + } + + /* + * 10.1. 判断两个树是否互相镜像 + * (1) 根必须同时为空,或是同时不为空 + * + * 如果根不为空: + * (1).根的值一样 + * (2).r1的左树是r2的右树的镜像 + * (3).r1的右树是r2的左树的镜像 + * */ + public static boolean isMirrorRec(TreeNode r1, TreeNode r2){ + // 如果2个树都是空树 + if (r1 == null && r2 == null) { + return true; + } + + // 如果其中一个为空,则返回false. + if (r1 == null || r2 == null) { + return false; + } + + // If both are not null, they should be: + // 1. have same value for root. + // 2. R1's left tree is the mirror of R2's right tree; + // 3. R2's right tree is the mirror of R1's left tree; + return r1.val == r2.val + && isMirrorRec(r1.left, r2.right) + && isMirrorRec(r1.right, r2.left); } /* + * 10.1. 判断两个树是否互相镜像 Iterator 做法 + * (1) 根必须同时为空,或是同时不为空 + * + * 如果根不为空: + * traversal 整个树,判断它们是不是镜像,每次都按照反向来traversal + * (1). 当前节点的值相等 + * (2). 当前节点的左右节点要镜像, + * 无论是左节点,还是右节点,对应另外一棵树的镜像位置,可以同时为空,或是同时不为空,但是不可以一个为空,一个不为空。 + * */ + public static boolean isMirror(TreeNode r1, TreeNode r2){ + // 如果2个树都是空树 + if (r1 == null && r2 == null) { + return true; + } + + // 如果其中一个为空,则返回false. + if (r1 == null || r2 == null) { + return false; + } + + Stack s1 = new Stack(); + Stack s2 = new Stack(); + + s1.push(r1); + s2.push(r2); + + while (!s1.isEmpty() && !s2.isEmpty()) { + TreeNode cur1 = s1.pop(); + TreeNode cur2 = s2.pop(); + + // 弹出的节点的值必须相等 + if (cur1.val != cur2.val) { + return false; + } + + // tree1的左节点,tree2的右节点,可以同时不为空,也可以同时为空,否则返回false. + TreeNode left1 = cur1.left; + TreeNode right1 = cur1.right; + TreeNode left2 = cur2.left; + TreeNode right2 = cur2.right; + + if (left1 != null && right2 != null) { + s1.push(left1); + s2.push(right2); + } else if (!(left1 == null && right2 == null)) { + return false; + } + + // tree1的左节点,tree2的右节点,可以同时不为空,也可以同时为空,否则返回false. + if (right1 != null && left2 != null) { + s1.push(right1); + s2.push(left2); + } else if (!(right1 == null && left2 == null)) { + return false; + } + } + + return true; + } + + /* + * 11. 求二叉树中两个节点的最低公共祖先节点: + * getLastCommonParent, + * getLastCommonParentRec, + * getLastCommonParentRec2 + * */ + public static TreeNode getLastCommonParentRec(TreeNode root, TreeNode node1, TreeNode node2) { + + + return root; + } + + /* + * 15. findLongest * 第一种解法: * 返回左边最长,右边最长,及左子树最长,右子树最长。 * */ diff --git a/ReverseLinkedList2.java b/list/ReverseLinkedList2.java similarity index 96% rename from ReverseLinkedList2.java rename to list/ReverseLinkedList2.java index 8246c8b..1441333 100644 --- a/ReverseLinkedList2.java +++ b/list/ReverseLinkedList2.java @@ -1,4 +1,6 @@ -package Algorithms; +package Algorithms.list; + +import Algorithms.ListNode; public class ReverseLinkedList2 { public static void main(String[] args) { diff --git a/LCA.java b/tree/LCA.java similarity index 98% rename from LCA.java rename to tree/LCA.java index 199a7eb..3efdc52 100644 --- a/LCA.java +++ b/tree/LCA.java @@ -1,4 +1,6 @@ -package Algorithms; +package Algorithms.tree; + +import Algorithms.TreeNode; /** diff --git a/Level_Order.java b/tree/Level_Order.java similarity index 97% rename from Level_Order.java rename to tree/Level_Order.java index 1ea79b4..04956bf 100644 --- a/Level_Order.java +++ b/tree/Level_Order.java @@ -1,8 +1,10 @@ -package Algorithms; +package Algorithms.tree; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Queue; +import Algorithms.TreeNode; + public class Level_Order { From ab453fcdbfba11cfdb53c7cc65b299ec9b72150a Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 26 Sep 2014 00:53:09 -0700 Subject: [PATCH 07/66] move the folder. --- ThreeSum.java => array/ThreeSum.java | 2 +- ThreeSumN2.java => array/ThreeSumN2.java | 2 +- TwoSum.java => array/TwoSum.java | 2 +- NQueens2.java => dp/NQueens2.java | 2 +- MinCut.java => string/MinCut.java | 2 +- tree/LCA.java | 1 - PostOrder.java => tree/PostOrder.java | 4 +++- 7 files changed, 8 insertions(+), 7 deletions(-) rename ThreeSum.java => array/ThreeSum.java (99%) rename ThreeSumN2.java => array/ThreeSumN2.java (99%) rename TwoSum.java => array/TwoSum.java (95%) rename NQueens2.java => dp/NQueens2.java (98%) rename MinCut.java => string/MinCut.java (97%) rename PostOrder.java => tree/PostOrder.java (97%) diff --git a/ThreeSum.java b/array/ThreeSum.java similarity index 99% rename from ThreeSum.java rename to array/ThreeSum.java index ac4fa2c..d83ed9c 100644 --- a/ThreeSum.java +++ b/array/ThreeSum.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.array; import java.util.ArrayList; import java.util.Arrays; diff --git a/ThreeSumN2.java b/array/ThreeSumN2.java similarity index 99% rename from ThreeSumN2.java rename to array/ThreeSumN2.java index 82c3140..7ecf08e 100644 --- a/ThreeSumN2.java +++ b/array/ThreeSumN2.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.array; import java.util.ArrayList; import java.util.Arrays; diff --git a/TwoSum.java b/array/TwoSum.java similarity index 95% rename from TwoSum.java rename to array/TwoSum.java index 0b5b043..f4afa17 100644 --- a/TwoSum.java +++ b/array/TwoSum.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.array; import java.util.HashMap; diff --git a/NQueens2.java b/dp/NQueens2.java similarity index 98% rename from NQueens2.java rename to dp/NQueens2.java index cb72b58..da4d6d6 100644 --- a/NQueens2.java +++ b/dp/NQueens2.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.dp; import java.util.ArrayList; diff --git a/MinCut.java b/string/MinCut.java similarity index 97% rename from MinCut.java rename to string/MinCut.java index 97c8e3c..3a0910b 100644 --- a/MinCut.java +++ b/string/MinCut.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.string; public class MinCut { public int minCut(String s) { diff --git a/tree/LCA.java b/tree/LCA.java index 3efdc52..ae3d4b0 100644 --- a/tree/LCA.java +++ b/tree/LCA.java @@ -89,7 +89,6 @@ public static void main(String[] strs) { System.out.println(cnt); } - public TreeNode getLCA(TreeNode root, TreeNode node1, TreeNode node2) { cnt++; if (root == null || node1 == root || root == node2) { diff --git a/PostOrder.java b/tree/PostOrder.java similarity index 97% rename from PostOrder.java rename to tree/PostOrder.java index 22ccb70..572956b 100644 --- a/PostOrder.java +++ b/tree/PostOrder.java @@ -1,8 +1,10 @@ -package Algorithms; +package Algorithms.tree; import java.util.ArrayList; import java.util.LinkedList; import java.util.Stack; +import Algorithms.TreeNode; + public class PostOrder { /** From af5edeb6b963360460b97a5297d943b585f049cf Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 26 Sep 2014 01:32:58 -0700 Subject: [PATCH 08/66] modify the tree Demo --- TreeDemo.java | 132 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 100 insertions(+), 32 deletions(-) diff --git a/TreeDemo.java b/TreeDemo.java index 02db229..4726d98 100644 --- a/TreeDemo.java +++ b/TreeDemo.java @@ -43,12 +43,12 @@ public class TreeDemo { 4 5 6 */ public static void main(String[] args) { -// TreeNode r1 = new TreeNode(1); -// TreeNode r2 = new TreeNode(2); -// TreeNode r3 = new TreeNode(3); -// TreeNode r4 = new TreeNode(4); -// TreeNode r5 = new TreeNode(5); -// TreeNode r6 = new TreeNode(6); + TreeNode r1 = new TreeNode(1); + TreeNode r2 = new TreeNode(2); + TreeNode r3 = new TreeNode(3); + TreeNode r4 = new TreeNode(4); + TreeNode r5 = new TreeNode(5); + TreeNode r6 = new TreeNode(6); /* 10 @@ -59,12 +59,12 @@ public static void main(String[] args) { / 0 */ - TreeNode r1 = new TreeNode(10); - TreeNode r2 = new TreeNode(6); - TreeNode r3 = new TreeNode(14); - TreeNode r4 = new TreeNode(4); - TreeNode r5 = new TreeNode(8); - TreeNode r6 = new TreeNode(16); +// TreeNode r1 = new TreeNode(10); +// TreeNode r2 = new TreeNode(6); +// TreeNode r3 = new TreeNode(14); +// TreeNode r4 = new TreeNode(4); +// TreeNode r5 = new TreeNode(8); +// TreeNode r6 = new TreeNode(16); TreeNode r7 = new TreeNode(0); @@ -72,9 +72,21 @@ public static void main(String[] args) { r1.right = r3; r2.left = r4; r2.right = r5; - //r3.right = r6; + r3.right = r6; r4.left = r7; + /* + 1 + / \ + 2 3 + / \ \ + 4 5 6 +*/ + System.out.println(LACRec(r1, r2, r4).val); + System.out.println(LACRec(r1, r2, r6).val); + System.out.println(LACRec(r1, r4, r6).val); + System.out.println(LACRec(r1, r4, r4).val); + System.out.println(LACRec(r1, r3, r6).val); TreeNode t1 = new TreeNode(10); TreeNode t2 = new TreeNode(6); @@ -95,21 +107,21 @@ public static void main(String[] args) { //System.out.println(isSame(r1, t1)); - System.out.println(isAVLRec(r1)); - - preorderTraversalRec(r1); - //mirrorRec(r1); - //TreeNode r1Mirror = mirror(r1); - - TreeNode r1MirrorCopy = mirrorCopy(r1); - System.out.println(); - //preorderTraversalRec(r1Mirror); - preorderTraversalRec(r1MirrorCopy); - - System.out.println(); - - System.out.println(isMirrorRec(r1, r1MirrorCopy)); - System.out.println(isMirror(r1, r1MirrorCopy)); +// System.out.println(isAVLRec(r1)); +// +// preorderTraversalRec(r1); +// //mirrorRec(r1); +// //TreeNode r1Mirror = mirror(r1); +// +// TreeNode r1MirrorCopy = mirrorCopy(r1); +// System.out.println(); +// //preorderTraversalRec(r1Mirror); +// preorderTraversalRec(r1MirrorCopy); +// +// System.out.println(); +// +// System.out.println(isMirrorRec(r1, r1MirrorCopy)); +// System.out.println(isMirror(r1, r1MirrorCopy)); //System.out.println(getNodeNumKthLevelRec(r1, 5)); @@ -1018,13 +1030,69 @@ public static boolean isMirror(TreeNode r1, TreeNode r2){ /* * 11. 求二叉树中两个节点的最低公共祖先节点: - * getLastCommonParent, - * getLastCommonParentRec, - * getLastCommonParentRec2 + * Recursion Version: + * LACRec + * 1. If found in the left tree, return the Ancestor. + * 2. If found in the right tree, return the Ancestor. + * 3. If Didn't find any of the node, return null. + * 4. If found both in the left and the right tree, return the root. + * */ + public static TreeNode LACRec(TreeNode root, TreeNode node1, TreeNode node2) { + if (root == null || node1 == null || node2 == null) { + return null; + } + + // If any of the node is the root, just return the root. + if (root == node1 || root == node2) { + return root; + } + + // if no node is in the node, just recursively find it in LEFT and RIGHT tree. + TreeNode left = LACRec(root.left, node1, node2); + TreeNode right = LACRec(root.right, node1, node2); + + if (left == null) { // If didn't found in the left tree, then just return it from right. + return right; + } else if (right == null) { // Or if didn't found in the right tree, then just return it from the left side. + return left; + } + + // if both right and right found a node, just return the root as the Common Ancestor. + return root; + } + + /* + * 11. 求BST中两个节点的最低公共祖先节点: + * Recursive version: + * LCABst + * + * 1. If found in the left tree, return the Ancestor. + * 2. If found in the right tree, return the Ancestor. + * 3. If Didn't find any of the node, return null. + * 4. If found both in the left and the right tree, return the root. * */ - public static TreeNode getLastCommonParentRec(TreeNode root, TreeNode node1, TreeNode node2) { + public static TreeNode LCABstRec(TreeNode root, TreeNode node1, TreeNode node2) { + if (root == null || node1 == null || node2 == null) { + return null; + } + // If any of the node is the root, just return the root. + if (root == node1 || root == node2) { + return root; + } + + int min = Math.min(node1.val, node2.val); + int max = Math.max(node1.val, node2.val); + + // if the values are smaller than the root value, just search them in the left tree. + if (root.val > max) { + return LCABstRec(root.left, node1, node2); + } else if (root.val < min) { + // if the values are larger than the root value, just search them in the right tree. + return LCABstRec(root.right, node1, node2); + } + // if root is in the middle, just return the root. return root; } From 52407ba8ae344733fff285139f7c361f0c93a195 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 26 Sep 2014 04:00:34 -0700 Subject: [PATCH 09/66] The LCA problem. --- TreeDemo.java | 121 +++++++++++++++++++++++++++----- tree/LCA_Demo.java | 167 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 272 insertions(+), 16 deletions(-) create mode 100644 tree/LCA_Demo.java diff --git a/TreeDemo.java b/TreeDemo.java index 4726d98..96f7789 100644 --- a/TreeDemo.java +++ b/TreeDemo.java @@ -1,10 +1,12 @@ package Algorithms; import java.util.ArrayList; +import java.util.Iterator; import java.util.LinkedList; import java.util.Queue; import java.util.Stack; + /** * REFS: * http://blog.csdn.net/fightforyourdream/article/details/16843303 面试大总结之二:Java搞定面试中的二叉树题目 @@ -25,8 +27,11 @@ * mirrorRec, mirrorCopyRec * mirror, mirrorCopy * 10.1 判断两个树是否互相镜像:isMirrorRec isMirror - * - * 11. 求二叉树中两个节点的最低公共祖先节点:getLastCommonParent, getLastCommonParentRec, getLastCommonParentRec2 + * 11. 求二叉树中两个节点的最低公共祖先节点: + * LAC 求解最小公共祖先, 使用list来存储path. + * LCABstRec 递归求解BST树. + * LCARec 递归算法 . + * * 12. 求二叉树中节点的最大距离:getMaxDistanceRec * 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec @@ -50,7 +55,7 @@ public static void main(String[] args) { TreeNode r5 = new TreeNode(5); TreeNode r6 = new TreeNode(6); -/* +/* 10 / \ 6 14 @@ -59,6 +64,13 @@ public static void main(String[] args) { / 0 */ + /* + 1 + / \ + 2 3 + / \ \ + 4 5 6 +*/ // TreeNode r1 = new TreeNode(10); // TreeNode r2 = new TreeNode(6); // TreeNode r3 = new TreeNode(14); @@ -75,19 +87,7 @@ public static void main(String[] args) { r3.right = r6; r4.left = r7; - /* - 1 - / \ - 2 3 - / \ \ - 4 5 6 -*/ - System.out.println(LACRec(r1, r2, r4).val); - System.out.println(LACRec(r1, r2, r6).val); - System.out.println(LACRec(r1, r4, r6).val); - System.out.println(LACRec(r1, r4, r4).val); - System.out.println(LACRec(r1, r3, r6).val); - + TreeNode t1 = new TreeNode(10); TreeNode t2 = new TreeNode(6); TreeNode t3 = new TreeNode(14); @@ -105,6 +105,28 @@ public static void main(String[] args) { t4.left = t7; + /* + 10 + / \ + 6 14 + / \ \ + 4 8 16 + / + 0 + */ + System.out.println(LCABstRec(t1, t2, t4).val); + System.out.println(LCABstRec(t1, t2, t6).val); + System.out.println(LCABstRec(t1, t4, t6).val); + System.out.println(LCABstRec(t1, t4, t7).val); + System.out.println(LCABstRec(t1, t3, t6).val); + + System.out.println(LCA(t1, t2, t4).val); + System.out.println(LCA(t1, t2, t6).val); + System.out.println(LCA(t1, t4, t6).val); + System.out.println(LCA(t1, t4, t7).val); + System.out.println(LCA(t1, t3, t6).val); + System.out.println(LCA(t1, t6, t6).val); + //System.out.println(isSame(r1, t1)); // System.out.println(isAVLRec(r1)); @@ -1095,6 +1117,73 @@ public static TreeNode LCABstRec(TreeNode root, TreeNode node1, TreeNode node2) // if root is in the middle, just return the root. return root; } + + /* + * 解法1. 记录下path,并且比较之: + * LAC + * http://www.geeksforgeeks.org/lowest-common-ancestor-binary-tree-set-1/ + * */ + public static TreeNode LCA(TreeNode root, TreeNode r1, TreeNode r2) { + // If the nodes have one in the root, just return the root. + if (root == null || r1 == null || r2 == null) { + return null; + } + + ArrayList list1 = new ArrayList(); + ArrayList list2 = new ArrayList(); + + boolean find1 = LCAPath(root, r1, list1); + boolean find2 = LCAPath(root, r2, list2); + + // If didn't find any of the node, just return a null. + if (!find1 || !find2) { + return null; + } + + // 注意: 使用Iterator 对于linkedlist可以提高性能。 + // 所以 统一使用Iterator 来进行操作。 + Iterator iter1 = list1.iterator(); + Iterator iter2 = list2.iterator(); + + TreeNode last = null; + while (iter1.hasNext() && iter2.hasNext()) { + TreeNode tmp1 = iter1.next(); + TreeNode tmp2 = iter2.next(); + + if (tmp1 != tmp2) { + return last; + } + + last = tmp1; + } + + // If never find any node which is different, means Node 1 and Node 2 are the same one. + // so just return the last one. + return last; + } + + public static boolean LCAPath(TreeNode root, TreeNode node, ArrayList path) { + // if didn't find, we should return a empty path. + if (root == null || node == null) { + return false; + } + + // First add the root node. + path.add(root); + + // if the node is in the left side. + if (root != node + && !LCAPath(root.left, node, path) + && !LCAPath(root.right, node, path) + ) { + // Didn't find the node. should remove the node added before. + path.remove(root); + return false; + } + + // found + return true; + } /* * 15. findLongest diff --git a/tree/LCA_Demo.java b/tree/LCA_Demo.java new file mode 100644 index 0000000..e088e0c --- /dev/null +++ b/tree/LCA_Demo.java @@ -0,0 +1,167 @@ +package Algorithms.tree; + + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * REFS: + * http://blog.csdn.net/fightforyourdream/article/details/16843303 面试大总结之二:Java搞定面试中的二叉树题目 + * http://blog.csdn.net/luckyxiaoqiang/article/details/7518888 轻松搞定面试中的二叉树题目 + * http://www.cnblogs.com/Jax/archive/2009/12/28/1633691.html 算法大全(3) 二叉树 + + * 1. 求二叉树中两个节点的最低公共祖先节点: + * LAC 求解最小公共祖先, 使用list来存储path. + * 算法复杂度是:O(n), 这里遍历2次,加一次对最高为H的list的遍历. 并且有O(h)的空间复杂度。 + * LCABstRec 递归求解BST树. + * 算法复杂度: O(logN). + * LCARec 递归算法 . + * 算法复杂度是:O(n) + */ + +public class LCA_Demo { + private static class TreeNode{ + int val; + TreeNode left; + TreeNode right; + public TreeNode(int val){ + this.val = val; + left = null; + right = null; + } + } + /* + * 1. 求二叉树中两个节点的最低公共祖先节点: + * Recursion Version: + * LACRec + * 1. If found in the left tree, return the Ancestor. + * 2. If found in the right tree, return the Ancestor. + * 3. If Didn't find any of the node, return null. + * 4. If found both in the left and the right tree, return the root. + * */ + public static TreeNode LACRec(TreeNode root, TreeNode node1, TreeNode node2) { + if (root == null || node1 == null || node2 == null) { + return null; + } + + // If any of the node is the root, just return the root. + if (root == node1 || root == node2) { + return root; + } + + // if no node is in the node, just recursively find it in LEFT and RIGHT tree. + TreeNode left = LACRec(root.left, node1, node2); + TreeNode right = LACRec(root.right, node1, node2); + + if (left == null) { // If didn't found in the left tree, then just return it from right. + return right; + } else if (right == null) { // Or if didn't found in the right tree, then just return it from the left side. + return left; + } + + // if both right and right found a node, just return the root as the Common Ancestor. + return root; + } + + /* + * 11. 求BST中两个节点的最低公共祖先节点: + * Recursive version: + * LCABst + * + * 1. If found in the left tree, return the Ancestor. + * 2. If found in the right tree, return the Ancestor. + * 3. If Didn't find any of the node, return null. + * 4. If found both in the left and the right tree, return the root. + * */ + public static TreeNode LCABstRec(TreeNode root, TreeNode node1, TreeNode node2) { + if (root == null || node1 == null || node2 == null) { + return null; + } + + // If any of the node is the root, just return the root. + if (root == node1 || root == node2) { + return root; + } + + int min = Math.min(node1.val, node2.val); + int max = Math.max(node1.val, node2.val); + + // if the values are smaller than the root value, just search them in the left tree. + if (root.val > max) { + return LCABstRec(root.left, node1, node2); + } else if (root.val < min) { + // if the values are larger than the root value, just search them in the right tree. + return LCABstRec(root.right, node1, node2); + } + + // if root is in the middle, just return the root. + return root; + } + + /* + * 解法1. 记录下path,并且比较之: + * LAC + * http://www.geeksforgeeks.org/lowest-common-ancestor-binary-tree-set-1/ + * */ + public static TreeNode LCA(TreeNode root, TreeNode r1, TreeNode r2) { + // If the nodes have one in the root, just return the root. + if (root == null || r1 == null || r2 == null) { + return null; + } + + ArrayList list1 = new ArrayList(); + ArrayList list2 = new ArrayList(); + + boolean find1 = LCAPath(root, r1, list1); + boolean find2 = LCAPath(root, r2, list2); + + // If didn't find any of the node, just return a null. + if (!find1 || !find2) { + return null; + } + + // 注意: 使用Iterator 对于linkedlist可以提高性能。 + // 所以 统一使用Iterator 来进行操作。 + Iterator iter1 = list1.iterator(); + Iterator iter2 = list2.iterator(); + + TreeNode last = null; + while (iter1.hasNext() && iter2.hasNext()) { + TreeNode tmp1 = iter1.next(); + TreeNode tmp2 = iter2.next(); + + if (tmp1 != tmp2) { + return last; + } + + last = tmp1; + } + + // If never find any node which is different, means Node 1 and Node 2 are the same one. + // so just return the last one. + return last; + } + + public static boolean LCAPath(TreeNode root, TreeNode node, ArrayList path) { + // if didn't find, we should return a empty path. + if (root == null || node == null) { + return false; + } + + // First add the root node. + path.add(root); + + // if the node is in the left side. + if (root != node + && !LCAPath(root.left, node, path) + && !LCAPath(root.right, node, path) + ) { + // Didn't find the node. should remove the node added before. + path.remove(root); + return false; + } + + // found + return true; + } +} \ No newline at end of file From 7c9819f71d7d77198f8261f5c9b076632420eef8 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 26 Sep 2014 04:04:16 -0700 Subject: [PATCH 10/66] add some comments. --- tree/LCA_Demo.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tree/LCA_Demo.java b/tree/LCA_Demo.java index e088e0c..cb802e8 100644 --- a/tree/LCA_Demo.java +++ b/tree/LCA_Demo.java @@ -7,16 +7,16 @@ /** * REFS: * http://blog.csdn.net/fightforyourdream/article/details/16843303 面试大总结之二:Java搞定面试中的二叉树题目 - * http://blog.csdn.net/luckyxiaoqiang/article/details/7518888 轻松搞定面试中的二叉树题目 - * http://www.cnblogs.com/Jax/archive/2009/12/28/1633691.html 算法大全(3) 二叉树 + * http://blog.csdn.net/luckyxiaoqiang/article/details/7518888 轻松搞定面试中的二叉树题目 + * http://www.cnblogs.com/Jax/archive/2009/12/28/1633691.html 算法大全(3) 二叉树 * 1. 求二叉树中两个节点的最低公共祖先节点: - * LAC 求解最小公共祖先, 使用list来存储path. + * (1) LAC 求解最小公共祖先, 使用list来存储path. * 算法复杂度是:O(n), 这里遍历2次,加一次对最高为H的list的遍历. 并且有O(h)的空间复杂度。 - * LCABstRec 递归求解BST树. - * 算法复杂度: O(logN). - * LCARec 递归算法 . + * (2) LCARec 递归算法 . * 算法复杂度是:O(n) + * (3) LCABstRec 递归求解BST树. + * 算法复杂度: O(logN). */ public class LCA_Demo { From bb3eb2b16829659e4b49bbd17b4f0cc6b82a4691 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sat, 27 Sep 2014 13:21:31 -0700 Subject: [PATCH 11/66] Arrange the code. --- Flatten.java | 2 + InOrderTraversal.java | 2 + IsSymmetric.java | 2 + Max_path_BinaryTree.java | 2 + Populate2.java | 3 + Recover.java | 2 + ZigzagLevelOrder.java | 2 + {string => dp}/MinCut.java | 2 +- sort/QuickSort.java | 149 ++++++++++++++++++++ tree/LCA.java | 1 - tree/Level_Order.java | 2 - tree/PostOrder.java | 93 ------------ TreeDemo.java => tree/TreeDemo.java | 5 +- TreeLinkNode.java => tree/TreeLinkNode.java | 2 +- TreeNode.java => tree/TreeNode.java | 2 +- 15 files changed, 170 insertions(+), 101 deletions(-) rename {string => dp}/MinCut.java (97%) create mode 100644 sort/QuickSort.java delete mode 100644 tree/PostOrder.java rename TreeDemo.java => tree/TreeDemo.java (99%) rename TreeLinkNode.java => tree/TreeLinkNode.java (82%) rename TreeNode.java => tree/TreeNode.java (90%) diff --git a/Flatten.java b/Flatten.java index 06fc2d4..4f4bcf4 100644 --- a/Flatten.java +++ b/Flatten.java @@ -1,6 +1,8 @@ package Algorithms; import java.util.Stack; +import Algorithms.tree.TreeNode; + public class Flatten { diff --git a/InOrderTraversal.java b/InOrderTraversal.java index b365588..6de42e4 100644 --- a/InOrderTraversal.java +++ b/InOrderTraversal.java @@ -2,6 +2,8 @@ import java.util.ArrayList; import java.util.Stack; +import Algorithms.tree.TreeNode; + public class InOrderTraversal { public ArrayList inorderTraversal(TreeNode root) { diff --git a/IsSymmetric.java b/IsSymmetric.java index eb8509f..eee9d5a 100644 --- a/IsSymmetric.java +++ b/IsSymmetric.java @@ -2,6 +2,8 @@ import java.util.ArrayDeque; +import Algorithms.tree.TreeNode; + public class IsSymmetric { public boolean isSymmetric(TreeNode root) { if (root == null) { diff --git a/Max_path_BinaryTree.java b/Max_path_BinaryTree.java index de91cc8..9422213 100644 --- a/Max_path_BinaryTree.java +++ b/Max_path_BinaryTree.java @@ -1,6 +1,8 @@ package Algorithms; import java.util.ArrayList; +import Algorithms.tree.TreeNode; + public class Max_path_BinaryTree { public static void main(String args[]){ diff --git a/Populate2.java b/Populate2.java index de55770..8cf79a9 100644 --- a/Populate2.java +++ b/Populate2.java @@ -1,4 +1,7 @@ package Algorithms; + +import Algorithms.tree.TreeLinkNode; + public class Populate2 { public static void main(String[] args) { TreeLinkNode root = new TreeLinkNode(2); diff --git a/Recover.java b/Recover.java index c185ce5..989ff5a 100644 --- a/Recover.java +++ b/Recover.java @@ -1,5 +1,7 @@ package Algorithms; +import Algorithms.tree.TreeNode; + public class Recover { private TreeNode big = null; private TreeNode small = null; diff --git a/ZigzagLevelOrder.java b/ZigzagLevelOrder.java index 3eca3df..07686f8 100644 --- a/ZigzagLevelOrder.java +++ b/ZigzagLevelOrder.java @@ -4,6 +4,8 @@ import java.util.Queue; import java.util.Stack; +import Algorithms.tree.TreeNode; + public class ZigzagLevelOrder { public ArrayList> zigzagLevelOrder(TreeNode root) { diff --git a/string/MinCut.java b/dp/MinCut.java similarity index 97% rename from string/MinCut.java rename to dp/MinCut.java index 3a0910b..9aaa616 100644 --- a/string/MinCut.java +++ b/dp/MinCut.java @@ -1,4 +1,4 @@ -package Algorithms.string; +package Algorithms.dp; public class MinCut { public int minCut(String s) { diff --git a/sort/QuickSort.java b/sort/QuickSort.java new file mode 100644 index 0000000..7090a41 --- /dev/null +++ b/sort/QuickSort.java @@ -0,0 +1,149 @@ +package Algorithms.sort; + +/********************************************************* + * + * 08-722 Data Structures for Application Programmers + * Lab 5 Comparing MergeSort with QuickSort + * + * A simple QuickSort implementation + * + *********************************************************/ + +import java.util.*; + +public class QuickSort { + //private static final int SIZE = 100000; + private static final int SIZE = 100000; + private static Random rand = new Random(); + + public static void main(String args[]) { + int[] array = new int[SIZE]; + + for (int i = 0; i < SIZE; i++) + array[i] = rand.nextInt(); + + // reversely ordered + /* + for(int i=0;i= right) { + return; + } + + // we just set the right node to be pivot. + int pivPosition = partition(arr, left, right, arr[right]); + + recQuickSort(arr, left, pivPosition - 1); + recQuickSort(arr, pivPosition + 1, right); + } + + // partition the array and return the new pivot position. + private static int partition(int[] arr, int left, int right, int pivot) { + int len = arr.length; + + // set the pivot. + int l = left ; + int r = right - 1; + + /* + example: + let 4 to be the pivot. + + (1) At the beginning: + 2 8 7 1 3 5 6 4 + i j + + + (2) After the first while loop: + 2 8 7 1 3 5 6 4 + i j + + (3) swap them, then continue to move i and j: + 2 3 7 1 8 5 6 4 + i j + + (3) swap them, then continue to move i and j: + 2 3 1 7 8 5 6 4 + j i pivo + + (4) swap the left and the pivo. + 2 3 1 7 8 5 6 4 + j i pivo + + */ + + while (true) { + // Find the first element which does not fullfill the rule + // When l move to the pivot, it will not move again because arr[l] == pivot. + while (arr[l] < pivot) { + l++; + } + + // Find the first element which does not fullfill the rule + while (r > 0 && arr[r] > pivot) { + r--; + } + + // If r <= l, means that all the elements is in the right place. + if (r <= l) { + break; + } + + // Swap the first two elements that does not fit the rule. + swap(arr, r, l); + } + + // The l pointer point to the first element which is bigger than the pvio. + // So we can put the pvio just here. Because put a big one in the last will not change the rule that: + // all the smaller one is in the left and the right one is in the right. + swap(arr, l, right); + + return l; + } + + // private helper method to swap two values in an array + private static void swap(int[] arr, int dex1, int dex2) { + int tmp = arr[dex1]; + arr[dex1] = arr[dex2]; + arr[dex2] = tmp; + } + + /********************************************************** + * Check if array is sorted. A simple debugging tool + **********************************************************/ + private static boolean isSorted(int[] array) { + return isSorted(array, 0, array.length - 1); + } + + private static boolean isSorted(int[] array, int lo, int hi) { + for (int i = lo + 1; i <= hi; i++) + if (array[i] < array[i - 1]) + return false; + return true; + } + +} diff --git a/tree/LCA.java b/tree/LCA.java index ae3d4b0..9119361 100644 --- a/tree/LCA.java +++ b/tree/LCA.java @@ -1,6 +1,5 @@ package Algorithms.tree; -import Algorithms.TreeNode; /** diff --git a/tree/Level_Order.java b/tree/Level_Order.java index 04956bf..b73e3e9 100644 --- a/tree/Level_Order.java +++ b/tree/Level_Order.java @@ -3,8 +3,6 @@ import java.util.ArrayList; import java.util.Queue; -import Algorithms.TreeNode; - public class Level_Order { diff --git a/tree/PostOrder.java b/tree/PostOrder.java deleted file mode 100644 index 572956b..0000000 --- a/tree/PostOrder.java +++ /dev/null @@ -1,93 +0,0 @@ -package Algorithms.tree; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.Stack; - -import Algorithms.TreeNode; - - -public class PostOrder { - /** - * Definition for binary tree - * public class TreeNode { - * int val; - * TreeNode left; - * TreeNode right; - * TreeNode(int x) { val = x; } - * } - */ - public ArrayList postorderTraversal(TreeNode root) { - ArrayList result = new ArrayList(); - - if (root == null) { - return result; - } - - Stack s = new Stack(); - Stack s2 = new Stack(); - - int currval = 0; - //s.push(root); - //s2.push(root.val); - - TreeNode curr = root; - - while (true) { - // store all the right node and the root node. then shift to the left node. - while (curr != null) { - if (curr.right != null) { - // s.push(curr.right); - } - s.push(curr); - s2.push(curr.val); - curr = curr.left; - } - - if (s.isEmpty()) { - return result; - } - - curr = s.pop(); - currval = s2.pop(); - if (curr.right != null && (s.isEmpty() || s.peek() != null)) { - // this is to indicate that this node has been visited, - // when come back from the right branch, we can know that we don't need - // to search right branch again. - s.push(null); - s.push(curr); - s2.push(0); - s2.push(curr.val); - curr = curr.right; - } else { - result.add(curr.val); - if (!s.isEmpty() && s.peek() == null) { - s.pop(); // give up the "null" node. - s2.pop(); - } - - curr = null; - } - } - } - - public static void main(String[] args) { - PostOrder p = new PostOrder(); - - TreeNode root = new TreeNode(1); - - root.left = new TreeNode(2); - root.right = new TreeNode(3); - root.right.right = new TreeNode(6); - - root.left.left = new TreeNode(4); - root.left.right = new TreeNode(5); - - root.left.left.left = new TreeNode(7); - - ArrayList rst = p.postorderTraversal(root); - - System.out.printf(rst.toString()); - - - } -} diff --git a/TreeDemo.java b/tree/TreeDemo.java similarity index 99% rename from TreeDemo.java rename to tree/TreeDemo.java index 96f7789..75cb957 100644 --- a/TreeDemo.java +++ b/tree/TreeDemo.java @@ -1,4 +1,5 @@ -package Algorithms; +@@ -1,1260 +0,0 @@ +package Algorithms.tree; import java.util.ArrayList; import java.util.Iterator; @@ -1257,4 +1258,4 @@ static int[] findLongest2Help(TreeNode root, int[] maxVal) { return ret; } -} \ No newline at end of file +} \ No newline at end of file diff --git a/TreeLinkNode.java b/tree/TreeLinkNode.java similarity index 82% rename from TreeLinkNode.java rename to tree/TreeLinkNode.java index 822615e..d81489c 100644 --- a/TreeLinkNode.java +++ b/tree/TreeLinkNode.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.tree; public class TreeLinkNode { int val; TreeLinkNode left, right, next; diff --git a/TreeNode.java b/tree/TreeNode.java similarity index 90% rename from TreeNode.java rename to tree/TreeNode.java index a7b8af7..9323d13 100644 --- a/TreeNode.java +++ b/tree/TreeNode.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.tree; public class TreeNode { public int val; From fa314c254194aaaca7124d0e31022d2296eb454d Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sun, 28 Sep 2014 13:28:12 -0700 Subject: [PATCH 12/66] merge Sort --- sort/MergeSort.java | 123 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 sort/MergeSort.java diff --git a/sort/MergeSort.java b/sort/MergeSort.java new file mode 100644 index 0000000..e994925 --- /dev/null +++ b/sort/MergeSort.java @@ -0,0 +1,123 @@ +package Algorithms.sort; + +/******************************************************** + * + * 08-722 Data Structures for Application Programmers + * Lecture 14 Advanced Sorting + * + * Naive version of Merge Sort + * + *********************************************************/ +import java.util.Arrays; + +public class MergeSort { + + private static final int SIZE = 10000; + + public static int[] mergeSort(int[] data) { + // parameter valid judge. + if (data == null) { + return null; + } + + // the base case. + int len = data.length; + if (len <= 1) { + return data; + } + + // divide into two arrays. + // create left half and right half. + int left[] = new int[len/2]; + int right[] = new int[len - len/2]; + + System.arraycopy(data, 0, left, 0, len/2); + System.arraycopy(data, len/2, right, 0, len - len/2); + + // call itself to sort left half + left = mergeSort(left); + right = mergeSort(right); + + return merge(left, right); + } + + // Precondition: two input arrays are sorted and they are not null. + private static int[] merge(int[] left, int[] right) { + int len = left.length + right.length; + + int[] ret = new int[len]; + + int leftPoint = 0; + int rightPoint = 0; + + int cur = 0; + while (leftPoint < left.length && rightPoint < right.length) { + if (left[leftPoint] < right[rightPoint]) { + ret[cur++] = left[leftPoint++]; + } else { + ret[cur++] = right[rightPoint++]; + } + } + + if (leftPoint >= left.length) { + while (rightPoint < right.length) { + ret[cur++] = right[rightPoint++]; + } + } else { + while (leftPoint < left.length) { + ret[cur++] = left[leftPoint++]; + } + } + + return ret; + } + + public static void mergeSort2(int[] data) { + // parameter valid judge. + if (data == null) { + return null; + } + + // the base case. + int len = data.length; + if (len <= 1) { + return data; + } + + // divide into two arrays. + // create left half and right half. + int left[] = new int[len/2]; + int right[] = new int[len - len/2]; + + System.arraycopy(data, 0, left, 0, len/2); + System.arraycopy(data, len/2, right, 0, len - len/2); + + // call itself to sort left half + left = mergeSort(left); + right = mergeSort(right); + + return merge(left, right); + } + + public static void main(String[] args) { + int[] a = new int[SIZE]; + for (int i = 0; i < SIZE; i++) + a[i] = (int) (Math.random() * SIZE); + + //mergeSort(a); + + int[] test = { 42, 12, 89, 27, 94, 63, 3, 78 }; + System.out.println(Arrays.toString(mergeSort(test))); + + // test merge method + int[] left = { 12, 42, 63, 89 }; + int[] right = { 3, 27, 78, 94 }; + System.out.println(Arrays.toString(merge(left, right))); + + // test merge method + int[] left2 = {}; + int[] right2 = { 3, 27, 78, 94 }; + System.out.println(Arrays.toString(merge(left2, right2))); + } + +} \ No newline at end of file From 37c41057a5ac94e8d00848675d6174190f7b6982 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 2 Oct 2014 01:23:58 -0700 Subject: [PATCH 13/66] merge --- sort/MergeSort.java | 27 ---------- tree/TreeDemo.java | 126 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 112 insertions(+), 41 deletions(-) diff --git a/sort/MergeSort.java b/sort/MergeSort.java index e994925..053da1e 100644 --- a/sort/MergeSort.java +++ b/sort/MergeSort.java @@ -72,33 +72,6 @@ private static int[] merge(int[] left, int[] right) { return ret; } - public static void mergeSort2(int[] data) { - // parameter valid judge. - if (data == null) { - return null; - } - - // the base case. - int len = data.length; - if (len <= 1) { - return data; - } - - // divide into two arrays. - // create left half and right half. - int left[] = new int[len/2]; - int right[] = new int[len - len/2]; - - System.arraycopy(data, 0, left, 0, len/2); - System.arraycopy(data, len/2, right, 0, len - len/2); - - // call itself to sort left half - left = mergeSort(left); - right = mergeSort(right); - - return merge(left, right); - } - public static void main(String[] args) { int[] a = new int[SIZE]; for (int i = 0; i < SIZE; i++) diff --git a/tree/TreeDemo.java b/tree/TreeDemo.java index 75cb957..dcaf513 100644 --- a/tree/TreeDemo.java +++ b/tree/TreeDemo.java @@ -1,9 +1,9 @@ -@@ -1,1260 +0,0 @@ package Algorithms.tree; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; +import java.util.List; import java.util.Queue; import java.util.Stack; @@ -32,8 +32,8 @@ * LAC 求解最小公共祖先, 使用list来存储path. * LCABstRec 递归求解BST树. * LCARec 递归算法 . - * * 12. 求二叉树中节点的最大距离:getMaxDistanceRec + * * 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec * 15. 找出二叉树中最长连续子串(即全部往左的连续节点,或是全部往右的连续节点)findLongest @@ -98,6 +98,12 @@ public static void main(String[] args) { TreeNode t7 = new TreeNode(0); + TreeNode t8 = new TreeNode(0); + TreeNode t9 = new TreeNode(0); + TreeNode t10 = new TreeNode(0); + TreeNode t11 = new TreeNode(0); + + t1.left = t2; t1.right = t3; t2.left = t4; @@ -106,6 +112,12 @@ public static void main(String[] args) { t4.left = t7; + // test distance + t5.right = t8; + t8.right = t9; + t9.right = t10; + t10.right = t11; + /* 10 / \ @@ -115,18 +127,20 @@ public static void main(String[] args) { / 0 */ - System.out.println(LCABstRec(t1, t2, t4).val); - System.out.println(LCABstRec(t1, t2, t6).val); - System.out.println(LCABstRec(t1, t4, t6).val); - System.out.println(LCABstRec(t1, t4, t7).val); - System.out.println(LCABstRec(t1, t3, t6).val); - - System.out.println(LCA(t1, t2, t4).val); - System.out.println(LCA(t1, t2, t6).val); - System.out.println(LCA(t1, t4, t6).val); - System.out.println(LCA(t1, t4, t7).val); - System.out.println(LCA(t1, t3, t6).val); - System.out.println(LCA(t1, t6, t6).val); +// System.out.println(LCABstRec(t1, t2, t4).val); +// System.out.println(LCABstRec(t1, t2, t6).val); +// System.out.println(LCABstRec(t1, t4, t6).val); +// System.out.println(LCABstRec(t1, t4, t7).val); +// System.out.println(LCABstRec(t1, t3, t6).val); +// +// System.out.println(LCA(t1, t2, t4).val); +// System.out.println(LCA(t1, t2, t6).val); +// System.out.println(LCA(t1, t4, t6).val); +// System.out.println(LCA(t1, t4, t7).val); +// System.out.println(LCA(t1, t3, t6).val); +// System.out.println(LCA(t1, t6, t6).val); + + System.out.println(getMaxDistanceRec(t1)); //System.out.println(isSame(r1, t1)); @@ -1185,6 +1199,90 @@ public static boolean LCAPath(TreeNode root, TreeNode node, ArrayList // found return true; } + + /* + * * 12. 求二叉树中节点的最大距离:getMaxDistanceRec + * + * 首先我们来定义这个距离: + * 距离定义为:两个节点间边的数目. + * 如: + * 1 + * / \ + * 2 3 + * \ + * 4 + * 这里最大距离定义为2,4的距离,为3. + * 求二叉树中节点的最大距离 即二叉树中相距最远的两个节点之间的距离。 (distance / diameter) + * 递归解法: + * 返回值设计: + * 返回1. 深度, 2. 当前树的最长距离 + * (1) 计算左子树的深度,右子树深度,左子树独立的链条长度,右子树独立的链条长度 + * (2) 最大长度为三者之最: + * a. 通过根节点的链,为左右深度+2 + * b. 左子树独立链 + * c. 右子树独立链。 + * + * (3)递归初始条件: + * 当root == null, depth = -1.maxDistance = -1; + * + */ + public static int getMaxDistanceRec(TreeNode root) { + return getMaxDistanceRecHelp(root).maxDistance; + } + + public static Result getMaxDistanceRecHelp(TreeNode root) { + Result ret = new Result(-1, -1); + + if (root == null) { + return ret; + } + + Result left = getMaxDistanceRecHelp(root.left); + Result right = getMaxDistanceRecHelp(root.right); + + // 深度应加1, the depth from the subtree to the root. + ret.depth = Math.max(left.depth, right.depth) + 1; + + // 左子树,右子树与根的距离都要加1,所以通过根节点的路径为两边深度+2 + int crossLen = left.depth + right.depth + 2; + + // 求出cross根的路径,及左右子树的独立路径,这三者路径的最大值。 + ret.maxDistance = Math.max(left.maxDistance, right.maxDistance); + ret.maxDistance = Math.max(ret.maxDistance, crossLen); + + return ret; + } + + + private static class Result { + int depth; + int maxDistance; + public Result(int depth, int maxDistance) { + this.depth = depth; + this.maxDistance = maxDistance; + } + } + + /* + * 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec + * */ + public static TreeNode rebuildBinaryTreeRec(List preOrder, List inOrder) { + if (preOrder == null || inOrder == null) { + return null; + } + + // If the traversal is empty, just return a NULL. + if (preOrder.size() == 0 || inOrder.size() == 0) { + return null; + } + + // we can get the root from the preOrder. Because the first one is the + // root. + TreeNode root = preOrder.get(0); + + return null; + + } /* * 15. findLongest From b0e4e32cf5128522a9907c991fcf373d3ef0a76a Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 2 Oct 2014 01:58:32 -0700 Subject: [PATCH 14/66] Five Chessman --- dfs/FiveChessman.java | 143 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 dfs/FiveChessman.java diff --git a/dfs/FiveChessman.java b/dfs/FiveChessman.java new file mode 100644 index 0000000..35a0355 --- /dev/null +++ b/dfs/FiveChessman.java @@ -0,0 +1,143 @@ +package Algorithms.dfs; + +/* + * 输入一个19*19的矩阵,只包含数字0、1、2,表示两人下五子棋的棋牌状态,1、2分别表示两人的棋子,0表示空格。 + * 要求判断当前状态下是否有人获胜(横向、竖向或者斜线方向连成5个同色棋子)。题目说明输入样例保证每条线上至多 + * 只有连续5个同色棋子,并且保证至多只有1人获胜。如果有人获胜,输出获胜者(1或2)加一个冒号, + * 接着输出获胜的五连珠的第一个棋子的坐标,从上到下从左到右序号最小的为第一个,序号从1开始编号。如果无人获胜,输出no。 + * */ +public class FiveChessman { + private static class Coordinate { + int col; + int row; + + public Coordinate (int col, int row) { + this.col = col; + this.row = row; + } + } + + public static class Visit { + boolean right; + boolean down; + boolean rightDown; + boolean leftDown; + + public Visit (boolean right, boolean down, boolean rightDown, boolean leftDown) { + this.right = right; + this.down = down; + this.rightDown = rightDown; + this.leftDown = leftDown; + } + } + + public static void main(String[] args) { + int[][] input = { + {1, 0, 0, 0, 1, 0}, + {0, 1, 0, 1, 0, 2}, + {0, 0, 1, 0, 2, 0}, + {0, 1, 0, 2, 0, 0}, + {0, 0, 2, 0, 1, 0}, + {0, 2, 0, 0, 0, 0} + }; + + Coordinate result = findWin(input); + if (result != null) { + System.out.println("" + result.row + " " + result.col); + } + + } + + // in 代表棋盘 + public static Coordinate findWin(int[][] in) { + if (in == null || in.length == 0) { + return null; + } + + int row = in.length; + int col = in[0].length; + + Visit[][] visit = new Visit[row][col]; + + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + // try to get the result from 4 directions. + for (int k = 0; k < 4; k++) { + visit[i][j] = new Visit(false, false, false, false); + Coordinate ret = findWinHelp(in, j, i, in[i][j], k, visit, 0); + if (ret != null) { + return ret; + } + } + } + } + + return null; + } + + // row, col 代表我们现在正在扫描的点的坐标 + public static Coordinate findWinHelp(int[][] in, int col, int row, int side, int direction, Visit[][] visit, int num) { + // 扫描不可以超过范围 + if (col >= in.length || row >= in.length || row < 0 || col < 0) { + return null; + } + + // if it is 0, just return. + if (in[row][col] == 0) { + return null; + } + + if (side != in[row][col]) { + return null; + } + + // we get the result. + if (num == 4) { + return new Coordinate(col, row); + } + + if (visit[row][col] == null) { + visit[row][col] = new Visit(false, false, false, false); + } + + if (direction == 0) { + if (visit[row][col].right) { + return null; + } + visit[row][col].right = true; + + // right + return findWinHelp(in, col + 1, row, side, direction, visit, num + 1); + } else if (direction == 1) { + if (visit[row][col].down) { + return null; + } + + visit[row][col].down = true; + + // down + return findWinHelp(in, col, row + 1, side, direction, visit, num + 1); + } else if (direction == 2) { + if (visit[row][col].rightDown) { + return null; + } + + + visit[row][col].rightDown = true; + + // right down + return findWinHelp(in, col + 1, row + 1, side, direction, visit, num + 1); + } else if (direction == 3) { + if (visit[row][col].leftDown) { + return null; + } + + visit[row][col].leftDown = true; + + // left down + return findWinHelp(in, col - 1, row + 1, side, direction, visit, num + 1); + } + + return null; + } +} From 441dba7dce3a0455c7e1d35654edf916773ab449 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 2 Oct 2014 02:12:28 -0700 Subject: [PATCH 15/66] FiveChessman --- dfs/FiveChessman.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dfs/FiveChessman.java b/dfs/FiveChessman.java index 35a0355..d4f8ad2 100644 --- a/dfs/FiveChessman.java +++ b/dfs/FiveChessman.java @@ -122,7 +122,6 @@ public static Coordinate findWinHelp(int[][] in, int col, int row, int side, int return null; } - visit[row][col].rightDown = true; // right down From 2eec8247b274f9d2cc973197ab0158c45490e8f7 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 2 Oct 2014 02:35:23 -0700 Subject: [PATCH 16/66] notes --- dfs/FiveChessman.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dfs/FiveChessman.java b/dfs/FiveChessman.java index d4f8ad2..9e0c33f 100644 --- a/dfs/FiveChessman.java +++ b/dfs/FiveChessman.java @@ -76,6 +76,9 @@ public static Coordinate findWin(int[][] in) { } // row, col 代表我们现在正在扫描的点的坐标 + // side 记录目前是哪一方的棋子 + // direction 记录扫描方向,有四个方向扫描:右,右下,左下,下。 + // num: 代表扫描到第几个棋子了。 public static Coordinate findWinHelp(int[][] in, int col, int row, int side, int direction, Visit[][] visit, int num) { // 扫描不可以超过范围 if (col >= in.length || row >= in.length || row < 0 || col < 0) { @@ -87,6 +90,7 @@ public static Coordinate findWinHelp(int[][] in, int col, int row, int side, int return null; } + // 必须是同边的棋子。例如,都是1,或都是2. if (side != in[row][col]) { return null; } @@ -96,10 +100,12 @@ public static Coordinate findWinHelp(int[][] in, int col, int row, int side, int return new Coordinate(col, row); } + // 如果未设置标记,新建标记。 if (visit[row][col] == null) { visit[row][col] = new Visit(false, false, false, false); } + // 对各个方向进行不同的搜索方向。 if (direction == 0) { if (visit[row][col].right) { return null; From 1551e7f95a26328bb8be765803b2b818767e613f Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 2 Oct 2014 13:44:09 -0700 Subject: [PATCH 17/66] the largest Common subtree --- tree/LargestCommonSubtrees.java | 177 ++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 tree/LargestCommonSubtrees.java diff --git a/tree/LargestCommonSubtrees.java b/tree/LargestCommonSubtrees.java new file mode 100644 index 0000000..d366db8 --- /dev/null +++ b/tree/LargestCommonSubtrees.java @@ -0,0 +1,177 @@ +package Algorithms.tree; + +import java.util.*; + + +public class LargestCommonSubtrees { + /* + * Function: Find all the common subtrees root that have most number + */ + private static class TreeNode { + int val; + ArrayList subNodes; + public TreeNode(int val, ArrayList subNodes) { + this.val = val; + this.subNodes = subNodes; + } + } + + public static void main(String[] args) { + /* + * 1 + * + * / \ \ + * 2 3 4 + * / \ / \ + * 5 6 8 9 + * \ \ + * 7 10 + * */ + TreeNode r1 = new TreeNode(1, new ArrayList()); + TreeNode r2 = new TreeNode(2, new ArrayList()); + TreeNode r3 = new TreeNode(3, new ArrayList()); + TreeNode r4 = new TreeNode(4, new ArrayList()); + TreeNode r5 = new TreeNode(5, new ArrayList()); + TreeNode r6 = new TreeNode(6, new ArrayList()); + TreeNode r7 = new TreeNode(7, new ArrayList()); + TreeNode r8 = new TreeNode(8, new ArrayList()); + TreeNode r9 = new TreeNode(9, new ArrayList()); + TreeNode r10 = new TreeNode(10, new ArrayList()); + + r1.subNodes.add(r2); + r1.subNodes.add(r3); + r1.subNodes.add(r4); + + r2.subNodes.add(r5); + r2.subNodes.add(r6); + + r6.subNodes.add(r7); + + r4.subNodes.add(r8); + r4.subNodes.add(r9); + + r9.subNodes.add(r10); + + ArrayList> ret = largestCommonSubtrees(r1); + for (ArrayList arrayl: ret) { + for (TreeNode t: arrayl) { + System.out.println(t.val); + } + } + + } + + public static ArrayList> largestCommonSubtrees(TreeNode root) { + if (root == null) { + return null; + } + + ArrayList> ret = new ArrayList>(); + + // store all the tree nodes to a arrayList. + ArrayList nodes = new ArrayList(); + traversalTree(root, nodes); + + int maxNum = 0; + + HashMap hash = new HashMap(); + + TreeNode r1 = null; + TreeNode r2 = null; + + + // compare all the nodes. + int size = nodes.size(); + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + if (i == j) { + continue; + } + int num = compareTree(nodes.get(i), nodes.get(j), hash); + if (num > maxNum) { + ArrayList iden = new ArrayList(); + iden.add(nodes.get(i)); + iden.add(nodes.get(j)); + + ret.add(iden); + r1 = nodes.get(i); + r2 = nodes.get(j); + } + } + } + + ArrayList> retNew = new ArrayList>(); + retNew.add(new ArrayList()); + retNew.get(0).add(r1); + retNew.get(0).add(r2); + return retNew; + } + + + // compare two tree, if same, return the number of leafs. if no, return -1; + public static int compareTree(TreeNode r1, TreeNode r2, HashMap hash) { + if (r1 == null && r2 == null) { + return 0; + } + + if (r1 == null || r2 == null) { + return -1; + } + + // the number of subtrees should be same. + if (r1.subNodes.size() != r2.subNodes.size()) { + return -1; + } + + int num = 1; // the root itself. + + for (int i = 0; i < r1.subNodes.size(); i++) { + // get the subNode of r1. + TreeNode subNode1 = r1.subNodes.get(i); + TreeNode subNode2 = r2.subNodes.get(i); + + int HashCode = hashCode(subNode1, subNode2); + + Integer numNode = hash.get(HashCode); + if (numNode == null) { + numNode = compareTree(subNode1, subNode2, hash); + } + + if (numNode == -1) { + // not the same, should return; + num = -1; + break; + } else { + num += numNode; + continue; + } + } + + int hashCodeRoot = hashCode(r1, r2); + hash.put(hashCodeRoot, num); + + return num; + } + + public static int hashCode(TreeNode r1, TreeNode r2) { + int hash = r1.hashCode() * 31 + r2.hashCode(); + return hash; + } + + public static void traversalTree(TreeNode root, ArrayList ret) { + if (root == null) { + return; + } + + ret.add(root); + + // add all the sub nodes. + if (root.subNodes != null) { + for(TreeNode t: root.subNodes) { + traversalTree(t, ret); + } + } + } + + +} \ No newline at end of file From 61e79b2770d90e1b18a5585101d9109f71a584a9 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 2 Oct 2014 13:47:46 -0700 Subject: [PATCH 18/66] the largest common --- tree/LargestCommonSubtrees.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tree/LargestCommonSubtrees.java b/tree/LargestCommonSubtrees.java index d366db8..6376a55 100644 --- a/tree/LargestCommonSubtrees.java +++ b/tree/LargestCommonSubtrees.java @@ -89,6 +89,7 @@ public static ArrayList> largestCommonSubtrees(TreeNode root } int num = compareTree(nodes.get(i), nodes.get(j), hash); if (num > maxNum) { + maxNum = num; ArrayList iden = new ArrayList(); iden.add(nodes.get(i)); iden.add(nodes.get(j)); From ff798aeb1a6152c8ba16958d64c5651bee7907bc Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 2 Oct 2014 13:51:46 -0700 Subject: [PATCH 19/66] largestCommon --- tree/LargestCommonSubtrees.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tree/LargestCommonSubtrees.java b/tree/LargestCommonSubtrees.java index 6376a55..2011e94 100644 --- a/tree/LargestCommonSubtrees.java +++ b/tree/LargestCommonSubtrees.java @@ -66,8 +66,6 @@ public static ArrayList> largestCommonSubtrees(TreeNode root return null; } - ArrayList> ret = new ArrayList>(); - // store all the tree nodes to a arrayList. ArrayList nodes = new ArrayList(); traversalTree(root, nodes); @@ -90,11 +88,6 @@ public static ArrayList> largestCommonSubtrees(TreeNode root int num = compareTree(nodes.get(i), nodes.get(j), hash); if (num > maxNum) { maxNum = num; - ArrayList iden = new ArrayList(); - iden.add(nodes.get(i)); - iden.add(nodes.get(j)); - - ret.add(iden); r1 = nodes.get(i); r2 = nodes.get(j); } From 718698dc9e5462d91c0399fed355dedac70d4751 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sat, 4 Oct 2014 20:32:43 -0700 Subject: [PATCH 20/66] TestPermutation --- permutation/Permutation.java | 92 +++++++++++++++++++ permutation/Stopwatch.java | 22 +++++ tree/TreeDemo.java | 166 +++++++++++++++++++++++++++++++++-- 3 files changed, 271 insertions(+), 9 deletions(-) create mode 100644 permutation/Permutation.java create mode 100644 permutation/Stopwatch.java diff --git a/permutation/Permutation.java b/permutation/Permutation.java new file mode 100644 index 0000000..dfbd401 --- /dev/null +++ b/permutation/Permutation.java @@ -0,0 +1,92 @@ +package Algorithms.permutation; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; + +public class Permutation { + public static void main(String[] strs) { + int[] num = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + System.out.printf("Test size:%d \n", num.length); + + Stopwatch timer1 = new Stopwatch(); + + permute(num); + System.out + .println("Computing time with ArrayDeque used as Queue/Deque: " + + timer1.elapsedTime() + " millisec."); + + System.out.printf("Test size:%d \n", num.length); + + Stopwatch timer2 = new Stopwatch(); + + permute2(num); + System.out + .println("Computing time with ArrayDeque used as Queue/Deque: " + + timer2.elapsedTime() + " millisec."); + } + + public static ArrayList> permute(int[] num) { + ArrayList> ret = new ArrayList>(); + if (num == null) { + return ret; + } + + permuteHelp(num, ret, new LinkedHashMap()); + return ret; + } + + public static void permuteHelp(int[] num, ArrayList> ret, LinkedHashMap set) { + if (set.size() == num.length) { + + ArrayList list = new ArrayList(); + for (Integer i: set.keySet()){ + list.add(i); + } + ret.add(list); + return; + } + + int len = num.length; + for (int i = 0; i < len; i++) { + if (set.containsKey(num[i])) { + continue; + } + + //path.add(num[i]); + set.put(num[i], 0); + permuteHelp(num, ret, set); + //path.remove(path.size() - 1); + set.remove(num[i]); + } + } + + public static ArrayList> permute2(int[] num) { + ArrayList> ret = new ArrayList>(); + if (num == null) { + return ret; + } + + ArrayList path = new ArrayList(); + permuteHelp2(num, path, ret); + return ret; + } + + public static void permuteHelp2(int[] num, ArrayList path, ArrayList> ret) { + if (path.size() == num.length) { + ret.add(new ArrayList(path)); + return; + } + + int len = num.length; + for (int i = 0; i < len; i++) { + if (path.contains(num[i])) { + continue; + } + + path.add(num[i]); + permuteHelp2(num, path, ret); + path.remove(path.size() - 1); + } + } +} diff --git a/permutation/Stopwatch.java b/permutation/Stopwatch.java new file mode 100644 index 0000000..3d95f47 --- /dev/null +++ b/permutation/Stopwatch.java @@ -0,0 +1,22 @@ +package Algorithms.permutation; + +/***************************************** + * Stopwatch class to be used as a timer + *****************************************/ + +public class Stopwatch { + + + private final long start; + + public Stopwatch() { + start = System.currentTimeMillis(); + } + + // return time (in milliseconds) since this object was created + public double elapsedTime() { + long now = System.currentTimeMillis(); + return now - start; + } + +} \ No newline at end of file diff --git a/tree/TreeDemo.java b/tree/TreeDemo.java index dcaf513..8d019e0 100644 --- a/tree/TreeDemo.java +++ b/tree/TreeDemo.java @@ -33,9 +33,9 @@ * LCABstRec 递归求解BST树. * LCARec 递归算法 . * 12. 求二叉树中节点的最大距离:getMaxDistanceRec - * - * 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec - * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec + * 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec + * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec + * * 15. 找出二叉树中最长连续子串(即全部往左的连续节点,或是全部往右的连续节点)findLongest * */ @@ -214,7 +214,35 @@ public static void main(String[] args) { // System.out.println(); // System.out.println(findLongest2(r1)); - + // test the rebuildBinaryTreeRec. + test_rebuildBinaryTreeRec(); + } + + public static void test_rebuildBinaryTreeRec() { + ArrayList list1 = new ArrayList(); + list1.add(1); + list1.add(2); + list1.add(4); + list1.add(5); + list1.add(3); + list1.add(6); + list1.add(7); + list1.add(8); + + ArrayList list2 = new ArrayList(); + list2.add(4); + list2.add(2); + list2.add(5); + list2.add(1); + list2.add(3); + list2.add(7); + list2.add(6); + list2.add(8); + + TreeNode root = rebuildBinaryTreeRec(list1, list2); + preorderTraversalRec(root); + System.out.println(); + postorderTraversalRec(root); } private static class TreeNode{ @@ -1265,7 +1293,21 @@ public Result(int depth, int maxDistance) { /* * 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec - * */ + * We assume that there is no duplicate in the trees. + * For example: + * 1 + * / \ + * 2 3 + * /\ \ + * 4 5 6 + * /\ + * 7 8 + * + * PreOrder should be: 1 2 4 5 3 6 7 8 + * 根 左子树 右子树 + * InOrder should be: 4 2 5 1 3 7 6 8 + * 左子树 根 右子树 + * */ public static TreeNode rebuildBinaryTreeRec(List preOrder, List inOrder) { if (preOrder == null || inOrder == null) { return null; @@ -1276,12 +1318,118 @@ public static TreeNode rebuildBinaryTreeRec(List preOrder, List preOrderLeft; + List preOrderRight; + List inOrderLeft; + List inOrderRight; + // 获得在 inOrder中,根的位置 + int rootInIndex = inOrder.indexOf(preOrder.get(0)); + preOrderLeft = preOrder.subList(1, rootInIndex + 1); + preOrderRight = preOrder.subList(rootInIndex + 1, preOrder.size()); + + // 得到inOrder左边的左子树 + inOrderLeft = inOrder.subList(0, rootInIndex); + inOrderRight = inOrder.subList(rootInIndex + 1, inOrder.size()); + + // 通过 Rec 来调用生成左右子树。 + root.left = rebuildBinaryTreeRec(preOrderLeft, inOrderLeft); + root.right = rebuildBinaryTreeRec(preOrderRight, inOrderRight); + + return root; + } + + /* + * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec + * + * */ + + public static boolean isCompleteBinaryTree(TreeNode root) { + return false; + } + + /* + * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTreeRec + * + * + * 我们可以分解为: + * CompleteBinary Tree 的条件是: + * 1. 左右子树均为Perfect binary tree, 并且两者Height相同 + * 2. 左子树为CompleteBinaryTree, 右子树为Perfect binary tree,并且两者Height差1 + * 3. 左子树为Perfect Binary Tree,右子树为CompleteBinaryTree, 并且Height 相同 + * + * Base 条件: + * (1) root = null: 为perfect & complete BinaryTree, Height -1; + * + * 而 Perfect Binary Tree的条件: + * 左右子树均为Perfect Binary Tree,并且Height 相同。 + * */ + + public static boolean isCompleteBinaryTreeRec(TreeNode root) { + return isCompleteBinaryTreeRecHelp(root).isCompleteBT; + } + + private static class ReturnBinaryTree { + boolean isCompleteBT; + boolean isPerfectBT; + int height; + + ReturnBinaryTree(boolean isCompleteBT, boolean isPerfectBT, int height) { + this.isCompleteBT = isCompleteBT; + this.isPerfectBT = isPerfectBT; + this.height = height; + } + } + + /* + * 我们可以分解为: + * CompleteBinary Tree 的条件是: + * 1. 左右子树均为Perfect binary tree, 并且两者Height相同 + * 2. 左子树为CompleteBinaryTree, 右子树为Perfect binary tree,并且两者Height差1 + * 3. 左子树为Perfect Binary Tree,右子树为CompleteBinaryTree, 并且Height 相同 + * + * Base 条件: + * (1) root = null: 为perfect & complete BinaryTree, Height -1; + * + * 而 Perfect Binary Tree的条件: + * 左右子树均为Perfect Binary Tree,并且Height 相同。 + * */ + public static ReturnBinaryTree isCompleteBinaryTreeRecHelp(TreeNode root) { + ReturnBinaryTree ret = new ReturnBinaryTree(true, true, -1); + + if (root == null) { + return ret; + } + + ReturnBinaryTree left = isCompleteBinaryTreeRecHelp(root.left); + ReturnBinaryTree right = isCompleteBinaryTreeRecHelp(root.right); + + // 树的高度为左树高度,右树高度的最大值+1 + ret.height = 1 + Math.max(left.height, right.height); + + // set the isPerfectBT + ret.isPerfectBT = false; + if (left.isPerfectBT && right.isPerfectBT && left.height == right.height) { + ret.isPerfectBT = true; + } + + // set the isCompleteBT. + /* + * CompleteBinary Tree 的条件是: + * 1. 左右子树均为Perfect binary tree, 并且两者Height相同(其实就是本树是perfect tree) + * 2. 左子树为CompleteBinaryTree, 右子树为Perfect binary tree,并且两者Height差1 + * 3. 左子树为Perfect Binary Tree,右子树为CompleteBinaryTree, 并且Height 相同 + * */ + ret.isCompleteBT = ret.isPerfectBT + || (left.isCompleteBT && right.isPerfectBT && left.height == right.height + 1) + || (left.isPerfectBT && right.isCompleteBT && left.height == right.height); + + return ret; } /* From 7d60ff42f618c4a69179164045e69454163ea97b Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sat, 4 Oct 2014 22:20:09 -0700 Subject: [PATCH 21/66] isCompleteBinaryTree --- tree/TreeDemo.java | 75 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 10 deletions(-) diff --git a/tree/TreeDemo.java b/tree/TreeDemo.java index 8d019e0..882b477 100644 --- a/tree/TreeDemo.java +++ b/tree/TreeDemo.java @@ -108,15 +108,19 @@ public static void main(String[] args) { t1.right = t3; t2.left = t4; t2.right = t5; - t3.right = t6; + t3.left = t6; + t3.right = t7; + + t4.left = t8; + //t4.right = t9; + t5.right = t9; - t4.left = t7; // test distance - t5.right = t8; - t8.right = t9; - t9.right = t10; - t10.right = t11; +// t5.right = t8; +// t8.right = t9; +// t9.right = t10; +// t10.right = t11; /* 10 @@ -140,7 +144,7 @@ public static void main(String[] args) { // System.out.println(LCA(t1, t3, t6).val); // System.out.println(LCA(t1, t6, t6).val); - System.out.println(getMaxDistanceRec(t1)); + //System.out.println(getMaxDistanceRec(t1)); //System.out.println(isSame(r1, t1)); @@ -215,7 +219,10 @@ public static void main(String[] args) { // System.out.println(findLongest2(r1)); // test the rebuildBinaryTreeRec. - test_rebuildBinaryTreeRec(); + //test_rebuildBinaryTreeRec(); + + System.out.println(isCompleteBinaryTreeRec(t1)); + System.out.println(isCompleteBinaryTree(t1)); } public static void test_rebuildBinaryTreeRec() { @@ -1346,11 +1353,59 @@ public static TreeNode rebuildBinaryTreeRec(List preOrder, List q = new LinkedList(); + + q.offer(root); + q.offer(dummyNode); + + // if this is true, no node should have any child. + boolean noChild = false; + + while (!q.isEmpty()) { + TreeNode cur = q.poll(); + if (cur == dummyNode) { + if (!q.isEmpty()) { + q.offer(dummyNode); + } + // Dummy node不需要处理。 + continue; + } + + if (cur.left != null) { + // 如果标记被设置,则Queue中任何元素不应再有子元素。 + if (noChild) { + return false; + } + q.offer(cur.left); + } else { + // 一旦某元素没有左节点或是右节点,则之后所有的元素都不应有子元素。 + // 并且该元素不可以有右节点. + noChild = true; + } + + if (cur.right != null) { + // 如果标记被设置,则Queue中任何元素不应再有子元素。 + if (noChild) { + return false; + } + q.offer(cur.right); + } else { + // 一旦某元素没有左节点或是右节点,则之后所有的元素都不应有子元素。 + noChild = true; + } + } + + return true; } /* From c73a8a77b50c85d6fb5bbc64b02b139550db3216 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sun, 5 Oct 2014 03:19:24 -0700 Subject: [PATCH 22/66] NextPermutation --- permutation/NextPermutation.java | 55 ++++++++++++++++++++++++++++++++ tree/TreeDemo.java | 2 -- 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 permutation/NextPermutation.java diff --git a/permutation/NextPermutation.java b/permutation/NextPermutation.java new file mode 100644 index 0000000..e8acbed --- /dev/null +++ b/permutation/NextPermutation.java @@ -0,0 +1,55 @@ +package Algorithms.permutation; + +public class NextPermutation { + public void nextPermutation(int[] num) { + // There should be at least 2 digitals. + if (num == null || num.length <= 1) { + return; + } + + int len = num.length; + + // From the tail to find the first digital which drop + // example: 1 2 4321 + // i + int i = len - 2; + for (; i >= 0; i--) { + if (num[i] < num[i + 1]) { + break; + } + } + + // example: 1 2 4321 + // i j + // then swap i and j. + // Find the first digital which is bigger than the digital just found. + // swap: 1 3 4221 + // if i == -1, it means that it should be like: 432, 从尾部往前,没有下降的情况 + if (i != -1) { + for (int j = len - 1; j > i; j--) { + if (num[j] > num[i]) { + swap(num, i, j); + break; + } + } + } + + + // than just make the 4221 to reverse. + // result: 1 3 1224 + int left = i + 1; + int right = len - 1; + while (left < right) { + swap(num, left, right); + left++; + right--; + } + } + + // swap the i, j element in the array. + public void swap(int[] num, int i, int j) { + int tmp = num[i]; + num[i] = num[j]; + num[j] = tmp; + } +} diff --git a/tree/TreeDemo.java b/tree/TreeDemo.java index 882b477..8931467 100644 --- a/tree/TreeDemo.java +++ b/tree/TreeDemo.java @@ -35,9 +35,7 @@ * 12. 求二叉树中节点的最大距离:getMaxDistanceRec * 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec - * * 15. 找出二叉树中最长连续子串(即全部往左的连续节点,或是全部往右的连续节点)findLongest - * */ public class TreeDemo { From 8c9f0e8c6eb486448d889228af1936c2f3528e2d Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sun, 5 Oct 2014 04:21:02 -0700 Subject: [PATCH 23/66] permutation sequence --- permutation/PermutationSequence.java | 69 ++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 permutation/PermutationSequence.java diff --git a/permutation/PermutationSequence.java b/permutation/PermutationSequence.java new file mode 100644 index 0000000..22d5833 --- /dev/null +++ b/permutation/PermutationSequence.java @@ -0,0 +1,69 @@ +package Algorithms.permutation; + +/* + The set [1,2,3,…,n] contains a total of n! unique permutations. + +By listing and labeling all of the permutations in order, +We get the following sequence (ie, for n = 3): + + "123" + "132" + "213" + "231" + "312" + "321" + +Given n and k, return the kth permutation sequence. + +Note: Given n will be between 1 and 9 inclusive. + * */ +public class PermutationSequence { + public static String getPermutation(int n, int k) { + if (n == 0) { + return ""; + } + + // 先计算出(n)! + int num = 1; + for (int i = 1; i <= n; i++) { + num *= i; + } + + boolean[] use = new boolean[n]; + for (int i = 0; i < n; i++) { + use[i] = false; + } + + // 因为index是从0开始计算 + k--; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < n; i++) { + // 计算完第一个数字前,num要除以(n) + num = num / (n - i); + + int index = k / num; + k = k % num; + + for (int j = 0; j < n; j++) { + if (!use[j]) { + if (index == 0) { + // 记录下本次的结果. + sb.append((j + 1) + ""); + use[j] = true; + break; + } + + // 遇到未使用过的数字,记录index + index--; + } + } + } + + return sb.toString(); + } + + public static void main(String[] args) { + System.out.println(getPermutation(3, 5)); + } + +} From b8c8f5fbfd241cf949e7b346947e5b87e22cf138 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sun, 5 Oct 2014 16:46:07 -0700 Subject: [PATCH 24/66] Fibonacci --- dp/Fibonacci.java | 69 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 dp/Fibonacci.java diff --git a/dp/Fibonacci.java b/dp/Fibonacci.java new file mode 100644 index 0000000..1c00e40 --- /dev/null +++ b/dp/Fibonacci.java @@ -0,0 +1,69 @@ +package Algorithms.dp; + +import java.util.ArrayList; + +/************************************************************************* + * Compilation: javac Fibonacci.java + * Execution: java Fibonacci N + * + * Computes and prints the first N Fibonacci numbers. + * + * WARNING: this program is spectacularly inefficient and is meant + * to illustrate a performance bug, e.g., set N = 45. + * + * + * % java Fibonacci 7 + * 1: 1 + * 2: 1 + * 3: 2 + * 4: 3 + * 5: 5 + * 6: 8 + * 7: 13 + * + * Remarks + * ------- + * - The 93rd Fibonacci number would overflow a long, but this + * will take so long to compute with this function that we + * don't bother to check for overflow. + * + *************************************************************************/ +public class Fibonacci { + public static long fib(int n) { + //System.out.println("Enter rec once."); + + if (n <= 2) { + return 1; + } + + return fib(n - 1) + fib(n - 2); + } + + public static ArrayList fibDp(int n) { + ArrayList ret = new ArrayList(); + + // We use the arrayList to store the result to avoid multiply count. + for (int i = 0; i < n; i++) { + if (i <= 1) { + ret.add(1); + } else { + ret.add(ret.get(i - 1) + ret.get(i - 2)); + } + } + + return ret; + } + + public static void main(String[] args) { + int N = 5; + + System.out.print(fib(5) + " "); +// for (int i = 1; i <= N; i++) { +// System.out.print(fib(i) + " "); +// } + + ArrayList list = fibDp(500); + System.out.println(list.toString()); + } + +} From 92f4168c0ae2fade27ce21caed29b03a6d5a05c8 Mon Sep 17 00:00:00 2001 From: piggy Date: Tue, 7 Oct 2014 01:22:12 -0700 Subject: [PATCH 25/66] add new file --- tree/sortedListToBST.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tree/sortedListToBST.java diff --git a/tree/sortedListToBST.java b/tree/sortedListToBST.java new file mode 100644 index 0000000..e69de29 From f928b91b615a05af515f4028a4d7359ae8811b72 Mon Sep 17 00:00:00 2001 From: piggy Date: Tue, 7 Oct 2014 01:46:30 -0700 Subject: [PATCH 26/66] add code. --- tree/sortedListToBST.java | 102 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/tree/sortedListToBST.java b/tree/sortedListToBST.java index e69de29..eaac151 100644 --- a/tree/sortedListToBST.java +++ b/tree/sortedListToBST.java @@ -0,0 +1,102 @@ +/** + * Definition for singly-linked list. + * public class ListNode {h + * int val; + * ListNode next; + * ListNode(int x) { val = x; next = null; } + * } + */ +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class Solution { + public TreeNode sortedListToBST1(ListNode head) { + ListNode fast = head; + ListNode slow = head; + + ListNode pre = head; + + if (head == null) { + return null; + } + + TreeNode root = null; + if (head.next == null) { + root = new TreeNode(head.val); + root.left = null; + root.right = null; + return root; + } + + // get the middle node. + while (fast != null && fast.next != null) { + fast = fast.next.next; + + // record the node before the SLOW. + pre = slow; + slow = slow.next; + } + + // cut the list to two parts. + pre.next = null; + TreeNode left = sortedListToBST1(head); + TreeNode right = sortedListToBST1(slow.next); + + root = new TreeNode(slow.val); + root.left = left; + root.right = right; + + return root; + } + + public TreeNode sortedListToBST(ListNode head) { + if (head == null) { + return null; + } + + int size = 0; + ListNode cur = head; + while (cur != null) { + size++; + cur = cur.next; + } + + CurrNode curNode = new CurrNode(head); + return sortedListToBSTHelp(curNode, size); + } + + public class CurrNode { + ListNode node; + + CurrNode(ListNode node) { + this.node = node; + } + } + + // when the recursion is done, the curr node should point to the node + // which is the next of the block. + public TreeNode sortedListToBSTHelp(CurrNode curr, int size) { + if (size <= 0) { + return null; + } + + TreeNode left = sortedListToBSTHelp(curr, size/2); + + // because we want to deal with the right block. + TreeNode root = new TreeNode(curr.node.val); + curr.node = curr.node.next; + + TreeNode right = sortedListToBSTHelp(curr, size - 1 - size/2); + + root.left = left; + root.right = right; + + return root; + } +} From b6817a69218e9897dbdd4342243b03408ebdde90 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Tue, 7 Oct 2014 19:38:05 -0700 Subject: [PATCH 27/66] Recover Binary Search Tree --- tree/IsSymmetric_LeetCode.java | 112 +++++++++++++++++++++++++++++++++ tree/RecoverTree.java | 70 +++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 tree/IsSymmetric_LeetCode.java create mode 100644 tree/RecoverTree.java diff --git a/tree/IsSymmetric_LeetCode.java b/tree/IsSymmetric_LeetCode.java new file mode 100644 index 0000000..d52a3db --- /dev/null +++ b/tree/IsSymmetric_LeetCode.java @@ -0,0 +1,112 @@ +package Algorithms.tree; + +import java.util.Stack; + +public class IsSymmetric_LeetCode { + /* + * Given a binary tree, check whether it is a mirror of itself (ie, + * symmetric around its center). + * + * For example, this binary tree is symmetric: + * + * 1 / \ 2 2 / \ / \ 3 4 4 3 + * + * But the following is not: + * + * 1 / \ 2 2 \ \ 3 3 + * + * Note: Bonus points if you could solve it both recursively and + * iteratively. + * + * confused what "{1,#,2,3}" means? > read more on how binary tree is + * serialized on OJ. + * + * OJ's Binary Tree Serialization: + * + * The serialization of a binary tree follows a level order traversal, where + * '#' signifies a path terminator where no node exists below. + * + * Here's an example: + * + * 1 / \ 2 3 / 4 \ 5 + * + * The above binary tree is serialized as "{1,2,3,#,#,4,#,#,5}". + */ + // + public boolean isSymmetric(TreeNode root) { + if (root == null) { + return true; + } + + return isMirrorRec(root.left, root.right); + } + + /* + * 判断两个树是否互相镜像 + * (1) 根必须同时为空,或是同时不为空 + * + * 如果根不为空: + * (1).根的值一样 + * (2).r1的左树是r2的右树的镜像 + * (3).r1的右树是r2的左树的镜像 + */ + public boolean isMirrorRec(TreeNode r1, TreeNode r2) { + if (r1 == null && r2 == null) { + return true; + } + + if (r1 == null || r2 == null) { + return false; + } + + // should compare the value of the root. remember this. + return r1.val == r2.val + && isMirrorRec(r1.left, r2.right) + && isMirrorRec(r1.right, r2.left); + } + + public boolean isMirror(TreeNode r1, TreeNode r2) { + if (r1 == null && r2 == null) { + return true; + } + + if (r1 == null || r2 == null) { + return false; + } + + // We can do preOrder traverse to judge if the trees are mirror. + Stack s1 = new Stack(); + Stack s2 = new Stack(); + s1.push(r1); + s2.push(r2); + + while (!s1.isEmpty() && !s2.isEmpty()) { + // pop the current node out. + TreeNode cur1 = s1.pop(); + TreeNode cur2 = s2.pop(); + + // Judge if the value of the node is equal. + if (cur1.val != cur2.val) { + return false; + } + + // tree1的左节点,tree2的右节点,可以同时不为空,也可以同时为空,否则返回false. + if (cur1.left != null && cur2.right != null) { + s1.push(cur1.left); + s2.push(cur2.right); + } else if (!(cur1.left == null && cur2.right == null)) { + return false; + } + + // tree1的右节点,tree2的左节点,可以同时不为空,也可以同时为空,否则返回false. + if (cur1.right != null && cur2.left != null) { + s1.push(cur1.right); + s2.push(cur2.left); + } else if (!(cur1.right == null && cur2.left == null)) { + return false; + } + } + + return true; + } +} diff --git a/tree/RecoverTree.java b/tree/RecoverTree.java new file mode 100644 index 0000000..87348ee --- /dev/null +++ b/tree/RecoverTree.java @@ -0,0 +1,70 @@ +package Algorithms.tree; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class RecoverTree { + TreeNode pre = null; + TreeNode first = null; + TreeNode second = null; + + + public void recoverTree(TreeNode root) { + inOrder(root); + + // swap the value of first and second node. + int tmp = first.val; + first.val = second.val; + second.val = tmp; + } + + public void inOrder(TreeNode root) { + if (root == null) { + return; + } + + // inorder traverse. + inOrder(root.left); + + /* + Find the place which the order is wrong. + For example: 1 3 4 6 7 8 10 13 14 + Wrong order: 1 3 8 6 7 4 10 13 14 + FIND: ___ + Then we find: ___ + 8, 6 是错误的序列, 但是,7,4也是错误的序列。 + 因为8,6前面的序列是正确的,所以8,6一定是后面的序列交换来的。 + 而后面的是比较大的数字,也就是说8一定是被交换过来的。而7,4 + 中也应该是小的数字4是前面交换过来的。 + + 用反证法来证明: + 假设:6是后面交换过来的 + 推论: 那么8比6还大,那么8应该也是后面交换来的, + 这样起码有3个错误的数字了 + 而题目是2个错误的数字,得证,只应该是8是交换过来的。 + */ + + // 判断 pre 是否已经设置 + if (pre != null && pre.val > root.val) { + if (first == null) { + // 首次找到反序. + first = pre; + second = root; + } else { + // 第二次找到反序,更新Second. + second = root; + } + } + + pre = root; + + // inorder traverse. + inOrder(root.right); + } +} From a758230b044d1924d4159962bb8897826befe07e Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Tue, 7 Oct 2014 20:16:16 -0700 Subject: [PATCH 28/66] isValidBST --- tree/IsValidBST.java | 59 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 tree/IsValidBST.java diff --git a/tree/IsValidBST.java b/tree/IsValidBST.java new file mode 100644 index 0000000..7d47f60 --- /dev/null +++ b/tree/IsValidBST.java @@ -0,0 +1,59 @@ +package Algorithms.tree; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class IsValidBST { + public boolean isValidBST(TreeNode root) { + return isValidBSTHelp(root).isValidBST; + } + + public ReturnType isValidBSTHelp(TreeNode root) { + ReturnType ret = new ReturnType(Integer.MAX_VALUE, Integer.MIN_VALUE, true); + if (root == null) { + return ret; + } + + ReturnType left = isValidBSTHelp(root.left); + ReturnType right = isValidBSTHelp(root.right); + + /* the left tree and the right tree should both be Valid BST. + And the value of the root should be in the middle. + */ + + if (!left.isValidBST + || !right.isValidBST + || left.max >= root.val + || right.min <= root.val + ) { + ret.isValidBST = false; + return ret; + } + + // get the min value of the tree; + ret.min = Math.min(left.min, root.val); + + // get the max value of the tree, consider the right node may be null; + ret.max = Math.max(right.max, root.val); + + return ret; + } + + public class ReturnType { + int min; + int max; + boolean isValidBST; + + ReturnType(int min, int max, boolean isValidBST) { + this.min = min; + this.max = max; + this.isValidBST = isValidBST; + } + } +} \ No newline at end of file From c04d0094c36499bacaf63964d972f89bd3ac9abd Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Tue, 7 Oct 2014 21:04:44 -0700 Subject: [PATCH 29/66] in order --- tree/InorderTraversal.java | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 tree/InorderTraversal.java diff --git a/tree/InorderTraversal.java b/tree/InorderTraversal.java new file mode 100644 index 0000000..9774325 --- /dev/null +++ b/tree/InorderTraversal.java @@ -0,0 +1,76 @@ +package Algorithms.tree; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + + +public class InorderTraversal { + public static List inorderTraversal(TreeNode root) { + ArrayList ret = new ArrayList(); + inorderTraversal(root, ret); + return ret; + } + + public static void inorderTraversalRec(TreeNode root, ArrayList ret) { + if (root == null) { + return; + } + + inorderTraversalRec(root.left, ret); + + ret.add(root.val); + + inorderTraversalRec(root.right, ret); + } + + public static void inorderTraversal(TreeNode root, ArrayList ret) { + if (root == null) { + return; + } + + TreeNode cur = root; + Stack s = new Stack(); + + while (true) { + // 因为是inorder,所以要一直先处理左节点,所以我们必须找到最最左边这一个节点, + // 否则是不处理的,也就是一直压栈。 + while (cur != null) { + s.push(cur); + cur = cur.left; + } + + // 如果栈空,表明没有任何需要处理的元素了. + if (s.isEmpty()) { + break; + } + + /* + * 1 + * / \ + * 2 6 + * / \ + * 3 5 + * / + * 4 + * + * 例如:1, 2, 3, 4会入栈。 + * 4,3,2陆续弹出 + * + * 然后会转向2的右节点,5. 5处理完后,会继续弹栈,也就是1. + * 最后处理6. + * + * */ + + // 因为所有的左节点全部已经加入栈中了,开始处理栈顶的元素, + // 或者是右子树是空的,那么弹出一个之前的节点来处理 + cur = s.pop(); + + // 处理当前节点(左节点与根节点 ) + ret.add(cur.val); + + // 处理了左节点与根节点,再处理右子树。 + cur = cur.right; + } + } +} From 32923195d6590ebf18d3871f61a425f57ab61d66 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Tue, 7 Oct 2014 22:10:02 -0700 Subject: [PATCH 30/66] tree --- tree/NumTrees.java | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tree/NumTrees.java diff --git a/tree/NumTrees.java b/tree/NumTrees.java new file mode 100644 index 0000000..5f9e245 --- /dev/null +++ b/tree/NumTrees.java @@ -0,0 +1,29 @@ +package Algorithms.tree; + +public class NumTrees { + public int numTrees(int n) { + // cnt[n] = cnt[0]cnt[n - 1] + cnt[1]cnt[n - 2] ... cnt[n - 1]cnt[0] + // cnt[n-1] = cnt[0]cnt[n - 2] + cnt[1]cnt[n - 3] ... cnt[n - 2]cnt[0] + // For example: + // when N = 3, + // cnt[3] = cnt[0]cnt[2] + cnt[1]cnt[1] + cnt[2]cnt[1]; + // so the Formula is : + + // F[n] = ∑ Cnt[j] * cnt[n-j-1] 0<=j<=n-1 + + // base case: + // when n = 0, cnt[0] = 1; + + int[] cnt = new int[n + 1]; + cnt[0] = 1; + + for (int i = 1 ; i <= n; i++) { + cnt[i] = 0; + for (int j = 0; j <= i - 1; j++) { + cnt[i] += cnt[j] * cnt[i - j - 1]; + } + } + + return cnt[n]; + } +} From 8f28a485082dba8fb3b03c079160bac7f973765b Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Tue, 7 Oct 2014 22:10:46 -0700 Subject: [PATCH 31/66] tree --- tree/NumTrees.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tree/NumTrees.java b/tree/NumTrees.java index 5f9e245..4f45028 100644 --- a/tree/NumTrees.java +++ b/tree/NumTrees.java @@ -1,7 +1,7 @@ package Algorithms.tree; public class NumTrees { - public int numTrees(int n) { + public int numTrees1(int n) { // cnt[n] = cnt[0]cnt[n - 1] + cnt[1]cnt[n - 2] ... cnt[n - 1]cnt[0] // cnt[n-1] = cnt[0]cnt[n - 2] + cnt[1]cnt[n - 3] ... cnt[n - 2]cnt[0] // For example: @@ -26,4 +26,19 @@ public int numTrees(int n) { return cnt[n]; } -} + + public int numTrees(int n) { + if (n == 0) { + return 1; + } + + // Get the results of all the trees which + // has the root from 1 to n; + int num = 0; + for (int i = 0; i <= n - 1; i++) { + num += numTrees(i) * numTrees(n - 1 - i); + } + + return num; + } +} \ No newline at end of file From 2d0cf85ad815e84a91d919a6c644261c66be1e10 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Wed, 8 Oct 2014 00:44:24 -0700 Subject: [PATCH 32/66] minDepth --- tree/MinDepth.java | 108 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 tree/MinDepth.java diff --git a/tree/MinDepth.java b/tree/MinDepth.java new file mode 100644 index 0000000..dc1aeb7 --- /dev/null +++ b/tree/MinDepth.java @@ -0,0 +1,108 @@ +package Algorithms.tree; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class MinDepth { + public int minDepth(TreeNode root) { + if (root == null) { + return 0; + } + + return minDepthHelp(root); + } + + /* + * The Recursion Version1: + * */ + public int minDepthRec(TreeNode root) { + if (root == null) { + return 0; + } + + //if there is not left tree, just consider the right tree. + if (root.left == null) { + return minDepthRec(root.right) + 1; + + //if there is not right tree, just consider the left tree. + } else if (root.right == null) { + return minDepthRec(root.left) + 1; + } + + return Math.min(minDepthRec(root.right), minDepthRec(root.left)) + 1; + } + + /* + * The Recursion Version2: + * 这种递归解法更简单。因为在本层递归中不需要考虑左右子树是否为NULL的情况。因为我们直接 + 把 null 设置为返回一个最大值,这样的话,如果出现空子树,它不会影响最小值。但是如果左 + 右均为空,则应返回1(即是仅仅为根节点) + * */ + public int minDepthHelp(TreeNode root) { + if (root == null) { + return Integer.MAX_VALUE; + } + + int min = Math.min(minDepthHelp(root.left), minDepthHelp(root.right)); + if (min == Integer.MAX_VALUE) { + return 1; + } + return min + 1; + } + + /* + * The Iteration Version: + * */ + public int minDepthHelpIterator(TreeNode root) { + if (root == null) { + return 0; + } + + TreeNode dummy = new TreeNode(0); + Queue q = new LinkedList(); + + q.offer(root); + q.offer(dummy); + + //如果一开始就退出,则起码是有根节点。 + int depth = 1; + + while (!q.isEmpty()) { + TreeNode cur = q.poll(); + if (cur == dummy) { + //if queue is not empty, just add a new dummy to the end to sign a new line. + if (!q.isEmpty()) { + q.offer(dummy); + } + //don't deal with the dummynode. + depth++; + continue; + } + + if (cur.left != null) { + q.offer(cur.left); + } + + if (cur.right != null) { + q.offer(cur.right); + } + + //this is a leaf node. + if (cur.left == null && cur.right == null) { + return depth; + } + } + + return 0; + } + +} \ No newline at end of file From dc15508d7673a47fb8583e4b780445825368a392 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Wed, 8 Oct 2014 10:52:01 -0700 Subject: [PATCH 33/66] min --- tree/MinDepth.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tree/MinDepth.java b/tree/MinDepth.java index dc1aeb7..b929e2e 100644 --- a/tree/MinDepth.java +++ b/tree/MinDepth.java @@ -46,17 +46,21 @@ public int minDepthRec(TreeNode root) { * 这种递归解法更简单。因为在本层递归中不需要考虑左右子树是否为NULL的情况。因为我们直接 把 null 设置为返回一个最大值,这样的话,如果出现空子树,它不会影响最小值。但是如果左 右均为空,则应返回1(即是仅仅为根节点) + + 而且这种做法更加合理。 因为如果是空树,应该是无法到达才是。这时就应该将值设置为最大。 * */ public int minDepthHelp(TreeNode root) { if (root == null) { return Integer.MAX_VALUE; } - int min = Math.min(minDepthHelp(root.left), minDepthHelp(root.right)); - if (min == Integer.MAX_VALUE) { + // 如果root是叶子节点,直接就可以退出咯。 + if (root.left == null && root.right == null) { return 1; } - return min + 1; + + // root不是叶子节点,输出左右子树的最小值,再加上root本身 + return 1 + Math.min(minDepthHelp(root.left), minDepthHelp(root.right)); } /* From de48d998f6e210e340fdf6d7eecca41cd2ac5e9d Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Wed, 8 Oct 2014 14:58:12 -0700 Subject: [PATCH 34/66] facebook --- facebook/SortWeight.java | 115 +++++++++++++++++++++++++++++++++++++++ tree/MinDepth.java | 2 +- 2 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 facebook/SortWeight.java diff --git a/facebook/SortWeight.java b/facebook/SortWeight.java new file mode 100644 index 0000000..779f466 --- /dev/null +++ b/facebook/SortWeight.java @@ -0,0 +1,115 @@ +package Algorithms.facebook; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; + +public class SortWeight { + public static void main(String[] args) { + String input1 = "crab hotdog 9.0 chicken 9.2 pig 9.2"; + String input2 = "pizza 1 hotdog 2.0"; + String input3 = "pizza 500 hotdog 2.0"; + String input4 = "pizza 500 2.0"; + + LinkedList list1 = sortWeight(input1); + LinkedList list2 = sortWeight(input2); + LinkedList list3 = sortWeight(input3); + LinkedList list4 = sortWeight(input4); + + System.out.println(list1.toString()); + System.out.println(list2.toString()); + System.out.println(list3.toString()); + System.out.println(list4.toString()); + } + + public static LinkedList sortWeight(String input) { + LinkedList ret = new LinkedList(); + if (input == null) { + return ret; + } + + String[] strs = input.split(" "); + + float defautWeight = 5; + + // 当weight = -1,表示这一组食物-重量链还未完成 + String food = null; + float weight = 0; + + // 记录某重量下所有的食物 + HashMap> map = new HashMap>(); + + // Go through the string. + for (String s: strs) { + // 上一次的food-weight对已经结束 + if (weight != -1) { + food = s; + weight = -1; + } else { + float tmp = stringToNumber(s); + // This is a float, so just add a food to the list. + if (tmp != -1) { + weight = tmp; + addFoodToMap(map, food, weight); + } else { + // This is not a float, means that there should be + // a new food. + addFoodToMap(map, food, defautWeight); + + // 开始新一轮的食物-重量链 + food = s; + weight = -1; + } + } + } + + //System.out.println(map.toString()); + + if (weight == -1) { + addFoodToMap(map, food, defautWeight); + } + + ArrayList array = new ArrayList(map.keySet()); + Collections.sort(array); + + for (Float w: array) { + ArrayList foods = map.get(w); + for (String element: foods) { + ret.addFirst(element); + } + } + + return ret; + } + + public static void addFoodToMap(HashMap> map, String food, + float weight) { + // 把上一次的食物-重量终结 + ArrayList list = map.get(weight); + if (list != null) { + // 在相应的重量下添加食物 + list.add(food); + } else { + // 新建一个重量链 + ArrayList listNew = new ArrayList(); + listNew.add(food); + map.put(weight, listNew); + } + } + + // when it is not a float, return -1; + public static float stringToNumber(String cur) { + float result = -1; + + try { + result = Float.parseFloat(cur); + } catch (NumberFormatException e) { + result = -1; + } + + return result; + } +} diff --git a/tree/MinDepth.java b/tree/MinDepth.java index b929e2e..ad0afbc 100644 --- a/tree/MinDepth.java +++ b/tree/MinDepth.java @@ -47,7 +47,7 @@ public int minDepthRec(TreeNode root) { 把 null 设置为返回一个最大值,这样的话,如果出现空子树,它不会影响最小值。但是如果左 右均为空,则应返回1(即是仅仅为根节点) - 而且这种做法更加合理。 因为如果是空树,应该是无法到达才是。这时就应该将值设置为最大。 + 而且这种做法更加合理。 因为如果是空树,应该是无法到达才是。这时就应该将值设置为最大。 * */ public int minDepthHelp(TreeNode root) { if (root == null) { From 72f914daab2fd9e2eb8a63e4643297d78d4fadaa Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Wed, 8 Oct 2014 20:29:37 -0700 Subject: [PATCH 35/66] Unique BSTs --- tree/GenerateTree2.java | 70 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 tree/GenerateTree2.java diff --git a/tree/GenerateTree2.java b/tree/GenerateTree2.java new file mode 100644 index 0000000..16eb9ed --- /dev/null +++ b/tree/GenerateTree2.java @@ -0,0 +1,70 @@ +package Algorithms.tree; + +import java.util.ArrayList; +import java.util.List; +/* + * Given n, generate all structurally unique BST's (binary search trees) that store values 1...n. + +For example, +Given n = 3, your program should return all 5 unique BST's shown below. + + 1 3 3 2 1 + \ / / / \ \ + 3 2 1 1 3 2 + / / \ \ + 2 1 2 3 +confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ. + * */ + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; left = null; right = null; } + * } + */ +public class GenerateTree2 { + public List generateTrees(int n) { + return generateTreesHelp(1, n); + } + + /* + 使用递归来完成,我们可以分解为2个步骤: + 完成左子树,完成右子树。 + + 如果说左子树有n种组合,右子树有m种组合,那最终的组合数就是n*m. 把这所有的组合组装起来即可 + */ + public List generateTreesHelp(int start, int end) { + ArrayList ret = new ArrayList(); + + // null也是一种解,也需要把它加上去。这样在组装左右子树的时候,不会出现左边没有解的情况,或 + // 是右边没有解的情况 + if (start > end) { + ret.add(null); + return ret; + } + + for (int i = start; i <= end; i++) { + // 求出左右子树的所有的可能。 + List left = generateTreesHelp(start, i - 1); + List right = generateTreesHelp(i + 1, end); + + // 将左右子树的所有的可能性全部组装起来 + for (TreeNode l: left) { + for(TreeNode r: right) { + // 先创建根节点 + TreeNode root = new TreeNode(i); + root.left = l; + root.right = r; + + // 将组合出来的树加到结果集合中。 + ret.add(root); + } + } + } + + return ret; + } +} From d92fcd1c5ba2eaabd7129351d76347ede50df5e2 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Wed, 8 Oct 2014 21:29:54 -0700 Subject: [PATCH 36/66] tree2 --- facebook/SortWeight.java | 89 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 5 deletions(-) diff --git a/facebook/SortWeight.java b/facebook/SortWeight.java index 779f466..7172043 100644 --- a/facebook/SortWeight.java +++ b/facebook/SortWeight.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; @@ -14,10 +13,10 @@ public static void main(String[] args) { String input3 = "pizza 500 hotdog 2.0"; String input4 = "pizza 500 2.0"; - LinkedList list1 = sortWeight(input1); - LinkedList list2 = sortWeight(input2); - LinkedList list3 = sortWeight(input3); - LinkedList list4 = sortWeight(input4); + LinkedList list1 = sortWeight2(input1); + LinkedList list2 = sortWeight2(input2); + LinkedList list3 = sortWeight2(input3); + LinkedList list4 = sortWeight2(input4); System.out.println(list1.toString()); System.out.println(list2.toString()); @@ -85,6 +84,86 @@ public static LinkedList sortWeight(String input) { return ret; } + public static class Pair implements Comparable { + String food; + float weight; + + Pair (String food, float weight) { + this.food = food; + this.weight = weight; + } + + // 注意,我们用o来减当前的重量,就能得到降序的排列 + public int compareTo(Pair o) { + if (o.weight - this.weight < 0) { + return -1; + } + + return 1; + } + } + + /* + * 使用自定义结构体 Pair而不是hashmap来记录食物-重量对。可以简化算法。 + * 但这时就需要自定义一个compareTo方法 + * */ + public static LinkedList sortWeight2(String input) { + LinkedList ret = new LinkedList(); + if (input == null) { + return ret; + } + + String[] strs = input.split(" "); + + float defautWeight = 5; + + // 当weight = -1,表示这一组食物-重量链还未完成 + String food = null; + float weight = 0; + + // 使用ArrayList来记录食物-重量对 + ArrayList list = new ArrayList(); + + // Go through the string. + for (String s: strs) { + // 上一次的food-weight对已经结束 + if (weight != -1) { + food = s; + weight = -1; + } else { + float tmp = stringToNumber(s); + // This is a float, so just add a food to the list. + if (tmp != -1) { + weight = tmp; + list.add(new Pair(food, weight)); + } else { + // This is not a float, means that there should be + // a new food. + list.add(new Pair(food, defautWeight)); + + // 开始新一轮的食物-重量链 + food = s; + weight = -1; + } + } + } + + //System.out.println(map.toString()); + + if (weight == -1) { + list.add(new Pair(food, defautWeight)); + } + + Collections.sort(list); + Iterator iter = list.iterator(); + while (iter.hasNext()) { + ret.add(iter.next().food); + } + + return ret; + } + + public static void addFoodToMap(HashMap> map, String food, float weight) { // 把上一次的食物-重量终结 From 632666f85c761a93efac2608a1a3b82287929e15 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Wed, 8 Oct 2014 22:36:20 -0700 Subject: [PATCH 37/66] merge Sort --- sort/MergeSort_LinkedList.java | 99 ++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 sort/MergeSort_LinkedList.java diff --git a/sort/MergeSort_LinkedList.java b/sort/MergeSort_LinkedList.java new file mode 100644 index 0000000..9fde42d --- /dev/null +++ b/sort/MergeSort_LinkedList.java @@ -0,0 +1,99 @@ +package Algorithms.sort; + +import java.util.LinkedList; + +import Algorithms.ListNode; + +public class MergeSort_LinkedList { + public static void main(String[] args) { + ListNode node1 = new ListNode(0); + ListNode node2 = new ListNode(15); + ListNode node3 = new ListNode(6); + ListNode node4 = new ListNode(9); + ListNode node5 = new ListNode(4); + + node1.next = node2; + node2.next = node3; + node3.next = node4; + node4.next = node5; + + System.out.println(node1.toString()); + sort(node1); + System.out.println(node1.toString()); + } + + public static ListNode sort(ListNode head) { + if (head == null) { + return null; + } + + // 注意一定要加这一行,否则会不断对1个元素无限分下去 + if (head.next == null) { + return head; + } + + ListNode mid = findMidPre(head); + + // 将list切为2个list. + ListNode right = mid.next; + mid.next = null; + + //调用将2边分别排序 + ListNode left = sort(head); + right = sort(right); + + // 将2个已经排序的List Merge在一起 + return merge(left, right); + } + + public static ListNode merge(ListNode head1, ListNode head2) { + ListNode dummy = new ListNode(0); + + // cur 表示新链的尾部. + ListNode cur = dummy; + + while (head1 != null && head2 != null) { + // 将2个链中较小的一个接到新链的尾部 + if (head1.val < head2.val) { + cur.next = head1; + head1 = head1.next; + } else { + cur.next = head2; + head2 = head2.next; + } + + // 将扫描指针移动到新链的尾部0 + cur = cur.next; + } + + // 把未扫描完毕的链接在新链的结尾即可 + if (head1 != null) { + cur.next = head1; + } else { + cur.next = head2; + } + + // 返回新链的头部 + return dummy.next; + } + + // 这个函数是寻找Mid的前一个节点, + // 技巧就是:一开始就将Fast放在head的前一个节点,这样当只有2个节点的时候: + // 1->2->null + // slow 会停在1处 ,这样就可以处理只有2个节点的情况. + public static ListNode findMidPre(ListNode head) { + if (head == null) { + return null; + } + + ListNode fast = head.next; + ListNode slow = head; + + if (fast != null && fast.next != null) { + fast = fast.next.next; + slow = slow.next; + } + + return slow; + } +} From d1c27bdba5d7b17574b3e26d35e6dfd6591dbf05 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 9 Oct 2014 00:40:30 -0700 Subject: [PATCH 38/66] merge --- array/MaxProduct.java | 33 +++++++++++++++++++++++++++++++++ array/MergeSortedArray.java | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 array/MaxProduct.java create mode 100644 array/MergeSortedArray.java diff --git a/array/MaxProduct.java b/array/MaxProduct.java new file mode 100644 index 0000000..65f10d3 --- /dev/null +++ b/array/MaxProduct.java @@ -0,0 +1,33 @@ +package Algorithms.array; + +public class MaxProduct { + public static int maxProduct(int[] A) { + int max = 0; + + int left = 0; + int right = 0; + + int len = A.length; + + int product = 1; + + for (int i = 0; i < len; i++) { + if (A[i] <= 0) { + max = Math.max(max, product); + product = 1; + } + product *= A[i]; + } + + return 0; + } + + /* + * 作法是找到连续的正数,不断相乘即可。 + * */ + public static void main(String[] strs) { + int[] A = {2, 3, -2, 4}; + + System.out.println(maxProduct(A)); + } +} diff --git a/array/MergeSortedArray.java b/array/MergeSortedArray.java new file mode 100644 index 0000000..aea7ae7 --- /dev/null +++ b/array/MergeSortedArray.java @@ -0,0 +1,33 @@ +package Algorithms.array; + +public class MergeSortedArray { + public void merge(int A[], int m, int B[], int n) { + int cur = m + n - 1; + + // 指向A的尾部 + int pA = m - 1; + + // 指向B的尾部 + int pB = n - 1; + + while (cur >= 0) { + if (pA < 0 || pB < 0) { + break; + } + + // 从尾部往前比较 + if (A[pA] > B[pB]) { + A[cur] = A[pA--]; + } else { + A[cur] = B[pB--]; + } + + cur--; + } + + // copy the left over elements in B to A. + System.arraycopy(B, 0, A, 0, pB + 1); + + return; + } +} From ec77e43960719d2659c7236799df1b44385389ba Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 9 Oct 2014 00:56:10 -0700 Subject: [PATCH 39/66] remove duplicate --- array/MaxProduct.java | 9 ++++----- array/RemoveDuplicates.java | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 array/RemoveDuplicates.java diff --git a/array/MaxProduct.java b/array/MaxProduct.java index 65f10d3..fc6401f 100644 --- a/array/MaxProduct.java +++ b/array/MaxProduct.java @@ -3,10 +3,7 @@ public class MaxProduct { public static int maxProduct(int[] A) { int max = 0; - - int left = 0; - int right = 0; - + int len = A.length; int product = 1; @@ -15,11 +12,13 @@ public static int maxProduct(int[] A) { if (A[i] <= 0) { max = Math.max(max, product); product = 1; + continue; } + product *= A[i]; } - return 0; + return max; } /* diff --git a/array/RemoveDuplicates.java b/array/RemoveDuplicates.java new file mode 100644 index 0000000..60e54c4 --- /dev/null +++ b/array/RemoveDuplicates.java @@ -0,0 +1,20 @@ +package Algorithms.array; + +public class RemoveDuplicates { + public int removeDuplicates(int[] A) { + if (A == null || A.length == 0) { + return 0; + } + + // A里至少有1个元素 + int len = 1; + + for (int i = 1; i < A.length; i++) { + if (A[i] != A[i - 1]) { + A[len++] = A[i]; + } + } + + return len; + } +} From 127db30ac10a7be7573979fd50b6e9e2bcdd3ba6 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 9 Oct 2014 01:21:32 -0700 Subject: [PATCH 40/66] remove duplicates2 --- array/RemoveDuplicates2.java | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 array/RemoveDuplicates2.java diff --git a/array/RemoveDuplicates2.java b/array/RemoveDuplicates2.java new file mode 100644 index 0000000..2bbb24f --- /dev/null +++ b/array/RemoveDuplicates2.java @@ -0,0 +1,42 @@ +package Algorithms.array; + +public class RemoveDuplicates2 { + public static int removeDuplicates(int[] A) { + if (A == null) { + return 0; + } + + if (A.length <= 1) { + return A.length; + } + + int len = 1; + + // 拷贝2次后就不再拷贝 + boolean canCopy = true; + + for (int i = 1; i < A.length; i++) { + if (A[i] == A[i - 1]) { + if (!canCopy) { + continue; + } + canCopy = false; + } else { + canCopy = true; + } + + A[len++] = A[i]; + } + + return len; + } + + public static void main(String[] strs) { + int[] A = {1,1,1,2,2,3}; + removeDuplicates(A); + + for (int i: A) { + System.out.print(i + " "); + } + } +} From 63dd8d0efa034cadabd5ade0c86984c80c25e372 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 9 Oct 2014 02:28:46 -0700 Subject: [PATCH 41/66] array --- array/SearchInRotatedSortedArray.java | 40 +++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 array/SearchInRotatedSortedArray.java diff --git a/array/SearchInRotatedSortedArray.java b/array/SearchInRotatedSortedArray.java new file mode 100644 index 0000000..530e50e --- /dev/null +++ b/array/SearchInRotatedSortedArray.java @@ -0,0 +1,40 @@ +package Algorithms.array; + +public class SearchInRotatedSortedArray { + public int search(int[] A, int target) { + if (A == null || A.length == 0) { + return -1; + } + + int left = 0; + int right = A.length - 1; + + while (left <= right) { + int mid = left + (right - left) / 2; + if (A[mid] == target) { + return mid; + } + + // the left side is sorted. + if (A[mid] >= A[left]) { + if (target <= A[mid] && target >= A[left]) { + // target is in the left side. + right = mid - 1; + } else { + // target is in the right side. + left = mid + 1; + } + } else { // the right side is sorted. + if (target >= A[mid] && target <= A[right]) { + // target is in the right side. + left = mid + 1; + } else { + // target is in the right side. + right = mid - 1; + } + } + } + + return -1; + } +} From 23f07e334f71188d03b52362791784d4411e8af9 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 9 Oct 2014 10:58:30 -0700 Subject: [PATCH 42/66] search --- array/SearchInRotatedSortedArray2.java | 60 ++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 array/SearchInRotatedSortedArray2.java diff --git a/array/SearchInRotatedSortedArray2.java b/array/SearchInRotatedSortedArray2.java new file mode 100644 index 0000000..4cb650e --- /dev/null +++ b/array/SearchInRotatedSortedArray2.java @@ -0,0 +1,60 @@ +package Algorithms.array; + +/* + * https://oj.leetcode.com/problems/search-in-rotated-sorted-array-ii/ + * + * Search in Rotated Sorted Array II Total Accepted: 18427 Total Submissions: 59728 My Submissions +Follow up for "Search in Rotated Sorted Array": +What if duplicates are allowed? + +Would this affect the run-time complexity? How and why? + +Write a function to determine if a given target is in the array. + * */ +public class SearchInRotatedSortedArray2 { + /* + In this function, the complex may go to O(n). It depents on how many duplicates exit in the array. + if there are M duplicates, the complexity may be O(logN + M). + */ + public boolean search(int[] A, int target) { + if (A == null || A.length == 0) { + return false; + } + + // setup two point to the left and right of the array. + int l = 0, r = A.length - 1; + while (l <= r) { + // get the mid point. + int mid = l + (r - l)/2; + if (target == A[mid]) { + return true; + } + + if (A[mid] > A[l]) { + // the left side is sorted. + if (target <= A[mid] && target >= A[l]) { + // target is in the left side. + r = mid - 1; + } else { + l = mid + 1; + } + } else if (A[mid] < A[l]) { + // the right side is sorted. + if (target <= A[r] && target >= A[mid]) { + // target is in the right side. + l = mid + 1; + } else { + r = mid - 1; + } + } else { + // when A[mid] == A[l], we can't determin, just move the + // left point one + l++; + } + } + + return false; + } + + +} From bd027087d5a4ee7a93fdc37bc03020af6ae6aabc Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 9 Oct 2014 11:57:47 -0700 Subject: [PATCH 43/66] maxSubArray --- array/MaxSubArray.java | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 array/MaxSubArray.java diff --git a/array/MaxSubArray.java b/array/MaxSubArray.java new file mode 100644 index 0000000..ea36db6 --- /dev/null +++ b/array/MaxSubArray.java @@ -0,0 +1,26 @@ +package Algorithms.array; + +public class MaxSubArray { + public int maxSubArray(int[] A) { + if (A == null || A.length == 0) { + return 0; + } + + int len = A.length; + int sum = 0; + + // 记录下最大值 + int max = Integer.MIN_VALUE; + for (int i = 0; i < len; i++) { + // 加上当前值 + sum += A[i]; + max = Math.max(max, sum); + + // 如果和小于0,则可以丢弃之,下一个值重新计算即可。 + // 因为对于每一个值来说,有2处选择:加上前面的一些数,或是不加。如果是负数,可以不加。 + sum = Math.max(0, sum); + } + + return max; + } +} From 88a4d501eeb901b667e18ad7b48cadc812d12b9b Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 9 Oct 2014 12:16:21 -0700 Subject: [PATCH 44/66] the merge --- list/MergeTwoLists.java | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 list/MergeTwoLists.java diff --git a/list/MergeTwoLists.java b/list/MergeTwoLists.java new file mode 100644 index 0000000..7eac1e1 --- /dev/null +++ b/list/MergeTwoLists.java @@ -0,0 +1,33 @@ +package Algorithms.list; + +import Algorithms.ListNode; + +public class MergeTwoLists { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if (l1 == null && l2 == null) { + return null; + } + + ListNode dummy = new ListNode(0); + ListNode cur = dummy; + while (l1 != null && l2 != null) { + if (l1.val < l2.val) { + cur.next = l1; + l1 = l1.next; + } else { + cur.next = l2; + l2 = l2.next; + } + + cur = cur.next; + } + + if (l1 != null) { + cur.next = l1; + } else { + cur.next = l2; + } + + return dummy.next; + } +} From 0ccff33fd4f4fdc32a1b879f0977b2cd8f246867 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 9 Oct 2014 21:30:45 -0700 Subject: [PATCH 45/66] strstr --- string/StrStr.java | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 string/StrStr.java diff --git a/string/StrStr.java b/string/StrStr.java new file mode 100644 index 0000000..cd04196 --- /dev/null +++ b/string/StrStr.java @@ -0,0 +1,33 @@ +package Algorithms.string; + +public class StrStr { + public String strStr(String haystack, String needle) { + if (haystack == null || needle == null) { + return null; + } + + int len1 = haystack.length(); + int len2 = needle.length(); + + // Pay attention. if find "pl" in "apple", then len1 = 5, len2 = 2, the + // i should <= 3. + // so it should be i <= len1 - len2; + for (int i = 0; i <= len1 - len2; i++) { + int j = 0; + for (; j < len2; j++) { + if (haystack.charAt(i + j) != needle.charAt(j)) { + break; + } + } + + // j goes to the end, it means that the loop never break. That means + // found the needle. + if (j == len2) { + return haystack.substring(i); + } + } + + // didn't find the needle. + return null; + } +} \ No newline at end of file From 096b7439eb9d191975c45b55e514be99b9956a9a Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 9 Oct 2014 22:23:40 -0700 Subject: [PATCH 46/66] list --- list/DeleteDuplicates.java | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 list/DeleteDuplicates.java diff --git a/list/DeleteDuplicates.java b/list/DeleteDuplicates.java new file mode 100644 index 0000000..6ddc921 --- /dev/null +++ b/list/DeleteDuplicates.java @@ -0,0 +1,40 @@ +package Algorithms.list; + +import Algorithms.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class DeleteDuplicates { + public ListNode deleteDuplicates(ListNode head) { + if (head == null) { + return null; + } + + ListNode dummy = new ListNode(0); + dummy.next = head; + + ListNode cur = dummy; + + while (cur != null) { + if (cur.next != null + && cur.next.next != null + && cur.next.val == cur.next.next.val) { + // remove cur.next; + cur.next = cur.next.next; + } else { + cur = cur.next; + } + } + + return dummy.next; + } +} \ No newline at end of file From d955d59d7c907dfa98fc8db5d6851e41f652ad86 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 9 Oct 2014 23:04:30 -0700 Subject: [PATCH 47/66] divide --- Divide2/Pow.java | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Divide2/Pow.java diff --git a/Divide2/Pow.java b/Divide2/Pow.java new file mode 100644 index 0000000..d9eebb5 --- /dev/null +++ b/Divide2/Pow.java @@ -0,0 +1,34 @@ +package Algorithms.Divide2; + +public class Pow { + public double pow(double x, int n) { + if (x == 0) { + return 0; + } + + if (n == 0) { + return 1; + } + + // should consider the case when n is below zero. + boolean minus = false; + if (n < 0) { + minus = true; + n = -n; + } + + int m = n%2; + + // count + double ret = pow(x, n/2); + ret *= ret; + if (m == 1) { + ret *= x; + } + + if (minus) { + return 1/ret; + } + return ret; + } +} \ No newline at end of file From 218d63f6bd55431a219d1c3603df522e8e94b1d4 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 9 Oct 2014 23:34:11 -0700 Subject: [PATCH 48/66] pow --- Divide2/Pow.java | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Divide2/Pow.java b/Divide2/Pow.java index d9eebb5..eaebb53 100644 --- a/Divide2/Pow.java +++ b/Divide2/Pow.java @@ -6,11 +6,28 @@ public double pow(double x, int n) { return 0; } - if (n == 0) { + if (x == 1 || n == 0) { return 1; } - // should consider the case when n is below zero. + if (x == -1) { + int left = Math.abs(n)%2; + if (left == 1) { + return -1; + } else { + return 1; + } + } + + // 注意 这样写是不行的,因为-n在n到最小值会出错, + // int的最小值(负数)取-n仍然是n 这样就错了。 + + // if (n < 0) { + // double ret1 = pow(x, -n); + // return 1/(double)ret1; + // } + + //should consider the case when n is below zero. boolean minus = false; if (n < 0) { minus = true; From 4f99b2df5e9c54d7b80ba7e22fa8b8c8e815f8f2 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Thu, 9 Oct 2014 23:49:30 -0700 Subject: [PATCH 49/66] pow --- Divide2/Pow.java | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/Divide2/Pow.java b/Divide2/Pow.java index eaebb53..3105b69 100644 --- a/Divide2/Pow.java +++ b/Divide2/Pow.java @@ -1,7 +1,12 @@ package Algorithms.Divide2; public class Pow { - public double pow(double x, int n) { + public static void main(String[] strs) { + System.out.println(pow(-3, -2147483648)); + + } + + public static double pow(double x, int n) { if (x == 0) { return 0; } @@ -10,28 +15,13 @@ public double pow(double x, int n) { return 1; } - if (x == -1) { - int left = Math.abs(n)%2; - if (left == 1) { - return -1; - } else { - return 1; - } - } - + // Because when we deal with -2147483648, we can't get right -n + // cause -n == n when it is -2147483648. // 注意 这样写是不行的,因为-n在n到最小值会出错, // int的最小值(负数)取-n仍然是n 这样就错了。 - - // if (n < 0) { - // double ret1 = pow(x, -n); - // return 1/(double)ret1; - // } - - //should consider the case when n is below zero. - boolean minus = false; if (n < 0) { - minus = true; - n = -n; + double ret1 = x * pow(x, -(1 + n)); + return 1/(double)ret1; } int m = n%2; @@ -43,9 +33,6 @@ public double pow(double x, int n) { ret *= x; } - if (minus) { - return 1/ret; - } return ret; } } \ No newline at end of file From 7564463efb17523a23ea8d816a44cdac10a4c505 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 10 Oct 2014 00:39:59 -0700 Subject: [PATCH 50/66] list --- sort/SortList_leetCode.java | 79 +++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 sort/SortList_leetCode.java diff --git a/sort/SortList_leetCode.java b/sort/SortList_leetCode.java new file mode 100644 index 0000000..f4f31d3 --- /dev/null +++ b/sort/SortList_leetCode.java @@ -0,0 +1,79 @@ +package Algorithms.sort; + +import Algorithms.ListNode; + +/** + * Definition for singly-linked list. + * class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class SortList_leetCode { + public ListNode sortList(ListNode head) { + if (head == null) { + return null; + } + + // !! Remember to add this line! Because this may cause infinit loop. + if (head.next == null) { + return head; + } + + ListNode midPre = findmidPre(head); + + ListNode right = sortList(midPre.next); + midPre.next = null; + + ListNode left = sortList(head); + + return merge(left, right); + } + + // get the node before mid. + public ListNode findmidPre(ListNode head) { + if (head == null) { + return null; + } + + ListNode slow = head; + ListNode fast = head.next; + + while (fast != null && fast.next != null) { + fast = fast.next.next; + slow = slow.next; + } + + return slow; + } + + // get the node before mid. + public ListNode merge(ListNode h1, ListNode h2) { + ListNode dummy = new ListNode(0); + + ListNode cur = dummy; + while (h1 != null && h2 != null) { + if (h1.val < h2.val) { + cur.next = h1; + h1 = h1.next; + } else { + cur.next = h2; + h2 = h2.next; + } + + cur = cur.next; + } + + if (h1 != null) { + cur.next = h1; + } else { + cur.next = h2; + } + + return dummy.next; + } +} \ No newline at end of file From 1ddacc55917a7b77ca6a12a03cea0d7b12b72143 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 10 Oct 2014 01:26:55 -0700 Subject: [PATCH 51/66] sort --- sort/InsertionSortList.java | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 sort/InsertionSortList.java diff --git a/sort/InsertionSortList.java b/sort/InsertionSortList.java new file mode 100644 index 0000000..fe368bd --- /dev/null +++ b/sort/InsertionSortList.java @@ -0,0 +1,51 @@ +package Algorithms.sort; + +import Algorithms.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class InsertionSortList { + public ListNode insertionSortList(ListNode head) { + // 使用dummynode来记录新的头节点,每次把旧链找合适的位置来插入即可 + if (head == null) { + return null; + } + + ListNode dummy = new ListNode(0); + + // 记录下插入位置的前趋节点. + ListNode pre = dummy; + + while (head != null) { + // every time we should reset the pre to the BEGIN OF THE LIST. + pre = dummy; + + // 这样可以找到pre.next为第一个比head大的节点 + // if we use <= here we can keep the Algorithm stable. + while (pre.next != null && pre.next.val <= head.val) { + pre = pre.next; + } + + // backup the next node of head; + ListNode tmp = head.next; + + // Insert the head between PRE and PRE.next. + head.next = pre.next; + pre.next = head; + + // set head to the next node. + head = tmp; + } + + return dummy.next; + } +} \ No newline at end of file From d5573fc6b1d3c364929c12257463c95367bcf899 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 10 Oct 2014 01:59:45 -0700 Subject: [PATCH 52/66] reorder list --- list/ReorderList.java | 109 ++++++++++++++++++++++++++++++++++++ sort/InsertionSortList.java | 2 +- 2 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 list/ReorderList.java diff --git a/list/ReorderList.java b/list/ReorderList.java new file mode 100644 index 0000000..6ec1e93 --- /dev/null +++ b/list/ReorderList.java @@ -0,0 +1,109 @@ +package Algorithms.list; + +import Algorithms.ListNode; + +/** + * Definition for singly-linked list. + * class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class ReorderList { + public void reorderList(ListNode head) { + // 4 STEP: + // 1. find the mid. + // 2. cut the list to two list. + // 3. REVERSE the right side. + // 4. MERGE the two list. + if (head == null) { + return; + } else if (head.next == null) { + return; + } + + ListNode pre = findMidPre(head); + + // cut the two list. + ListNode right = pre.next; + pre.next = null; + + // reverse the right link. + right = reverse(right); + + merge(head, right); + } + + // 找到mid的前一个节点 + // EXAMPLE: 1-> 4-> 2-> null + // 我们要找的是1. + // 这样可以把它断开为2个链:1->null and 4->2->null + // 这样做的是因为比如1->4->null + // 我们只能找1,如果你找到的是4,你是不能断开为2个的。 + // 对于这个题目可能无所谓,但是对于merge sort你不能分开2个节点就不能工作. + public ListNode findMidPre(ListNode head) { + if (head == null) { + return null; + } + + ListNode slow = head; + ListNode fast = head.next; + + while (fast != null && fast.next != null) { + fast = fast.next.next; + slow = slow.next; + } + + return slow; + } + + // reverse the linked list. + public ListNode reverse(ListNode head) { + if (head == null) { + return null; + } + + ListNode dummy = new ListNode(0); + while (head != null) { + // store the next node. + ListNode tmp = head.next; + + // insert the head into the head! + head.next = dummy.next; + dummy.next = head; + + head = tmp; + } + + return dummy.next; + } + + // merge head1 and head 2 one by one. + public void merge(ListNode head1, ListNode head2) { + ListNode dummy = new ListNode(0); + + ListNode cur = dummy; + + while (head1 != null && head2 != null) { + // 注意这里容易出错。head1要先指向它的下一个,再处理head2,否则cur.next=head2这里会改掉 + // head1的指向. + cur.next = head1; + cur = cur.next; + head1 = head1.next; + + cur.next = head2; + cur = cur.next; + head2 = head2.next; + } + + if (head1 != null) { + cur.next = head1; + } else { + cur.next = head2; + } + } +} \ No newline at end of file diff --git a/sort/InsertionSortList.java b/sort/InsertionSortList.java index fe368bd..7a36b62 100644 --- a/sort/InsertionSortList.java +++ b/sort/InsertionSortList.java @@ -15,7 +15,7 @@ */ public class InsertionSortList { public ListNode insertionSortList(ListNode head) { - // 使用dummynode来记录新的头节点,每次把旧链找合适的位置来插入即可 + // 使用dummy node来记录新的头节点,每次把旧链找合适的位置来插入即可 if (head == null) { return null; } From c144ac6620000dd673b8570fe793f581a5485078 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 10 Oct 2014 02:50:18 -0700 Subject: [PATCH 53/66] random --- list/CopyRandomList.java | 69 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 list/CopyRandomList.java diff --git a/list/CopyRandomList.java b/list/CopyRandomList.java new file mode 100644 index 0000000..499bd84 --- /dev/null +++ b/list/CopyRandomList.java @@ -0,0 +1,69 @@ +package Algorithms.list; + +/** + * Definition for singly-linked list with a random pointer. + * class RandomListNode { + * int label; + * RandomListNode next, random; + * RandomListNode(int x) { this.label = x; } + * }; + */ +public class CopyRandomList { + public static class RandomListNode { + int label; + RandomListNode next, random; + + RandomListNode(int x) { + this.label = x; + } + } + + public static void main(String[] strs) { + RandomListNode node = new RandomListNode(-1); + RandomListNode copy = copyRandomList(node); + } + + public static RandomListNode copyRandomList(RandomListNode head) { + if (head == null) { + return null; + } + + // copy the list; + RandomListNode cur = head; + while (cur != null) { + RandomListNode nodeCopy = new RandomListNode(cur.label); + + // insert the node between the old link. + nodeCopy.next = cur.next; + cur.next = nodeCopy; + + cur = cur.next.next; + } + + // copy the radom list. + cur = head; + while (cur != null) { + cur.next.random = cur.random; + cur = cur.next.next; + } + + // divide the two list. + RandomListNode headCopy = head.next; + cur = head; + + // track the new list. + RandomListNode curNew = headCopy; + while (cur != null) { + cur.next = cur.next.next; + cur = cur.next; + + if (curNew.next != null) { + curNew.next = curNew.next.next; + curNew = curNew.next; + } + + } + + return curNew; + } +} From 2a37fec11cac6630347afc9304a65470b3fcadf6 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 10 Oct 2014 03:37:28 -0700 Subject: [PATCH 54/66] reverse2 --- list/ReverseBetween.java | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 list/ReverseBetween.java diff --git a/list/ReverseBetween.java b/list/ReverseBetween.java new file mode 100644 index 0000000..790c197 --- /dev/null +++ b/list/ReverseBetween.java @@ -0,0 +1,49 @@ +package Algorithms.list; + +import Algorithms.ListNode; + +public class ReverseBetween { + public ListNode reverseBetween(ListNode head, int m, int n) { + if (head == null || head.next == null) { + return head; + } + + if (m >= n) { + return head; + } + + ListNode dummy = new ListNode(0); + dummy.next = head; + + ListNode pre = dummy; + + //1. get the pre node before m. + for (int i = m; i > 1; i--) { + pre = pre.next; + } + + // record the tail of the reversed link. + ListNode reverseTail = pre.next; + pre.next = null; + + // reverse the link. + ListNode cur = reverseTail; + + for (int i = n - m + 1; i > 0; i--) { + if (i == 1) { + // 这里是翻转段后的第一个元素 . + reverseTail.next = cur.next; + } + + ListNode tmp = cur.next; + + cur.next = pre.next; + pre.next = cur; + + cur = tmp; + } + + return dummy.next; + } + +} From 150f920da0cd4ae6ec8f8f888db294466815f23a Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 10 Oct 2014 04:05:18 -0700 Subject: [PATCH 55/66] tree --- tree/hasPathSum.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tree/hasPathSum.java diff --git a/tree/hasPathSum.java b/tree/hasPathSum.java new file mode 100644 index 0000000..d61d9b3 --- /dev/null +++ b/tree/hasPathSum.java @@ -0,0 +1,20 @@ +package Algorithms.tree; + +public class hasPathSum { + /** + * Definition for binary tree public class TreeNode { int val; TreeNode + * left; TreeNode right; TreeNode(int x) { val = x; } } + */ + public boolean hasPathSum(TreeNode root, int sum) { + if (root == null) { + return false; + } + + if (root.left == null && root.right == null && sum == root.val) { + return true; + } + + return hasPathSum(root.left, sum - root.val) + || hasPathSum(root.right, sum - root.val); + } +} From 82143ad9acbf6c02964b7a77cb0879f81cec6d0a Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 10 Oct 2014 04:06:29 -0700 Subject: [PATCH 56/66] name --- tree/hasPathSum.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tree/hasPathSum.java b/tree/hasPathSum.java index d61d9b3..d4c42ba 100644 --- a/tree/hasPathSum.java +++ b/tree/hasPathSum.java @@ -1,6 +1,6 @@ package Algorithms.tree; -public class hasPathSum { +public class HasPathSum { /** * Definition for binary tree public class TreeNode { int val; TreeNode * left; TreeNode right; TreeNode(int x) { val = x; } } From f08140a11ccdd41ec0be88453af9c963a6e7d8a5 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 10 Oct 2014 23:20:53 -0700 Subject: [PATCH 57/66] lett --- dfs/LetterCombinations.java | 86 ++++++++++++++++++++++++++++++++++++ dfs/LetterCombinations2.java | 53 ++++++++++++++++++++++ dp/Fibonacci.java | 23 ++++++++-- 3 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 dfs/LetterCombinations.java create mode 100644 dfs/LetterCombinations2.java diff --git a/dfs/LetterCombinations.java b/dfs/LetterCombinations.java new file mode 100644 index 0000000..f70414c --- /dev/null +++ b/dfs/LetterCombinations.java @@ -0,0 +1,86 @@ +package Algorithms.dfs; + +import java.util.ArrayList; +import java.util.List; + +public class LetterCombinations { + public List letterCombinations(String digits) { + List ret = new ArrayList(); + ArrayList path = new ArrayList(); + + letterCombinationsHelp(digits, path, ret, 0); + + return ret; + } + + /* + 表示从digit的index处开始直到结尾的数字对应的字符的组合数 + */ + public void letterCombinationsHelp(String digits, ArrayList path, List ret, int index) { + if (digits == null) { + return; + } + + int len = digits.length(); + if (path.size() == len) { + StringBuilder sb = new StringBuilder(); + for (char c: path) { + sb.append(c); + } + ret.add(sb.toString()); + return; + } + + List chars = getChar(digits.charAt(index)); + + for (int i = 0; i < chars.size(); i++) { + path.add(chars.get(i)); + letterCombinationsHelp(digits, path, ret, index + 1); + path.remove(path.size() - 1); + } + } + + public List getChar(char c) { + ArrayList list = new ArrayList(); + + if (c == '1') { + return list; + } else if (c == '2') { + list.add('a'); + list.add('b'); + list.add('c'); + } else if (c == '3') { + list.add('d'); + list.add('e'); + list.add('f'); + } else if (c == '4') { + list.add('g'); + list.add('h'); + list.add('i'); + } else if (c == '5') { + list.add('j'); + list.add('k'); + list.add('l'); + } else if (c == '6') { + list.add('m'); + list.add('n'); + list.add('o'); + } else if (c == '7') { + list.add('p'); + list.add('q'); + list.add('r'); + list.add('s'); + } else if (c == '8') { + list.add('t'); + list.add('u'); + list.add('v'); + } else if (c == '9') { + list.add('w'); + list.add('x'); + list.add('y'); + list.add('z'); + } + + return list; + } +} diff --git a/dfs/LetterCombinations2.java b/dfs/LetterCombinations2.java new file mode 100644 index 0000000..5d7dccb --- /dev/null +++ b/dfs/LetterCombinations2.java @@ -0,0 +1,53 @@ +package Algorithms.dfs; + +import java.util.ArrayList; +import java.util.List; + +public class LetterCombinations2 { + public class Solution { + // We create a map to map the digit to the characters. + String[] map = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; + + public List letterCombinations(String digits) { + List ret = new ArrayList(); + ArrayList path = new ArrayList(); + + letterCombinationsHelp(digits, path, ret, 0); + + return ret; + } + + /* + 表示从digit的index处开始直到结尾的数字对应的字符的组合数 + */ + public void letterCombinationsHelp(String digits, ArrayList path, List ret, int index) { + if (digits == null) { + return; + } + + int len = digits.length(); + if (path.size() == len) { + StringBuilder sb = new StringBuilder(); + for (char c: path) { + sb.append(c); + } + ret.add(sb.toString()); + return; + } + + // get the possiable characters. + // for example, get abc from '2' + String combs = getChar(digits.charAt(index)); + + for (int i = 0; i < combs.length(); i++) { + path.add(combs.charAt(i)); + letterCombinationsHelp(digits, path, ret, index + 1); + path.remove(path.size() - 1); + } + } + + public String getChar(char c) { + return map[c - '0']; + } + } +} \ No newline at end of file diff --git a/dp/Fibonacci.java b/dp/Fibonacci.java index 1c00e40..e376d9e 100644 --- a/dp/Fibonacci.java +++ b/dp/Fibonacci.java @@ -1,6 +1,7 @@ package Algorithms.dp; import java.util.ArrayList; +import java.util.HashMap; /************************************************************************* * Compilation: javac Fibonacci.java @@ -29,14 +30,28 @@ * *************************************************************************/ public class Fibonacci { - public static long fib(int n) { + public static long fib(int n, HashMap map) { //System.out.println("Enter rec once."); if (n <= 2) { return 1; } + + long first; + if (map.get(n - 2) != null) { + first = map.get(n - 2); + } else { + first = fib(n - 2, map); + } + + long second; + if (map.get(n - 1) != null) { + second = map.get(n - 1); + } else { + second = fib(n - 1, map); + } - return fib(n - 1) + fib(n - 2); + return second + first; } public static ArrayList fibDp(int n) { @@ -57,12 +72,12 @@ public static ArrayList fibDp(int n) { public static void main(String[] args) { int N = 5; - System.out.print(fib(5) + " "); + System.out.print(fib(10, new HashMap()) + " "); // for (int i = 1; i <= N; i++) { // System.out.print(fib(i) + " "); // } - ArrayList list = fibDp(500); + ArrayList list = fibDp(10); System.out.println(list.toString()); } From 42796c9f28d2672598df14710af30052fb3c4d8e Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Fri, 10 Oct 2014 23:53:39 -0700 Subject: [PATCH 58/66] list --- list/DeleteDuplicates2.java | 60 +++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 list/DeleteDuplicates2.java diff --git a/list/DeleteDuplicates2.java b/list/DeleteDuplicates2.java new file mode 100644 index 0000000..4b3e3ec --- /dev/null +++ b/list/DeleteDuplicates2.java @@ -0,0 +1,60 @@ +package Algorithms.list; + +import Algorithms.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + * + * Remove Duplicates from Sorted List II Total Accepted: 21701 Total Submissions: 87380 My Submissions + Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list. + + For example, + Given 1->2->3->3->4->4->5, return 1->2->5. + Given 1->1->1->2->3, return 2->3. + */ +public class DeleteDuplicates2 { + public ListNode deleteDuplicates(ListNode head) { + if (head == null) { + return null; + } + + // record the head. + ListNode dummy = new ListNode(0); + dummy.next = head; + + ListNode cur = dummy; + + // to delete the last node in the list of duplications. + boolean del = false; + + while (cur != null) { + if (cur.next != null + && cur.next.next != null + && cur.next.val == cur.next.next.val) { + cur.next = cur.next.next; + del = true; + } else { + // delete the last node in a duplicaions list. + if (del) { + cur.next = cur.next.next; + + // set back the flag to be false. + del = false; + } else { + // move forward. + cur = cur.next; + } + } + } + + return dummy.next; + } +} \ No newline at end of file From d6d13088fa5cd683251a6aa30fef90d012082239 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sat, 11 Oct 2014 00:20:27 -0700 Subject: [PATCH 59/66] list --- list/PartitionList.java | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 list/PartitionList.java diff --git a/list/PartitionList.java b/list/PartitionList.java new file mode 100644 index 0000000..683e17d --- /dev/null +++ b/list/PartitionList.java @@ -0,0 +1,51 @@ +package Algorithms.list; + +import Algorithms.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class PartitionList { + public ListNode partition(ListNode head, int x) { + // the list which is greater than or equal to x + ListNode dummyGE = new ListNode(0); + + // the list which is less than x + ListNode dummyLess = new ListNode(0); + + // link the dummy to the head; + dummyGE.next = head; + + ListNode pre = dummyGE; + + ListNode tailLess = dummyLess; + + // go through the list and remove the small node to a new list. + while (pre.next != null) { + if (pre.next.val < x) { + // Add this to the less list. + tailLess.next = pre.next; + tailLess = tailLess.next; + + // remove the node from the current list. + pre.next = pre.next.next; + } else { + // move the pre node forward. + pre = pre.next; + } + } + + // link the LESS list and the Large list. + tailLess.next = dummyGE.next; + + return dummyLess.next; + } +} From 0060c07292309dc2309a7923c63b2b5b4899740b Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sat, 11 Oct 2014 00:44:38 -0700 Subject: [PATCH 60/66] rotate --- list/RotateList.java | 63 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 list/RotateList.java diff --git a/list/RotateList.java b/list/RotateList.java new file mode 100644 index 0000000..f45f708 --- /dev/null +++ b/list/RotateList.java @@ -0,0 +1,63 @@ +package Algorithms.list; + +import Algorithms.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class RotateList { + public ListNode rotateRight(ListNode head, int n) { + if (head == null) { + return null; + } + + // when the list rotate n, it will go back. + n = n % getlen(head); + + ListNode dummy = new ListNode(0); + dummy.next = head; + + // get the pre node before the node which is the new head; + // for example: Given 1->2->3->4->5->NULL and k = 2, + // we should find 3 + // return 4->5->1->2->3->NULL. + ListNode tail = dummy; + while (n > 0) { + tail = tail.next; + n--; + } + + ListNode pre = dummy; + while (tail != null && tail.next != null) { + tail = tail.next; + pre = pre.next; + } + + // cut the two list and connect the head to the tail. + tail.next = dummy.next; + + ListNode headNew = pre.next; + pre.next = null; + + return headNew; + } + + // get the list lenght. + public int getlen(ListNode head) { + int len = 0; + while (head != null) { + len++; + head = head.next; + } + + return len; + } +} From 72e5ddfefe06db57fc26bc7644c62aa34581a13b Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sat, 11 Oct 2014 01:06:34 -0700 Subject: [PATCH 61/66] list --- list/RemoveNthFromEnd.java | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 list/RemoveNthFromEnd.java diff --git a/list/RemoveNthFromEnd.java b/list/RemoveNthFromEnd.java new file mode 100644 index 0000000..72296f9 --- /dev/null +++ b/list/RemoveNthFromEnd.java @@ -0,0 +1,45 @@ +package Algorithms.list; + +import Algorithms.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class RemoveNthFromEnd { + public ListNode removeNthFromEnd(ListNode head, int n) { + if (head == null) { + return null; + } + + ListNode dummy = new ListNode(0); + dummy.next = head; + + // move tail N nodes faster than pre. + ListNode tail = dummy; + // 注意,这里用for比较好一点,用while时,经常不记得将参量-- + for (int i = n; i > 0; i--) { + tail = tail.next; + } + + ListNode pre = dummy; + + // get the node before the node we want to delete. + while (tail != null && tail.next != null) { + tail = tail.next; + pre = pre.next; + } + + // DELTE. + pre.next = pre.next.next; + + return dummy.next; + } +} \ No newline at end of file From cfdbfe8ccf01d33b482da435cb245fd8a471c285 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sat, 11 Oct 2014 01:18:46 -0700 Subject: [PATCH 62/66] remove --- list/RemoveNthFromEnd.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/list/RemoveNthFromEnd.java b/list/RemoveNthFromEnd.java index 72296f9..cdf728c 100644 --- a/list/RemoveNthFromEnd.java +++ b/list/RemoveNthFromEnd.java @@ -38,7 +38,9 @@ public ListNode removeNthFromEnd(ListNode head, int n) { } // DELTE. - pre.next = pre.next.next; + if (pre.next != null) { + pre.next = pre.next.next; + } return dummy.next; } From 732d38a89b46c85f4a0b2a59780889d1bea3d75c Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sat, 11 Oct 2014 01:48:46 -0700 Subject: [PATCH 63/66] list --- list/MergeKLists.java | 63 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 list/MergeKLists.java diff --git a/list/MergeKLists.java b/list/MergeKLists.java new file mode 100644 index 0000000..fc90fa1 --- /dev/null +++ b/list/MergeKLists.java @@ -0,0 +1,63 @@ +package Algorithms.list; + +import java.util.Comparator; +import java.util.List; +import java.util.PriorityQueue; + +import Algorithms.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class MergeKLists { + public ListNode mergeKLists(List lists) { + // 注意:lists.size() == 0 一定要处理,否则建立queue时 不能输入初始size为0 + if (lists == null || lists.size() == 0) { + return null; + } + + Comparator comparator = new Comparator() { + public int compare(ListNode o1, ListNode o2) { + return o1.val - o2.val; + } + }; + + // create a priority Queue. + PriorityQueue q = new PriorityQueue(lists.size(), comparator); + + // add all the first nodes to the QUEUE. + for (ListNode node: lists) { + if (node != null) { + // don't add EMPTY lists. + q.offer(node); + } + } + + ListNode dummy = new ListNode(0); + ListNode tail = dummy; + + while (!q.isEmpty()) { + // get a list node from the queue. + ListNode node = q.poll(); + + // add the node to the result link. + tail.next = node; + tail = tail.next; + + // add a new node from the lists to the priority queue. + if (node.next != null) { + q.offer(node.next); + } + } + + return dummy.next; + } +} From 53f429f69d4c2fba0207b53e2c7bb13310ea1fc5 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sat, 11 Oct 2014 03:08:12 -0700 Subject: [PATCH 64/66] tree --- tree/PathSum2.java | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 tree/PathSum2.java diff --git a/tree/PathSum2.java b/tree/PathSum2.java new file mode 100644 index 0000000..6618f6f --- /dev/null +++ b/tree/PathSum2.java @@ -0,0 +1,47 @@ +package Algorithms.tree; + +import java.util.ArrayList; +import java.util.List; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class PathSum2 { + public List> pathSum(TreeNode root, int sum) { + List> ret = new ArrayList>(); + + ArrayList path = new ArrayList(); + + pathSumHelp(root, sum, path, ret); + + return ret; + } + + public void pathSumHelp(TreeNode root, int sum, ArrayList path, List> ret) { + if (root == null) { + return; + } + + path.add(root.val); + + if (root.left == null + && root.right == null + && root.val == sum) { + ret.add(new ArrayList(path)); + } else { + // 继续递归 + pathSumHelp(root.left, sum - root.val, path, ret); + pathSumHelp(root.right, sum - root.val, path, ret); + } + + // 注意,递归和回溯的特点就是 递归不可以改变path的值。也就是说,你返回时,这个path不能被改变 + // 所以在这里要执行remove操作。 + path.remove(path.size() - 1); + } +} \ No newline at end of file From 1693ac260b6cc6ce56c6bf7cb82b847fdfa631b7 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sat, 11 Oct 2014 03:52:24 -0700 Subject: [PATCH 65/66] candy --- dp/Candy.java | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 dp/Candy.java diff --git a/dp/Candy.java b/dp/Candy.java new file mode 100644 index 0000000..0f0a40d --- /dev/null +++ b/dp/Candy.java @@ -0,0 +1,36 @@ +package Algorithms.dp; + +public class Candy { + public int candy(int[] ratings) { + if (ratings == null || ratings.length == 0) { + return 0; + } + + int len = ratings.length; + int[] candys = new int[len]; + + // go from the left side to the right side and give them candys. + candys[0] = 1; + for (int i = 1; i < len; i++) { + if (ratings[i] > ratings[i - 1]) { + candys[i] = candys[i - 1] + 1; + } else { + candys[i] = 1; + } + } + + for (int i = len - 2; i >= 0; i--) { + if (ratings[i] > ratings[i + 1]) { + int num = candys[i + 1] + 1; + candys[i] = Math.max(candys[i], num); + } + } + + int sum = 0; + for (int i: candys) { + sum += i; + } + + return sum; + } +} From 7a80b4624546070af1d87069f6fa3805dda7bb58 Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Sat, 11 Oct 2014 14:22:03 -0700 Subject: [PATCH 66/66] combine --- combination/Combinations.java | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 combination/Combinations.java diff --git a/combination/Combinations.java b/combination/Combinations.java new file mode 100644 index 0000000..54a7b7d --- /dev/null +++ b/combination/Combinations.java @@ -0,0 +1,41 @@ +package Algorithms.combination; + +import java.util.ArrayList; +import java.util.List; + +public class Combinations { + public List> combine(int n, int k) { + List> ret = new ArrayList>(); + + if (n == 0 || k == 0) { + return ret; + } + + List path = new ArrayList(); + + combine(n, k, path, ret, 1); + + return ret; + } + + // index means the position which I can choose from. + // for example: when n = 4, + // 1, 2, 3, 4, and index = 1, means now I can choose a number from 1 - 4 + // + public void combine(int n, int k, List path, List> ret, int index) { + if (0 == k) { + ret.add(new ArrayList(path)); + return; + } + + // 注意这里的终止条件. + // For example: N = 4的时候,K = 2的时候, + // 这里还有2个可以取值,那么 1, 2, 3, 4中index最多可以从3取值,也就是4-2+1. + // 就是 n - k + 1 + for (int i = index; i <= n - k + 1; i++) { + path.add(i); + combine(n, k - 1, path, ret, i + 1); + path.remove(path.size() - 1); + } + } +} \ No newline at end of file