diff --git a/Ag.java b/Ag.java deleted file mode 100644 index b9746d6..0000000 --- a/Ag.java +++ /dev/null @@ -1,7 +0,0 @@ -package Algorithms; - - - -abstract public class Ag { - -} diff --git a/ListNodeDemo.java b/ListNodeDemo.java index 48bdae6..75bd1bb 100644 --- a/ListNodeDemo.java +++ b/ListNodeDemo.java @@ -58,10 +58,15 @@ public static void main(String[] args) { ListNode c2 = new ListNode(12); c1.next = c2; c2.next = n1; + //c2.next = c1; - //ListNode mergeNode = mergeSortedListRec(m1, c1); + ListNode mergeNode = mergeLink(m1, c1); + //ListNode mergeNode2 = mergeLink(m1, c1); //ListNode mergeNode = mergeSortedList(m1, c1); - //printList(mergeNode); + printList(mergeNode); + //printList(mergeNode2); + + System.out.println(); n1.next = n2; n2.next = n3; @@ -110,6 +115,7 @@ public static void main(String[] args) { System.out.println(isIntersect(n1, c1)); + System.out.println("TEST the getFirstCommonNode:"); ListNode cross = getFirstCommonNode(n1, c1); if (cross == null) { System.out.println("null"); @@ -433,6 +439,42 @@ public static ListNode mergeSortedList(ListNode head1, ListNode 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; + } + /* * 先完成的算法,应该会简单一点儿。 * 简直是优雅的算法啊!太棒了!只不过 为什么自己很难想出这么棒的算法呢? @@ -582,7 +624,9 @@ public static ListNode hasCycleRetNode(ListNode head) { * 2. 有环的情况 * (1). 交点在环上 * 这样子的话,实际上我们可以求出2个交点。我们只要判断2个交点是不是相等。不相等,把2个交点返回任何一个。 - * (2). 交点不在环上,则计算出环的交点,然后len1 = 起点至环的交点,len2 = 起点至环的交点,然后如方法1相同的做法。 + * 相等也是返回任何一个。 + * (2). 交点不在环上,则计算出环的交点,然后len1 = 起点至环的交点,len2 = 起点至环的交点,然后如方法1相同的做法。 + * 这段代码没写咯 */ public static ListNode getFirstCommonNode(ListNode head1, ListNode head2) { if (head1 == null || head2 == null) { @@ -610,14 +654,17 @@ public static ListNode getFirstCommonNode(ListNode head1, ListNode head2) { } } - while (head1 != null) { - if (head1.next == head2.next) { - return head1.next; + while (head1 != null && head2 != null) { + if (head1 == head2) { + return head1; } + head1 = head1.next; + head2 = head2.next; } return null; } else if (cross1 != null && cross2 != null) { + // 这一段没怎么写咯 return cross1; } diff --git a/PostOrder.java b/PostOrder.java deleted file mode 100644 index 491b9b9..0000000 --- a/PostOrder.java +++ /dev/null @@ -1,94 +0,0 @@ -package Algorithms; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.Stack; - - -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/README.md b/README.md new file mode 100644 index 0000000..7e98c30 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +LeetCode_algorithm +================== + +包括LeetCode的解答(目前还不完整,大概有一半左右)
+ +目录划分: + +algorithm ---- 包含除LeetCode以外的其它算法,如面经等。除了这个目录以外都是LeetCode +  -- interviews 面经 +  -- facebook 各公司的面经 + +array ---------- leetcode array 相关 +combination -- leetcode 组合相关 +... etc diff --git a/ReverseString.java b/ReverseString.java deleted file mode 100644 index 2e4c41d..0000000 --- a/ReverseString.java +++ /dev/null @@ -1,5 +0,0 @@ -package Algorithms; - -public class ReverseString { - -} diff --git a/SingleNumber2.java b/SingleNumber2.java deleted file mode 100644 index b34c5af..0000000 --- a/SingleNumber2.java +++ /dev/null @@ -1,5 +0,0 @@ -package Algorithms; - -public class SingleNumber2 { - -} diff --git a/TreeLinkNode.java b/TreeLinkNode.java deleted file mode 100644 index 822615e..0000000 --- a/TreeLinkNode.java +++ /dev/null @@ -1,6 +0,0 @@ -package Algorithms; -public class TreeLinkNode { - int val; - TreeLinkNode left, right, next; - TreeLinkNode(int x) { val = x; } -} \ No newline at end of file diff --git a/algorithm/NChapter/findKthNumber/FindKthNumber.java b/algorithm/NChapter/findKthNumber/FindKthNumber.java new file mode 100644 index 0000000..3e01052 --- /dev/null +++ b/algorithm/NChapter/findKthNumber/FindKthNumber.java @@ -0,0 +1,75 @@ +package Algorithms.algorithm.NChapter.findKthNumber; + +import java.util.Arrays; + +/* + * Version 1: The pivot is in the left. + * */ + +public class FindKthNumber { + public static void main(String[] strs) { + int[] A1 = new int[]{1,6,9,2,3,5}; + FindKthNumber find = new FindKthNumber(); + int rst = find.findKthNumber(A1, 5); + System.out.println(rst); + + System.out.println("after find"); + for (int i = 0; i < A1.length; i++) { + System.out.print(A1[i]); + System.out.print(" "); + } + + System.out.println(); + + Arrays.sort(A1); + System.out.println("After sort"); + for (int i = 0; i < A1.length; i++) { + System.out.print(A1[i]); + System.out.print(" "); + } + } + + public int findKthNumber(int A[], int k) { + + return findKthNumberHelp(A, A.length + 1 - k, 0, A.length - 1); + } + + public int findKthNumberHelp(int A[], int k, int start, int end) { + int left = start; + int right = end; + int pivot = left; + + while (left <= right) { + while (left <= right && A[left] <= A[pivot]) { + left++; + } + + while (left <= right && A[right] >= A[pivot]) { + right--; + } + + if (left < right) { + swap(A, left, right); + } + } + + swap(A, pivot, right); + + if (right + 1 == k) { + return A[right]; + } + + if (right + 1 > k) { + // find in the left side. + return findKthNumberHelp(A, k, start, right - 1); + } else { + return findKthNumberHelp(A, k, right + 1, end); + } + } + + private void swap(int A[], int one, int two) { + int tmp = A[one]; + A[one] = A[two]; + A[two] = tmp; + } +} diff --git a/FindKthNumber.java b/algorithm/NChapter/findKthNumber/FindMedianSortedArrays.java similarity index 83% rename from FindKthNumber.java rename to algorithm/NChapter/findKthNumber/FindMedianSortedArrays.java index 20c1f3e..743df47 100644 --- a/FindKthNumber.java +++ b/algorithm/NChapter/findKthNumber/FindMedianSortedArrays.java @@ -1,18 +1,15 @@ -package Algorithms; +package Algorithms.algorithm.NChapter.findKthNumber; -public class FindKthNumber { +public class FindMedianSortedArrays { public static void main(String[] str) { int A[] = {1,2,3,3}; int B[] = {3,3,7,8}; - FindKthNumber fn = new FindKthNumber(); - double ret = fn.findMedianSortedArrays(A, B); + double ret = findMedianSortedArrays(A, B); System.out.println(ret); } - public double findMedianSortedArrays(int A[], int B[]) { - int len = A.length + B.length; - + public static double findMedianSortedArrays(int A[], int B[]) { double ret = findKth(A, 0, B, 0, 6); return ret; diff --git a/algorithm/NChapter/findKthNumber/KthLargestElement_lintCode.java b/algorithm/NChapter/findKthNumber/KthLargestElement_lintCode.java new file mode 100644 index 0000000..0d056c3 --- /dev/null +++ b/algorithm/NChapter/findKthNumber/KthLargestElement_lintCode.java @@ -0,0 +1,67 @@ +package Algorithms.algorithm.NChapter.findKthNumber; + +import java.util.ArrayList; + +// The link: + +// http://www.lintcode.com/en/problem/kth-largest-element/ + +class KthLargestElement_lintCode { + //param k : description of k + //param numbers : array of numbers + //return: description of return + public int kthLargestElement(int k, ArrayList numbers) { + // write your code here + if (k < 1 || numbers == null) { + return 0; + } + + return getKth(numbers.size() - k + 1, numbers, 0, numbers.size() - 1); + } + + public int getKth(int k, ArrayList numbers, int start, int end) { + // Choose the last one as the pivot + int pivot = numbers.get(end); + + int left = start; + int right = end; + + while (true) { + while (numbers.get(left) < pivot && left < right) { + left++; + } + + while (numbers.get(right) >= pivot && right > left) { + right--; + } + + if (left == right) { + break; + } + + swap(numbers, left, right); + } + + // left: the first one which is bigger than pivot. + swap(numbers, left, end); + + if (k == left + 1) { + return pivot; + // Try to find the element from the left side. + } else if (k < left + 1) { + return getKth(k, numbers, start, left - 1); + } else { + // Try to find the element from the right side. + return getKth(k, numbers, left + 1, end); + } + } + + /* + Swap the two nodes. + */ + public void swap(ArrayList numbers, int n1, int n2) { + int tmp = numbers.get(n1); + numbers.set(n1, numbers.get(n2)); + numbers.set(n2, tmp); + } +}; diff --git a/KthLargestElement.java b/algorithm/NChapter/findKthNumber/KthLargestElement_lintCode_v1.java similarity index 88% rename from KthLargestElement.java rename to algorithm/NChapter/findKthNumber/KthLargestElement_lintCode_v1.java index 6bd6c34..6246913 100644 --- a/KthLargestElement.java +++ b/algorithm/NChapter/findKthNumber/KthLargestElement_lintCode_v1.java @@ -1,13 +1,16 @@ -package Algorithms; +package Algorithms.algorithm.NChapter.findKthNumber; import java.util.ArrayList; -import java.util.Collections; -class KthLargestElement { +/* + * LintCode Version 1: Use arrays to solve it. + * */ + +class KthLargestElement_lintCode_v1 { //param k : description of k //param numbers : array of numbers //return: description of return public static void main(String[] strs) { - KthLargestElement Kth = new KthLargestElement(); + KthLargestElement_lintCode_v1 Kth = new KthLargestElement_lintCode_v1(); ArrayList numbers = new ArrayList(); numbers.add(9); numbers.add(3); @@ -23,7 +26,6 @@ public int kthLargestElement(int k, ArrayList numbers) { // write your code here Integer[] num = new Integer[numbers.size()]; numbers.toArray(num); - //Integer[] num = numbers.toArray(new Integer[0]); return findKthNumberHelp(num, num.length + 1 - k, 0, num.length - 1); } diff --git a/algorithm/dp/FindLargeCommonLine.java b/algorithm/dp/FindLargeCommonLine.java new file mode 100644 index 0000000..32b0474 --- /dev/null +++ b/algorithm/dp/FindLargeCommonLine.java @@ -0,0 +1,70 @@ +package Algorithms.algorithm.dp; + +import java.util.ArrayList; + +public class FindLargeCommonLine { + public static void main(String[] str) { + int[][] input = { + {0, 1}, + {1, 0} + }; + + System.out.println(find(input)); + } + + public static class DpType { + ArrayList set0; + ArrayList set1; + int max0; + int max1; + + public DpType(int max0, int max1) { + super(); + this.set0 = new ArrayList(); + this.set1 = new ArrayList(); + this.max0 = max0; + this.max1 = max1; + } + } + + public static int find(int[][] input) { + if (input == null || input.length == 0 || input[0].length == 0) { + return 0; + } + + int rows = input.length; + int cols = input[0].length; + + // create a DP + int[] max1 = new int[cols]; + int[] max0 = new int[cols]; + + // initate to be one, means the first line. + int maxLine1 = 1; + int maxLine0 = 1; + + for (int i = 0; i < cols; i++) { + if (input[0][i] == 0) { + // no change. + max0[i] = 0; + + // should reverse. + max1[i] = 1; + } else { + max0[i] = 1; + max1[i] = 0; + } + } + + // Dp from the 2nd line to the last. + for (int i = 1; i < rows; i++) { + boolean is0 = true; + for (int j = 0; j < cols; j++) { + //if (input[]) + } + } + + return 0; + } + +} diff --git a/algorithm/dp/LongestPalindrome_dp1.java b/algorithm/dp/LongestPalindrome_dp1.java new file mode 100644 index 0000000..239606f --- /dev/null +++ b/algorithm/dp/LongestPalindrome_dp1.java @@ -0,0 +1,98 @@ +package Algorithms.algorithm.dp; + +public class LongestPalindrome_dp1 { + public static void main(String[] args) { + String s = "cabaabad"; + System.out.println(longestPalindrome(s)); + } + + // Solution 1: + public static String longestPalindrome1(String s) { + if (s == null) { + return null; + } + + int len = s.length(); + + // Record i-j is a palindrome. + boolean[][] D = new boolean[len][len]; + for (int i = 0; i < len; i++) { + for (int j = 0; j < len; j++) { + D[i][j] = false; + } + } + + int max = 0; + int retB = 0; + int retE = 0; + for (int j = 0; j < len; j++) { + for (int i = 0; i <= j; i++) { + if (s.charAt(i) == s.charAt(j) + && (j - i <= 3 || D[i + 1][j - 1]) + ) { + D[i][j] = true; + + if (j - i + 1 > max) { + retB = i; + retE = j; + } + } else { + D[i][j] = false; + } + } + } + + return s.substring(retB, retE + 1); + } + + // solution 2: ��������������������������������������������������������������������������������������������������������� + // ������������N^2 ���������inplace������������������O(1) + public static String longestPalindrome(String s) { + if (s == null) { + return null; + } + + int len = s.length(); + + if (len <= 0) { + return ""; + } + + int max = 0; + String ret = ""; + + for (int i = 0; i < len; i++) { + // ��������������������� + String s1 = expandAround(s, i, i); + if (s1.length() > max) { + ret = s1; + max = s1.length(); + } + + // ������������������������������ + String s2 = expandAround(s, i, i); + if (s2.length() > max) { + ret = s2; + max = s2.length(); + } + } + + return ret; + } + + public static String expandAround(String s, int c1, int c2) { + int len = s.length(); + + while (c1 >= 0 && c2 <= len - 1) { + if (s.charAt(c1) != s.charAt(c2)) { + break; + } + + c1++; + c2--; + } + + // ��������������� substring������������c2���������1 + return s.substring(c1 + 1, c2); + } +} diff --git a/algorithm/dp/MinAdjustmentCost_Class.java b/algorithm/dp/MinAdjustmentCost_Class.java new file mode 100644 index 0000000..4fd11e7 --- /dev/null +++ b/algorithm/dp/MinAdjustmentCost_Class.java @@ -0,0 +1,243 @@ +package Algorithms.algorithm.dp; + +import java.util.ArrayList; + +public class MinAdjustmentCost_Class { + public static void main(String[] strs) { + ArrayList A = new ArrayList(); + A.add(1); + A.add(4); + A.add(2); + A.add(3); + + System.out.println(MinAdjustmentCost1(A, 1)); + } + + /** + * @param A: An integer array. + * @param target: An integer. + */ + public static int MinAdjustmentCost1(ArrayList A, int target) { + // write your code here + if (A == null) { + return 0; + } + + ArrayList B = new ArrayList(); + for (int i = 0; i < A.size(); i++) { + B.add(0); + } + + return rec(A, B, target, 0); + } + + /* + * SOL 1: + * 最普通的递归方法。 + * */ + public static int rec(ArrayList A, ArrayList B, int target, int index) { + int len = A.size(); + if (index >= len) { + // The index is out of range. + return 0; + } + + int dif = 0; + + int min = Integer.MAX_VALUE; + + // If this is the first element, it can be from 1 to 100; + for (int i = 0; i <= 100; i++) { + if (index != 0 && Math.abs(i - B.get(index - 1)) > target) { + continue; + } + + B.set(index, i); + dif = Math.abs(i - A.get(index)); + dif += rec(A, B, target, index + 1); + min = Math.min(min, dif); + + // 回溯 + //B.set(index, A.get(index)); + } + + return min; + } + + /* + * 递归2: + * Rec + memory. + * */ + /** + * @param A: An integer array. + * @param target: An integer. + */ + public static int MinAdjustmentCost2(ArrayList A, int target) { + // write your code here + if (A == null || A.size() == 0) { + return 0; + } + + int[][] M = new int[A.size()][100]; + for (int i = 0; i < A.size(); i++) { + for (int j = 0; j < 100; j++) { + M[i][j] = Integer.MAX_VALUE; + } + } + + return rec2(A, new ArrayList(A), target, 0, M); + } + + public static int rec2(ArrayList A, ArrayList B, int target, int index, + int[][] M) { + int len = A.size(); + if (index >= len) { + // The index is out of range. + return 0; + } + + int dif = 0; + int min = Integer.MAX_VALUE; + + // If this is the first element, it can be from 1 to 100; + for (int i = 1; i <= 100; i++) { + if (index != 0 && Math.abs(i - B.get(index - 1)) > target) { + continue; + } + + if (M[index][i - 1] != Integer.MAX_VALUE) { + dif = M[index][i - 1]; + min = Math.min(min, dif); + continue; + } + + B.set(index, i); + dif = Math.abs(i - A.get(index)); + dif += rec2(A, B, target, index + 1, M); + + min = Math.min(min, dif); + + // Record the result. + M[index][i - 1] = dif; + + // 回溯 + B.set(index, A.get(index)); + } + + return min; + } + + /* + * SOLUTION 3 递归2: + * Rec + memory. + * 改进的递归版本 + * */ + /** + * @param A: An integer array. + * @param target: An integer. + */ + public static int MinAdjustmentCost3(ArrayList A, int target) { + // write your code here + if (A == null || A.size() == 0) { + return 0; + } + + int[][] M = new int[A.size()][100]; + for (int i = 0; i < A.size(); i++) { + for (int j = 0; j < 100; j++) { + M[i][j] = Integer.MAX_VALUE; + } + } + + // 首个数字可以取1-100 + int min = Integer.MAX_VALUE; + for (int i = 1; i <= 100; i++) { + min = Math.min(min, rec3(A, target, 0, i, M)); + } + + return min; + } + + /* + * 将当前值设置为x能求得的最小解 + * */ + public static int rec3(ArrayList A, int target, int index, int x, + int[][] M) { + int len = A.size(); + if (index >= len) { + // The index is out of range. + return 0; + } + + if (M[index][x - 1] != Integer.MAX_VALUE) { + return M[index][x - 1]; + } + + int bas = Math.abs(x - A.get(index)); + int min = Integer.MAX_VALUE; + + // 对下一个值尝试取1-100 + for (int i = 1; i <= 100; i++) { + // 下一个值的取值不可以超过abs + if (index != len - 1 && Math.abs(i - x) > target) { + continue; + } + + // 计算dif + int dif = bas + rec3(A, target, index + 1, i, M); + min = Math.min(min, dif); + } + + // Record the result. + M[index][x - 1] = min; + return min; + } + + + /* + * SOLUTION 4: + * DP + * */ + /** + * @param A: An integer array. + * @param target: An integer. + */ + public static int MinAdjustmentCost(ArrayList A, int target) { + // write your code here + if (A == null || A.size() == 0) { + return 0; + } + + // D[i][v]: 把index = i的值修改为v,所需要的最小花费 + int[][] D = new int[A.size()][101]; + + int size = A.size(); + + for (int i = 0; i < size; i++) { + for (int j = 1; j <= 100; j++) { + D[i][j] = Integer.MAX_VALUE; + if (i == 0) { + // The first element. + D[i][j] = Math.abs(j - A.get(i)); + } else { + for (int k = 1; k <= 100; k++) { + // 不符合条件 + if (Math.abs(j - k) > target) { + continue; + } + + int dif = Math.abs(j - A.get(i)) + D[i - 1][k]; + D[i][j] = Math.min(D[i][j], dif); + } + } + } + } + + int ret = Integer.MAX_VALUE; + for (int i = 1; i <= 100; i++) { + ret = Math.min(ret, D[size - 1][i]); + } + + return ret; + } +} diff --git a/algorithm/dp/MinPath_Block.java b/algorithm/dp/MinPath_Block.java new file mode 100644 index 0000000..17078b0 --- /dev/null +++ b/algorithm/dp/MinPath_Block.java @@ -0,0 +1,5 @@ +package Algorithms.algorithm.dp; + +public class MinPath_Block { + +} diff --git a/algorithm/interviews/facebook/SortWeight.java b/algorithm/interviews/facebook/SortWeight.java new file mode 100644 index 0000000..bd15e74 --- /dev/null +++ b/algorithm/interviews/facebook/SortWeight.java @@ -0,0 +1,193 @@ +package Algorithms.algorithm.interviews.facebook; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +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 = sortWeight2(input1); + LinkedList list2 = sortWeight2(input2); + LinkedList list3 = sortWeight2(input3); + LinkedList list4 = sortWeight2(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; + + + String food = null; + float weight = 0; + + // 使用hashmap来记录food-weight 对 + HashMap> map = new HashMap>(); + + // Go through the string. + for (String s: strs) { + // 这是第一对食物-重量对 + 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 class Pair implements Comparable { + String food; + float weight; + + Pair (String food, float weight) { + this.food = food; + this.weight = weight; + } + + // 这样子写会达成反序的效果 + public int compareTo(Pair o) { + if (o.weight - this.weight < 0) { + return -1; + } + + return 1; + } + } + + /* + * 实现方法2:自定义一个Pair数据类型,并且用compare来自动排序 + * */ + public static LinkedList sortWeight2(String input) { + LinkedList ret = new LinkedList(); + if (input == null) { + return ret; + } + + String[] strs = input.split(" "); + + float defautWeight = 5; + + + String food = null; + float weight = 0; + + // 创建一个空的食物-weight 链 + ArrayList list = new ArrayList(); + + // Go through the string. + for (String s: strs) { + // 首个食物-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)); + + // 开始新一轮的食物-weight链 + 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) { + // 检查 在map中是否存在 + 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/algorithm/interviews/pocketGem/FindKthFrequency.java b/algorithm/interviews/pocketGem/FindKthFrequency.java new file mode 100644 index 0000000..3585cda --- /dev/null +++ b/algorithm/interviews/pocketGem/FindKthFrequency.java @@ -0,0 +1,107 @@ +package Algorithms.algorithm.interviews.pocketGem; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map.Entry; +import java.util.PriorityQueue; +import java.util.Set; + +/* + * Input: int[] A = {1, 1, 2, 3, 4, 5, 2}; k = 3 + * return the highest frequency numbers. + * return: [1, 2, 3] or [1, 2, 4] or [1, 2, 5] + * */ + +public class FindKthFrequency { + public static void main(String[] strs) { + int[] A = {1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 4, 5, 7, 2}; + System.out.println(findKthFrenquency(A, 3).toString()); + } + + /* + * Solution 1: + * 对HashMap Sort. + * Complexity: O(NLogN) + * */ + public static Set findKthFrenquency1(int[] input, int k) { + HashSet set = new HashSet(); + HashMap map = new HashMap(); + for (int num: input) { + if (map.containsKey(num)) { + map.put(num, map.get(num) + 1); + } else { + map.put(num, 1); + } + } + + ArrayList> list = new ArrayList>(map.entrySet()); + + Collections.sort(list, new Comparator>() { + public int compare(Entry o1, Entry o2) { + return o2.getValue() - o1.getValue(); + } + }); + + for (int i = 0; i < k; i++) { + set.add(list.get(i).getKey()); + } + + return set; + } + + /* + * Solution 2: + * Use TreeMap. + * */ + public static Set findKthFrenquency2(int[] input, int k) { + HashSet set = new HashSet(); + + return set; + } + + /* + * Solution 3: + * Use The priority queue. + * */ + public static List findKthFrenquency(int[] input, int k) { + LinkedList list = new LinkedList(); + + HashMap map = new HashMap(); + for (int num: input) { + if (map.containsKey(num)) { + map.put(num, map.get(num) + 1); + } else { + map.put(num, 1); + } + } + + PriorityQueue> q = new PriorityQueue>(k + 1, new Comparator>(){ + public int compare(Entry o1, Entry o2) { + return o1.getValue() - o2.getValue(); + } + }); + + for (Entry entry: map.entrySet()) { + if (q.size() == k + 1) { + // Delete the smallest element from the queue. + q.poll(); + } + q.offer(entry); + } + + // delete one small element + q.poll(); + + while (!q.isEmpty()) { + Entry entry = q.poll(); + list.addFirst(entry.getKey()); + } + + return list; + } +} diff --git a/algorithm/interviews/uber/Example.java b/algorithm/interviews/uber/Example.java new file mode 100644 index 0000000..bd1c1e1 --- /dev/null +++ b/algorithm/interviews/uber/Example.java @@ -0,0 +1,1091 @@ +package Algorithms.algorithm.interviews.uber; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; + +import Algorithms.tree.TreeNode; +public class Example { + public static void main(String[] strs) throws NoSuchAlgorithmException { +// printArray(sqrt2(100)); +// printArray(sqrt2(300)); +// printArray(sqrt2(400)); +// printArray(sqrt2(1)); +// printArray(sqrt2(0)); +// printArray(sqrt2(-4)); + +// int start = 1; +// for (int i = 0; i < 1000; i++) { +// System.out.print(start + " "); +// start = getNextPrime2(start); +// } + +// List records = new ArrayList(); +// records.add(new Record("a", 0, 2)); +// records.add(new Record("a", 1, 3)); +// records.add(new Record("a", 3, 5)); +// records.add(new Record("a", 2, 4)); +// records.add(new Record("a", 3, 5)); +// records.add(new Record("a", 4, 8)); +// records.add(new Record("a", 5, 10)); +// +// List ret = countRecord2(records); +// +// for (LogResult logRet: ret) { +// System.out.println(logRet.time + " " + logRet.number_of_users); +// } +// +// System.out.println(findPeak2(records)); + +// int[] A = {-1,0,1,2,3,5,8,9}; +// System.out.println(findIndex2(A)); +// +// int[] A3 = {0,0,1,2,3,5,8,9}; +// System.out.println(findIndex3(A3)); +// +// System.out.println(stringShift2("abC", 24)); +// +// ArrayList list = new ArrayList(); +// list.add("cba"); +// list.add("abc"); +// list.add("bcd"); +// list.add("dogs"); +// list.add("xyz"); +// list.add("zab"); +// list.add("c"); +// list.add("d"); +// getSame(list); + System.out.println(getShort("www.uber.com")); + + System.out.println(getFullUrl("f626cf")); + + TreeNode root = new TreeNode(1); + TreeNode node1 = new TreeNode(5); + TreeNode node2 = new TreeNode(6); + TreeNode node3 = new TreeNode(4); + + TreeNode node4 = new TreeNode(3); + TreeNode node5 = new TreeNode(2); + TreeNode node6 = new TreeNode(1); + + root.left = node1; + root.right = node2; + + root.left.left = node3; + + node2.left = node4; + node2.right = node5; + + node5.right = node6; + + System.out.println(getPath(root, 10)); + } + + static HashMap map = new HashMap(); + static HashMap mapFull = new HashMap(); + + public static void printArray(int[] in) { + for (int i = 0; i < in.length; i++) { + System.out.print(in[i] + " "); + } + + System.out.println(); + } + + /* sqrt(100) => 10,1 , sqrt(300) => 10,3 300 = 10^2 * 3 */ + // Running time: O(sqrt(n)) + public static int[] sqrt(int num){ + int[] rst = {-1,-1}; + + if (num < 0){// edge case + return rst; + } + + int n = (int) Math.sqrt(num); + while (n >= 1){ + if (num % (n*n) == 0){ + rst[0] = n; + rst[1] = num/(n*n); + return rst; + } + n--; + } + return rst; + } + + // Author: Yu Zhang. + public static int[] sqrt2(int n) { + int[] rst = {-1, -1}; + + if (n < 0) { + return rst; + } + + if (n == 0) { + rst[0] = 0; + rst[1] = 0; + return rst; + } + + int sqrNum = (int) Math.sqrt(n); + + //System.out.println("sqrNum:" + sqrNum); + + while (sqrNum >= 1) { + if (n % (sqrNum * sqrNum) == 0) { + rst[0] = n; + rst[1] = n / (sqrNum * sqrNum); + // bug: forget to return. + return rst; + } + + sqrNum--; + } + + return rst; + } + + /* given a number, find the next prime which is bigger than it */ + // Running time: O(nlogm) => m is an average recursion depth for each number, how to optimize it? + public static int getNextPrime(int value){ + if (value <= 1){ + return 2; + } + + int target = value + 1; + + // Yu Zhang optimize. Odds will not be prime. + if (target % 2 == 0) { + target++; + } + + while (!isPrime(target)){ + // Yu Zhang optimize 1: target += 2. + target += 2; + //target++; + } + + return target; + } + + public static boolean isPrime(int target){ + int n = 2; + while (n*n <= target){// may overflow here! + if (target % n == 0){ + return false; + } + n++; + } + return true; + } + + // Yu Zhang solution: + //http://stackoverflow.com/questions/6654671/whats-the-built-in-function-that-finds-next-largest-prime-number-in-java + //https://www.youtube.com/watch?v=nkIt8M9asaM + public static int getNextPrime2 (int val) { + if (val <= 1) { + return 2; + } + + val++; + if (val % 2 == 0) { + val++; + } + + while (!isPrime2(val)) { + val += 2; + if (val < 0) { + return -1; + } + } + + return val; + } + + public static boolean isPrime2(int target){ + int n = 3; + + // yu zhang: use / to avoid overflow. + + int sqrt = (int)Math.sqrt(target); + while (n <= sqrt) { + if (target % n == 0) { + return false; + } + + // bug: should addup n; + // Yu Zhang optimize: target will never be divided by odd. + n += 2; + } + + return true; + } + + public static class Record { + String username; + int log_time; + int logout_time; + public Record(String username, int log_time, int logout_time) { + super(); + this.username = username; + this.log_time = log_time; + this.logout_time = logout_time; + } + } + + public static class LogResult { + int time; + int number_of_users; + + LogResult (int time, int number_of_users) { + this.time = time; + this.number_of_users = number_of_users; + } + } + + /* given many logs , output */ + // use two priority queue: O(2nlogn) ; just sort: O(2nlog2n) + public List countRecord(List records){ + if (records == null || records.size() == 0){ + return new ArrayList(); + } + + List rst = new ArrayList(); + Collections.sort(records, new Comparator(){ + @Override + public int compare(Record o1, Record o2) { + // TODO Auto-generated method stub + return o1.log_time - o2.log_time; + } + }); + + PriorityQueue endheap = new PriorityQueue(records.size(),new Comparator(){ + @Override + public int compare(Integer o1, Integer o2) { + // TODO Auto-generated method stub + return o1-o2; + } + }); + + PriorityQueue startheap = new PriorityQueue(records.size(),new Comparator(){ + @Override + public int compare(Integer o1, Integer o2) { + // TODO Auto-generated method stub + return o1-o2; + } + }); + + int curr,i; + + for (i=0;i 0 || endheap.size() > 0){ + int curr1 = startheap.size() > 0 ? startheap.peek() : -1; + int curr2 = endheap.size() > 0 ? endheap.peek() : -1; + if (curr1 < 0 || curr1 > curr2){// only end time left + while (endheap.size() > 0 && endheap.peek() == curr2){ + curr--; + endheap.poll(); + } + rst.add(new LogResult(curr2,curr)); + } + else if (curr2 < 0 || curr1 < curr2){// go with start time + while (startheap.size() > 0 && startheap.peek() == curr1){ + curr++; + startheap.poll(); + } + rst.add(new LogResult(curr1,curr)); + } + else{// curr1 == curr2 + while (endheap.size() > 0 && endheap.peek() == curr2){ + curr--; + endheap.poll(); + } + while (startheap.size() > 0 && startheap.peek() == curr1){ + curr++; + startheap.poll(); + } + rst.add(new LogResult(curr1,curr)); + } + } + + return rst; + } + + /* given many logs , output */ + // use two priority queue: O(2nlogn) ; just sort: O(2nlog2n) + + // Yu Zhang solution. + public static List countRecord2(List records){ + ArrayList ret = new ArrayList(); + + if (records == null || records.size() == 0){ + return new ArrayList(); + } + + ArrayList timeList = new ArrayList(); + for (Record record: records) { + timeList.add(new LogResult(record.log_time, 1)); + timeList.add(new LogResult(record.logout_time, -1)); + } + + // bug: forget the right way to write comparator. + Collections.sort(timeList, new Comparator(){ + public int compare(LogResult o1, LogResult o2) { + return o1.time - o2.time; + } + }); + + int num = 0; + for (int i = 0; i < timeList.size(); i++) { + num += timeList.get(i).number_of_users; + + if (i == timeList.size() - 1 + || (timeList.get(i).time != timeList.get(i + 1).time)) { + ret.add(new LogResult(timeList.get(i).time, num)); + } + } + + return ret; + } + + // decode ways: 1-26 => 'A'-'Z' + public int numDecodings(String s){ + if (s == null || s.length() == 0){ + return 0; + } + int last = 0; + int curr = s.charAt(0) == '0' ? 0 : 1; + int next = last + curr; + int i,copy = 0; + + for (i = 0;i < s.length();i++){ + next = 0; + if (s.charAt(i) >= '1' && s.charAt(i) <= '9'){ + next = curr; + } + int value = copy*10 + s.charAt(i)-'0'; + + if (value >= 10 && value <= 26){ + next += last; + } + copy = value % 10; + + last = curr; + curr = next; + } + + return next; + } + + // Yu Zhang solution. + public int numDecodings2(String s) { + if (s == null || s.length() == 0) { + return 0; + } + + int len = s.length(); + int[] D = new int[len + 1]; + for (int i = 0; i <= len; i++) { + if (i == 0) { + D[i] = 1; + } else { + D[i] = 0; + if (isValidSingle(s.charAt(i - 1))) { + D[i] += D[i - 1]; + } + + if (i >= 2 && isValidTwo(s.substring(i - 2, i))) { + D[i] += D[i - 2]; + } + } + } + + return D[len]; + } + + public boolean isValidSingle(char c) { + return c != '0'; + } + + public boolean isValidTwo(String s) { + int num = Integer.parseInt(s); + return num <= 26 && num >= 10; + } + + // solution 3: + public int numDecodings3(String s) { + // bug 1: return 0 when len is 0. + if (s == null || s.length() == 0) { + return 0; + } + + int len = s.length(); + + // The result of first i digits. + int pre = 1; + int prepre = 0; + + for (int i = 1; i <= len; i++) { + // i >= 1 + int cur = 0; + if (i >= 2 && isValidTwo(s.substring(i - 2, i))) { + cur += prepre; + } + + // The digit should not be 0. + if (s.charAt(i - 1) != '0') { + cur += pre; + } + + prepre = pre; + pre = cur; + } + + return pre; + } + + // Wordbreak => [lock,locker, erning] ; lockerning : true, lockern : false + public boolean wordBreak(String s, Set dict){ + if (dict == null || s == null || s.length() == 0 || dict.size() == 0){ + return false; + } + int m = s.length(); + int range = 0; + int i,j; + boolean[] dp = new boolean[m+1]; + dp[0] = true; + String curr; + + for (i=1;i<=s.length();i++){ + for (j=0;j dict) { + if(s == null || dict == null) { + return false; + } + + // bug 2: length() + int len = s.length(); + // bug 1: use boolean not int. + boolean[] D = new boolean[len + 1]; + + for (int i = 0; i <= len; i++) { + if (i == 0) { + D[i] = true; + } else { + for (int j = 0; j < i; j++) { + if (D[j] && dict.contains(s.substring(j, i))) { + D[i] = true; + break; + } + } + } + } + + return D[len]; + } + + // find the most plights in the sky + class Point{ + int x; // start time + int y; // end time + + public Point(int x, int y){ + this.x = x; + this.y = y; + } + } + + public int findPeak(List flights){ + if (flights == null || flights.size() == 0){ + return 0; + } + int max = 0,i,curr = 0; + int k = flights.size(); + PriorityQueue startheap = new PriorityQueue(k,new Comparator(){ + @Override + public int compare(Integer o1, Integer o2) { + // TODO Auto-generated method stub + return o1-o2; + } + }); + PriorityQueue endheap = new PriorityQueue(k,new Comparator(){ + @Override + public int compare(Integer o1, Integer o2) { + // TODO Auto-generated method stub + return o1-o2; + } + }); + for (i=0;i flights.get(i).y){// edge case for the input + continue; + } + startheap.offer(flights.get(i).x); + endheap.offer(flights.get(i).y); + } + // get peak points via loop scan + int curr1,curr2; + while (startheap.size() > 0 && endheap.size() > 0){ + curr1 = startheap.peek(); + curr2 = endheap.peek(); + + if (curr1 < curr2){ + while (startheap.size() > 0 && startheap.peek() == curr1){ + curr++; + startheap.poll(); + } + + } + else if (curr2 < curr1){ + while (endheap.size() > 0 && endheap.peek() == curr2){ + curr--; + endheap.poll(); + } + } + else{// curr1 == curr2 + while (startheap.size() > 0 && startheap.peek() == curr1){ + curr++; + startheap.poll(); + } + while (endheap.size() > 0 && endheap.peek() == curr2){ + curr--; + endheap.poll(); + } + } + max = Math.max(max, curr); + } + + return max; + } + + // Yu Zhang solution. + public static int findPeak2(List records){ + ArrayList ret = new ArrayList(); + + if (records == null || records.size() == 0){ + return 0; + } + + ArrayList timeList = new ArrayList(); + for (Record record: records) { + timeList.add(new LogResult(record.log_time, 1)); + timeList.add(new LogResult(record.logout_time, -1)); + } + + // bug: forget the right way to write comparator. + Collections.sort(timeList, new Comparator(){ + public int compare(LogResult o1, LogResult o2) { + return o1.time - o2.time; + } + }); + + int num = 0; + int max = 0; + for (int i = 0; i < timeList.size(); i++) { + num += timeList.get(i).number_of_users; + + if (i == timeList.size() - 1 + || (timeList.get(i).time != timeList.get(i + 1).time)) { + ret.add(new LogResult(timeList.get(i).time, num)); + } + + max = Math.max(max, num); + } + + return max; + } + + /* given many logs , output */ + // use two priorityqueue: O(2nlogn) ; just sort: O(2nlog2n) +// public List countRecord(List records){ +// if (records == null || records.size() == 0){ +// return new ArrayList(); +// } +// List rst = new ArrayList(); +// Collections.sort(records, new Comparator(){ +// @Override +// public int compare(record o1, record o2) { +// // TODO Auto-generated method stub +// return o1.log_time - o2.log_time; +// } +// }); +// PriorityQueue endheap = new PriorityQueue(records.size(),new Comparator(){ +// @Override +// public int compare(Integer o1, Integer o2) { +// // TODO Auto-generated method stub +// return o1-o2; +// } +// }); +// PriorityQueue startheap = new PriorityQueue(records.size(),new Comparator(){ +// @Override +// public int compare(Integer o1, Integer o2) { +// // TODO Auto-generated method stub +// return o1-o2; +// } +// }); +// int curr,i; +// for (i=0;i 0 || endheap.size() > 0){ +// int curr1 = startheap.size() > 0 ? startheap.peek() : -1; +// int curr2 = endheap.size() > 0 ? endheap.peek() : -1; +// if (curr1 < 0 || curr1 > curr2){// only end time left +// while (endheap.size() > 0 && endheap.peek() == curr2){ +// curr--; +// endheap.poll(); +// } +// rst.add(new result(curr2,curr)); +// } +// else if (curr2 < 0 || curr1 < curr2){// go with start time +// while (startheap.size() > 0 && startheap.peek() == curr1){ +// curr++; +// startheap.poll(); +// } +// rst.add(new result(curr1,curr)); +// } +// else{// curr1 == curr2 +// while (endheap.size() > 0 && endheap.peek() == curr2){ +// curr--; +// endheap.poll(); +// } +// while (startheap.size() > 0 && startheap.peek() == curr1){ +// curr++; +// startheap.poll(); +// } +// rst.add(new result(curr1,curr)); +// } +// } +// +// return rst; +// } + + // spiral matrix + public List spiralMatrix(int[][] matrix){ + if (matrix == null || matrix.length == 0){ + return new ArrayList(); + } + List rst = new ArrayList(); + + int m = matrix.length; + int n = matrix[0].length; + int top = 0; + int bottom = m-1; + int left = 0; + int right = n-1; + int i; + int direction = 0; + while (true){ + if (direction == 0){ + for (i=left;i<=right;i++){ + rst.add(matrix[top][i]); + } + top++; + } + else if (direction == 1){ + for (i=top;i<=bottom;i++){ + rst.add(matrix[i][right]); + } + right--; + } + else if (direction == 2){ + for (i=right;i>=left;i--){ + rst.add(matrix[bottom][i]); + } + bottom--; + } + else{ + for (i=bottom;i>=top;i--){ + rst.add(matrix[i][left]); + } + left++; + } + //break + if (left > right || top > bottom){ + break; + } + // switch direction + direction = (direction+1) % 4; + } + + return rst; + } + + // Solution 4: Use Four corners. + // Author: Yu Zhang. + // spiral matrix + public List spiralOrder4(int[][] matrix) { + List ret = new ArrayList(); + if (matrix == null ||matrix.length == 0) { + // 注意在非法的时候,应该返回空解,而不是一个NULL值 + return ret; + } + + // Record how many rows and cols we still have. + int rows = matrix.length; + int cols = matrix[0].length; + + // The four corners. + int top = 0; + int left = 0; + int bottom = rows - 1; + int right = cols - 1; + + // every time we go through two rows and two cols. + for (; rows > 0 && cols > 0; rows -= 2, cols -= 2, top++, left++, bottom--, right--) { + // the first line. + for (int i = left; i <= right; i++) { + ret.add(matrix[top][i]); + } + + // the right column. + for (int i = top + 1; i < bottom; i++) { + ret.add(matrix[i][right]); + } + + // the down line; + if (rows > 1) { + for (int j = right; j >= left; j--) { + ret.add(matrix[bottom][j]); + } + } + + // the left column. + if (cols > 1) { + for (int i = bottom - 1; i > top; i --) { + ret.add(matrix[i][left]); + } + } + } + + return ret; + } + + // find the index of array in which A[i] = i, sorted array + /* problem1: no duplicate inside */ + public int findIndex(int[] num){ + if (num == null || num.length == 0){ + return -1; // defined to be the edge case number + } + int left = -1; + int right = num.length; + int mid; + + while (right - left > 1){ + mid = left + (right-left)/2; + if (num[mid] == mid){ + return mid; + } + else if (num[mid] > mid){// left + right = mid; + } + else{ + left = mid; + } + } + return -1; + } + + /* problem2: duplicate exists */ + public static int findIndex2(int[] num){ + if (num == null || num.length == 0){ + return -1; + } + return findMagic2(num,0,num.length-1); + } + + public int findMagic(int[] num, int left, int right){ + if (left < 0 || right >= num.length || left > right){ + return -1; + } + int mid,curr; + + mid = left + (right-left)/2; + if (num[mid] == mid){ + return mid; + } + else{ + // optimize here, shorten the length of binary search scope + curr = Math.min(num[mid], mid-1); + int leftIndex = findMagic(num,left,curr); + if (leftIndex >= 0){ + return leftIndex; + } + curr = Math.max(mid+1, num[mid]); + int rightIndex = findMagic(num,curr,right); + return rightIndex; + } + } + + // Yu Zhang solution: + + public static ArrayList findIndex3(int[] num){ + if (num == null || num.length == 0){ + return null; + } + + ArrayList ret = new ArrayList(); + findMagic3(num,0,num.length-1, ret); + return ret; + } + + public static int findMagic2(int[] num, int left, int right){ + if (left > right) { + return -1; + } + + int mid = left + (right - left) / 2; + + if (num[mid] == mid) { + return mid; + } + + if (num[mid] >= left) { + int ret = findMagic2(num, left, mid - 1); + if (ret != -1) { + return ret; + } + } + + if (num[mid] <= right) { + int ret = findMagic2(num, mid + 1, right); + if (ret != -1) { + return ret; + } + } + + return -1; + } + + // There are duplicate solutions. + public static void findMagic3(int[] num, int left, int right, ArrayList ret){ + if (left > right) { + return; + } + + int mid = left + (right - left) / 2; + + if (num[mid] == mid) { + ret.add(mid); + } + + if (num[mid] >= left) { + findMagic3(num, left, mid - 1, ret); + } + + if (num[mid] <= right) { + findMagic3(num, mid + 1, right, ret); + } + } + + /* string shift */ + public String stringShift(String s,int shift){ + if (s == null || s.length() == 0 || shift%26 <= 0){ + return s; + } + StringBuilder sb = new StringBuilder(); + char curr; + shift = shift%26; + + for (int i=0;i= 'a' && s.charAt(i) <= 'z'){ + curr = (char)('a'+(s.charAt(i)-'a'+shift)%26); + sb.append(curr); + } + else if (s.charAt(i) >= 'A' && s.charAt(i) <= 'Z'){ + curr = (char)('A'+(s.charAt(i)-'A'+shift)%26); + sb.append(curr); + } + else{ + // throw an exception here! + } + } + + return sb.toString(); + } + + /* string shift */ + public static String stringShift2(String s,int shift){ + if (s == null || s.length() == 0 || shift%26 <= 0){ + return s; + } + + StringBuilder sb = new StringBuilder(); + + shift = shift % 26; + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + int num = 0; + if (c <= 'z' && c >= 'a') { + num = c - 'a'; + num += shift; + num %= 26; + num += 'a'; + } else if (c <= 'Z' && c >= 'A') { + num = c - 'A'; + num += shift; + num %= 26; + num += 'A'; + } + + char c1 = (char)num; + sb.append(c1); + } + + + return sb.toString(); + } + + public static void getSame(ArrayList input) { + ArrayList> ret = new ArrayList>(); + if (input == null) { + return; + } + + HashMap> map = new HashMap>(); + + for (String str: input) { + char c1 = str.charAt(0); + + int shift = c1 - 'a'; + + int len = str.length(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < len; i++) { + char c = str.charAt(i); + int num = c - 'a'; + + num -= shift; + if (num < 0) { + num += 26; + } + + num += 'a'; + sb.append((char)num); + } + + String strNew = sb.toString(); + if (map.containsKey(strNew)) { + map.get(strNew).add(str); + } else { + ArrayList list = new ArrayList(); + list.add(str); + map.put(strNew, list); + } + } + + System.out.println(map.toString()); + } + + public static String getShort(String url) throws NoSuchAlgorithmException { + if (url == null) { + return ""; + } + + if (mapFull.containsKey(url)) { + return mapFull.get(url); + } + + String original = url; + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(original.getBytes()); + byte[] digest = md.digest(); + StringBuffer sb = new StringBuffer(); + for (byte b : digest) { + sb.append(String.format("%02x", b & 0xff)); + } + + System.out.println("original:" + original); + System.out.println("digested(hex):" + sb.toString()); + + String md5 = sb.toString(); + + String shortUrl = md5.substring(0, 6); + if (map.containsKey(shortUrl)) { + for (int i = 0; i < shortUrl.length(); i++) { + StringBuilder sbChange = new StringBuilder(shortUrl); + for (char c = 'a'; c <= 'z'; c++) { + sbChange.setCharAt(i, c); + shortUrl = sbChange.toString(); + if (!map.containsKey(shortUrl)) { + break; + } + } + } + map.put(shortUrl, url); + } else { + map.put(shortUrl, url); + } + + mapFull.put(url, shortUrl); + + return "http://uber.gl/" + shortUrl; + } + + public static String getFullUrl(String url){ + if (url == null) { + return ""; + } + + if (map.containsKey(url)) { + return map.get(url); + } else { + return ""; + } + } + + public static ArrayList> getPath(TreeNode root, int target) { + ArrayList> ret = new ArrayList>(); + + getPath(root, new ArrayList(), target, ret); + return ret; + } + + public static void getPath(TreeNode root, ArrayList path, int target, + ArrayList> ret) { + if (root == null) { + return; + } + + path.add(root.val); + target -= root.val; + if (target == 0 && root.left == null && root.right == null) { + ret.add(new ArrayList(path)); + path.remove(path.size() - 1); + return; + } + + if (target < 0) { + path.remove(path.size() - 1); + return; + } + + getPath(root.left, path, target, ret); + getPath(root.right, path, target, ret); + path.remove(path.size() - 1); + } +} diff --git a/algorithm/interviews/uber/FindEqualIndex.java b/algorithm/interviews/uber/FindEqualIndex.java new file mode 100644 index 0000000..13da545 --- /dev/null +++ b/algorithm/interviews/uber/FindEqualIndex.java @@ -0,0 +1,99 @@ +package Algorithms.algorithm.interviews.uber; + +import java.util.ArrayList; + +public class FindEqualIndex { + public static void main(String[] str) { + int[] input = {-4,-3,-2,-1,3,4,6,7,9,10,11,12}; + System.out.println(findEqual(input)); + + int[] input2 = {-4,-3,-2,-1,3,4,6,7,8,9,10,11}; + System.out.println(findEqual(input2)); + + int[] input3 = {-4, -3, -2, -1, 3, 4, 6, 7, 9, 10, 11, 13}; + System.out.println(findEqual2(input3)); + } + + public static ArrayList findEqual(int[] input) { + ArrayList ret = new ArrayList(); + + int l = 0; + int r = input.length - 1; + + // find the left bound. + while (l < r - 1) { + int mid = l + (r - l) / 2; + + // the value >= index. + if (input[mid] >= mid) { + r = mid; + } else { + l = mid; + } + } + + int leftBound = l == input[l] ? l: r; + + // bug:should reset l, r. + l = 0; + r = input.length - 1; + + // find the right bound. + while (l < r - 1) { + int mid = l + (r - l) / 2; + + // the value <= index. + if (input[mid] <= mid) { + // move right. + l = mid; + } else { + // move left. + r = mid; + } + } + + int rightBound = r == input[r] ? r: l; + + for (int i = leftBound; i <= rightBound; i++) { + ret.add(i); + } + + return ret; + } + + /* + * Author: He Long. + */ + public static ArrayList findEqual2(int[] A) { + ArrayList res = new ArrayList(); + if (A == null || A.length == 0) { + return res; + } + int ll = 0; + int lr = A.length - 1; + while (ll <= lr) { + int m = ll + (lr - ll) / 2; + if (A[m] - m < 0) { + ll = m + 1; + } else { + lr = m - 1; + } + } + int rl = 0; + int rr = A.length - 1; + while (rl <= rr) { + int m = rl + (rr - rl) / 2; + if (A[m] - m <= 0) { + rl = m + 1; + } else { + rr = m - 1; + } + } + if (ll <= rr) { + while (ll <= rr) { + res.add(A[ll++]); + } + } + return res; + } +} diff --git a/algorithm/interviews/uber/FindWord.java b/algorithm/interviews/uber/FindWord.java new file mode 100644 index 0000000..26388b6 --- /dev/null +++ b/algorithm/interviews/uber/FindWord.java @@ -0,0 +1,40 @@ +package Algorithms.algorithm.interviews.uber; + +import java.util.ArrayList; + +public class FindWord { + public static void main(String[] strs) { + System.out.println(findAllStrings("xxisxhis")); + + } + + public static boolean isAWord(String s) { + if (s.equals("is")) { + return true; + } else if (s.equals("his")){ + return true; + } + return false; + } + + public static ArrayList findAllStrings(String s) { + ArrayList ret = new ArrayList(); + + if (s == null || s.length() == 0) { + return ret; + } + + int len = s.length(); + + for (int i = 0; i < len; i++) { + for (int j = i; j < len; j++) { + String sub = s.substring(i, j + 1); + if (isAWord(sub)) { + ret.add(sub); + } + } + } + + return ret; + } +} diff --git a/AddBinary.java b/algorithm/others/AddBinary.java similarity index 97% rename from AddBinary.java rename to algorithm/others/AddBinary.java index c19b562..bc19c4f 100644 --- a/AddBinary.java +++ b/algorithm/others/AddBinary.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class AddBinary { public static void main(String[] args) { diff --git a/algorithm/others/Ag.java b/algorithm/others/Ag.java new file mode 100644 index 0000000..9e5b187 --- /dev/null +++ b/algorithm/others/Ag.java @@ -0,0 +1,7 @@ +package Algorithms.algorithm.others; + + + +abstract public class Ag { + +} diff --git a/Anagrams.java b/algorithm/others/Anagrams.java similarity index 97% rename from Anagrams.java rename to algorithm/others/Anagrams.java index 74ddb55..1d79f88 100644 --- a/Anagrams.java +++ b/algorithm/others/Anagrams.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; import java.util.HashMap; diff --git a/BinarySearch.java b/algorithm/others/BinarySearch.java similarity index 97% rename from BinarySearch.java rename to algorithm/others/BinarySearch.java index b8ad95e..b842c45 100644 --- a/BinarySearch.java +++ b/algorithm/others/BinarySearch.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class BinarySearch { public static void main(String[] strs) { diff --git a/Combination2.java b/algorithm/others/Combination2.java similarity index 97% rename from Combination2.java rename to algorithm/others/Combination2.java index 9a8b8e9..fb87aed 100644 --- a/Combination2.java +++ b/algorithm/others/Combination2.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; import java.util.Arrays; diff --git a/CombinationSum.java b/algorithm/others/CombinationSum.java similarity index 98% rename from CombinationSum.java rename to algorithm/others/CombinationSum.java index 2a2b7d3..4c7f2d4 100644 --- a/CombinationSum.java +++ b/algorithm/others/CombinationSum.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; import java.util.Arrays; diff --git a/DivideTwoIntegers.java b/algorithm/others/DivideTwoIntegers.java similarity index 94% rename from DivideTwoIntegers.java rename to algorithm/others/DivideTwoIntegers.java index d0c6e72..e2ad42d 100644 --- a/DivideTwoIntegers.java +++ b/algorithm/others/DivideTwoIntegers.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class DivideTwoIntegers { public static void main(String[] args) { diff --git a/FindSame.java b/algorithm/others/FindSame.java similarity index 96% rename from FindSame.java rename to algorithm/others/FindSame.java index d4d3c59..13ef64e 100644 --- a/FindSame.java +++ b/algorithm/others/FindSame.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.LinkedList; diff --git a/Flatten.java b/algorithm/others/Flatten.java similarity index 90% rename from Flatten.java rename to algorithm/others/Flatten.java index 06fc2d4..0e226c3 100644 --- a/Flatten.java +++ b/algorithm/others/Flatten.java @@ -1,6 +1,8 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.Stack; +import Algorithms.tree.TreeNode; + public class Flatten { diff --git a/GenerateParentheses.java b/algorithm/others/GenerateParentheses.java similarity index 98% rename from GenerateParentheses.java rename to algorithm/others/GenerateParentheses.java index ba26c66..beae96a 100644 --- a/GenerateParentheses.java +++ b/algorithm/others/GenerateParentheses.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; import java.util.Stack; diff --git a/algorithm/others/GraphDemo.java b/algorithm/others/GraphDemo.java new file mode 100644 index 0000000..2f34649 --- /dev/null +++ b/algorithm/others/GraphDemo.java @@ -0,0 +1,103 @@ +package Algorithms.algorithm.others; + +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/InOrderTraversal.java b/algorithm/others/InOrderTraversal.java similarity index 92% rename from InOrderTraversal.java rename to algorithm/others/InOrderTraversal.java index b365588..d802883 100644 --- a/InOrderTraversal.java +++ b/algorithm/others/InOrderTraversal.java @@ -1,7 +1,9 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; import java.util.Stack; +import Algorithms.tree.TreeNode; + public class InOrderTraversal { public ArrayList inorderTraversal(TreeNode root) { diff --git a/Insertion_Link.java b/algorithm/others/Insertion_Link.java similarity index 97% rename from Insertion_Link.java rename to algorithm/others/Insertion_Link.java index b5ea424..babef0c 100644 --- a/Insertion_Link.java +++ b/algorithm/others/Insertion_Link.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class Insertion_Link { public static void main(String[] str) { diff --git a/Interleaving.java b/algorithm/others/Interleaving.java similarity index 98% rename from Interleaving.java rename to algorithm/others/Interleaving.java index 7c24db8..e74ef19 100644 --- a/Interleaving.java +++ b/algorithm/others/Interleaving.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class Interleaving { public static void main(String[] strs) { System.out.println(isInterleave("a", "b", "ab")); diff --git a/IntersectionOfThreeSets.java b/algorithm/others/IntersectionOfThreeSets.java similarity index 96% rename from IntersectionOfThreeSets.java rename to algorithm/others/IntersectionOfThreeSets.java index 6d3f2cb..8b41852 100644 --- a/IntersectionOfThreeSets.java +++ b/algorithm/others/IntersectionOfThreeSets.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.HashMap; import java.util.LinkedList; diff --git a/IsMach.java b/algorithm/others/IsMach.java similarity index 67% rename from IsMach.java rename to algorithm/others/IsMach.java index 709e35d..32c5930 100644 --- a/IsMach.java +++ b/algorithm/others/IsMach.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class IsMach { public static void main(String[] str) { @@ -18,37 +18,37 @@ public static boolean help(String s, String p, int indexS, int indexP) { int pLen = p.length(); int sLen = s.length(); - // 1. P结束了,这时 S也应该要结束 + // 1. P?????????????????? S?????????????????? if (indexP == pLen) { return indexS == sLen; } - // 2. P 只有最后一个没有匹配 + // 2. P ?????????????????????????????? if (indexP == pLen - 1) { - // 必须相等,或者是p为'.'. - // S必须只有一个字符 + // ????????????????????????p???'.'. + // S???????????????????????? return indexS == sLen - 1 && matchChar(s, p, indexS, indexP); } - // 以下P 至少还有2个字符. + // ??????P ????????????2?????????. - // 2. 单独匹配的情况, 如 aa, a. 类似这样 + // 2. ?????????????????????, ??? aa, a. ???????????? if (p.charAt(indexP + 1) != '*') { if (indexS < sLen && matchChar(s, p, indexS, indexP)) { - return help(s, p, indexS + 1, indexP + 1); // p可以前进一格 + return help(s, p, indexS + 1, indexP + 1); // p?????????????????? } else { return false; } } - // 3. 多重匹配的情况, 如 .* or a* ,这时需要进行递归 + // 3. ?????????????????????, ??? .* or a* ,???????????????????????? - // 先直接跳过此2个正则,因为我们可以匹配空。 + // ??????????????????2?????????????????????????????????????????? if (help(s, p, indexS, indexP + 2)) { return true; } - // 匹配非空的情况,这里不可以跳过p,必须 匹配1个或是多个 + // ?????????????????????,?????????????????????p????????? ??????1??????????????? for (int i = indexS; i < sLen; i++) { if (!matchChar(s, p, i, indexP)) { return false; @@ -59,7 +59,7 @@ public static boolean help(String s, String p, int indexS, int indexP) { } } - // 多重匹配之后,余下的字串仍然不可以匹配,则返回失败。 + // ?????????????????????????????????????????????????????????????????????????????? return false; } diff --git a/IsSymmetric.java b/algorithm/others/IsSymmetric.java similarity index 94% rename from IsSymmetric.java rename to algorithm/others/IsSymmetric.java index eb8509f..a3f864a 100644 --- a/IsSymmetric.java +++ b/algorithm/others/IsSymmetric.java @@ -1,7 +1,9 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayDeque; +import Algorithms.tree.TreeNode; + public class IsSymmetric { public boolean isSymmetric(TreeNode root) { if (root == null) { diff --git a/JavaAppWithoutMain.java b/algorithm/others/JavaAppWithoutMain.java similarity index 75% rename from JavaAppWithoutMain.java rename to algorithm/others/JavaAppWithoutMain.java index 5ebab11..ab020d2 100644 --- a/JavaAppWithoutMain.java +++ b/algorithm/others/JavaAppWithoutMain.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class JavaAppWithoutMain { static diff --git a/algorithm/others/KthSort.java b/algorithm/others/KthSort.java new file mode 100644 index 0000000..20c3200 --- /dev/null +++ b/algorithm/others/KthSort.java @@ -0,0 +1,43 @@ +package Algorithms.algorithm.others; + +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/LRUCache.java b/algorithm/others/LRUCache.java similarity index 98% rename from LRUCache.java rename to algorithm/others/LRUCache.java index f367fdc..2dfcc92 100644 --- a/LRUCache.java +++ b/algorithm/others/LRUCache.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.HashMap; diff --git a/LargestRectangleArea.java b/algorithm/others/LargestRectangleArea.java similarity index 94% rename from LargestRectangleArea.java rename to algorithm/others/LargestRectangleArea.java index 9709f21..d374156 100644 --- a/LargestRectangleArea.java +++ b/algorithm/others/LargestRectangleArea.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.Stack; diff --git a/Line.java b/algorithm/others/Line.java similarity index 98% rename from Line.java rename to algorithm/others/Line.java index 3ce7a15..d5f56e2 100644 --- a/Line.java +++ b/algorithm/others/Line.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.Comparator; import java.util.HashMap; diff --git a/ListNode.java b/algorithm/others/ListNode.java similarity index 92% rename from ListNode.java rename to algorithm/others/ListNode.java index 431ec40..6ff9fba 100644 --- a/ListNode.java +++ b/algorithm/others/ListNode.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class ListNode { public int val; diff --git a/LongestPare.java b/algorithm/others/LongestPare.java similarity index 98% rename from LongestPare.java rename to algorithm/others/LongestPare.java index 68be7dd..34c046d 100644 --- a/LongestPare.java +++ b/algorithm/others/LongestPare.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.Stack; diff --git a/Max_path_BinaryTree.java b/algorithm/others/Max_path_BinaryTree.java similarity index 97% rename from Max_path_BinaryTree.java rename to algorithm/others/Max_path_BinaryTree.java index de91cc8..be76468 100644 --- a/Max_path_BinaryTree.java +++ b/algorithm/others/Max_path_BinaryTree.java @@ -1,6 +1,8 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; +import Algorithms.tree.TreeNode; + public class Max_path_BinaryTree { public static void main(String args[]){ diff --git a/MiniStack.java b/algorithm/others/MiniStack.java similarity index 98% rename from MiniStack.java rename to algorithm/others/MiniStack.java index e391595..cc70e69 100644 --- a/MiniStack.java +++ b/algorithm/others/MiniStack.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.Stack; diff --git a/MinimumWindowSubString.java b/algorithm/others/MinimumWindowSubString.java similarity index 98% rename from MinimumWindowSubString.java rename to algorithm/others/MinimumWindowSubString.java index ef34ed2..913ce3d 100644 --- a/MinimumWindowSubString.java +++ b/algorithm/others/MinimumWindowSubString.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.HashMap; public class MinimumWindowSubString { diff --git a/MortgageCalculator.java b/algorithm/others/MortgageCalculator.java similarity index 99% rename from MortgageCalculator.java rename to algorithm/others/MortgageCalculator.java index b128438..b46bfac 100644 --- a/MortgageCalculator.java +++ b/algorithm/others/MortgageCalculator.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.text.NumberFormat; diff --git a/MutiplyString.java b/algorithm/others/MutiplyString.java similarity index 97% rename from MutiplyString.java rename to algorithm/others/MutiplyString.java index 18da410..8517f78 100644 --- a/MutiplyString.java +++ b/algorithm/others/MutiplyString.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class MutiplyString { public static void main(String[] args) { MutiplyString ms = new MutiplyString(); diff --git a/NumDecodings.java b/algorithm/others/NumDecodings.java similarity index 97% rename from NumDecodings.java rename to algorithm/others/NumDecodings.java index 88dc103..2e1d0f8 100644 --- a/NumDecodings.java +++ b/algorithm/others/NumDecodings.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class NumDecodings { public static void main(String[] strs) { diff --git a/NumTree.java b/algorithm/others/NumTree.java similarity index 95% rename from NumTree.java rename to algorithm/others/NumTree.java index 9f8ee1f..6a807a6 100644 --- a/NumTree.java +++ b/algorithm/others/NumTree.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class NumTree { public static void main(String[] strs) { diff --git a/PartitionArray.java b/algorithm/others/PartitionArray.java similarity index 96% rename from PartitionArray.java rename to algorithm/others/PartitionArray.java index 43d6344..c4a1e47 100644 --- a/PartitionArray.java +++ b/algorithm/others/PartitionArray.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class PartitionArray { public static void main(String[] strs) { diff --git a/Permute.java b/algorithm/others/Permute.java similarity index 96% rename from Permute.java rename to algorithm/others/Permute.java index 6e810bd..290f3b2 100644 --- a/Permute.java +++ b/algorithm/others/Permute.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; import java.util.Arrays; diff --git a/PlusOne.java b/algorithm/others/PlusOne.java similarity index 95% rename from PlusOne.java rename to algorithm/others/PlusOne.java index 5f69f72..ec0dacd 100644 --- a/PlusOne.java +++ b/algorithm/others/PlusOne.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class PlusOne { public static void main(String[] args) { diff --git a/Point.java b/algorithm/others/Point.java similarity index 79% rename from Point.java rename to algorithm/others/Point.java index 4fc5f18..615d2b3 100644 --- a/Point.java +++ b/algorithm/others/Point.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; class Point { int x; diff --git a/Populate2.java b/algorithm/others/Populate2.java similarity index 96% rename from Populate2.java rename to algorithm/others/Populate2.java index de55770..a4097dd 100644 --- a/Populate2.java +++ b/algorithm/others/Populate2.java @@ -1,4 +1,7 @@ -package Algorithms; +package Algorithms.algorithm.others; + +import Algorithms.tree.TreeLinkNode; + public class Populate2 { public static void main(String[] args) { TreeLinkNode root = new TreeLinkNode(2); diff --git a/Premute.java b/algorithm/others/Premute.java similarity index 98% rename from Premute.java rename to algorithm/others/Premute.java index dc5e852..7487874 100644 --- a/Premute.java +++ b/algorithm/others/Premute.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; import java.util.Arrays; diff --git a/Recover.java b/algorithm/others/Recover.java similarity index 92% rename from Recover.java rename to algorithm/others/Recover.java index c185ce5..7cde9de 100644 --- a/Recover.java +++ b/algorithm/others/Recover.java @@ -1,4 +1,6 @@ -package Algorithms; +package Algorithms.algorithm.others; + +import Algorithms.tree.TreeNode; public class Recover { private TreeNode big = null; diff --git a/Rectangle.java b/algorithm/others/Rectangle.java similarity index 97% rename from Rectangle.java rename to algorithm/others/Rectangle.java index 0dd9f4b..8e1438d 100644 --- a/Rectangle.java +++ b/algorithm/others/Rectangle.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.Stack; diff --git a/algorithm/others/ReverseString.java b/algorithm/others/ReverseString.java new file mode 100644 index 0000000..6d81434 --- /dev/null +++ b/algorithm/others/ReverseString.java @@ -0,0 +1,5 @@ +package Algorithms.algorithm.others; + +public class ReverseString { + +} diff --git a/algorithm/others/Reverse_binary.java b/algorithm/others/Reverse_binary.java new file mode 100644 index 0000000..8ddecc4 --- /dev/null +++ b/algorithm/others/Reverse_binary.java @@ -0,0 +1,20 @@ +package Algorithms.algorithm.others; + +public class Reverse_binary { + public static void main(String[] strs) { + System.out.println(reverse(20034556)); + } + + public static int reverse(int in) { + int ret = 0; + + for (int i = 0; i < 4; i++) { + int tmp = (in & 0xFF); + ret <<= 8; + ret += tmp; + in >>= 8; + } + + return ret; + } +} diff --git a/SearchInRotatedArray.java b/algorithm/others/SearchInRotatedArray.java similarity index 98% rename from SearchInRotatedArray.java rename to algorithm/others/SearchInRotatedArray.java index 11e3521..4908cac 100644 --- a/SearchInRotatedArray.java +++ b/algorithm/others/SearchInRotatedArray.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class SearchInRotatedArray { public static void main(String[] args) { diff --git a/algorithm/others/SingleNumber2.java b/algorithm/others/SingleNumber2.java new file mode 100644 index 0000000..9b549ee --- /dev/null +++ b/algorithm/others/SingleNumber2.java @@ -0,0 +1,5 @@ +package Algorithms.algorithm.others; + +public class SingleNumber2 { + +} diff --git a/SortColors.java b/algorithm/others/SortColors.java similarity index 97% rename from SortColors.java rename to algorithm/others/SortColors.java index 67444f6..b35e432 100644 --- a/SortColors.java +++ b/algorithm/others/SortColors.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.Collection; import java.util.LinkedList; diff --git a/SortList.java b/algorithm/others/SortList.java similarity index 97% rename from SortList.java rename to algorithm/others/SortList.java index 40c9531..6ed1099 100644 --- a/SortList.java +++ b/algorithm/others/SortList.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class SortList { public static void main(String[] str) { SortList sl = new SortList(); diff --git a/SpiralMatrix.java b/algorithm/others/SpiralMatrix.java similarity index 96% rename from SpiralMatrix.java rename to algorithm/others/SpiralMatrix.java index e14d76f..dd518b6 100644 --- a/SpiralMatrix.java +++ b/algorithm/others/SpiralMatrix.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class SpiralMatrix { public int[][] generateMatrix(int n) { int[][] rst = new int[n][n]; diff --git a/SpiralOrder.java b/algorithm/others/SpiralOrder.java similarity index 97% rename from SpiralOrder.java rename to algorithm/others/SpiralOrder.java index 2b6eb74..1fd66c0 100644 --- a/SpiralOrder.java +++ b/algorithm/others/SpiralOrder.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; diff --git a/Sqrt.java b/algorithm/others/Sqrt.java similarity index 96% rename from Sqrt.java rename to algorithm/others/Sqrt.java index 06a9a67..db3e855 100644 --- a/Sqrt.java +++ b/algorithm/others/Sqrt.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class Sqrt { public static int sqrt(int x) { diff --git a/SubSet2.java b/algorithm/others/SubSet2.java similarity index 97% rename from SubSet2.java rename to algorithm/others/SubSet2.java index 7f94174..ea1a14a 100644 --- a/SubSet2.java +++ b/algorithm/others/SubSet2.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; import java.util.Arrays; diff --git a/Subset.java b/algorithm/others/Subset.java similarity index 98% rename from Subset.java rename to algorithm/others/Subset.java index a70eb11..49ae1ff 100644 --- a/Subset.java +++ b/algorithm/others/Subset.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; import java.util.Arrays; diff --git a/SurroundRegions.java b/algorithm/others/SurroundRegions.java similarity index 95% rename from SurroundRegions.java rename to algorithm/others/SurroundRegions.java index 3ed4c16..4fb2474 100644 --- a/SurroundRegions.java +++ b/algorithm/others/SurroundRegions.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.LinkedList; import java.util.Queue; @@ -56,7 +56,7 @@ public static void solve(char[][] board) { public static void bfs(char[][] board, int x, int y) { Queue q = new LinkedList(); - // 把x, y放入queue代表准备要访问它的邻接点 + // ???x, y??????queue???????????????????????????????????? visit(board, x, y, q); while (!q.isEmpty()) { int num = q.poll(); diff --git a/TestArrayChange.java b/algorithm/others/TestArrayChange.java similarity index 93% rename from TestArrayChange.java rename to algorithm/others/TestArrayChange.java index 924eaba..919524a 100644 --- a/TestArrayChange.java +++ b/algorithm/others/TestArrayChange.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; public class TestArrayChange { public static void main(String[] args) { diff --git a/TreeSumCloset.java b/algorithm/others/TreeSumCloset.java similarity index 98% rename from TreeSumCloset.java rename to algorithm/others/TreeSumCloset.java index a9ad817..5a6b808 100644 --- a/TreeSumCloset.java +++ b/algorithm/others/TreeSumCloset.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.Arrays; diff --git a/WordBreak2.java b/algorithm/others/WordBreak2.java similarity index 98% rename from WordBreak2.java rename to algorithm/others/WordBreak2.java index 562b197..b9c7570 100644 --- a/WordBreak2.java +++ b/algorithm/others/WordBreak2.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; diff --git a/ZigzagLevelOrder.java b/algorithm/others/ZigzagLevelOrder.java similarity index 98% rename from ZigzagLevelOrder.java rename to algorithm/others/ZigzagLevelOrder.java index 3eca3df..3ec2fc7 100644 --- a/ZigzagLevelOrder.java +++ b/algorithm/others/ZigzagLevelOrder.java @@ -1,9 +1,11 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue; import java.util.Stack; +import Algorithms.tree.TreeNode; + public class ZigzagLevelOrder { public ArrayList> zigzagLevelOrder(TreeNode root) { diff --git a/letterCombinations.java b/algorithm/others/letterCombinations.java similarity index 98% rename from letterCombinations.java rename to algorithm/others/letterCombinations.java index 53cf31a..ecc2f85 100644 --- a/letterCombinations.java +++ b/algorithm/others/letterCombinations.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.algorithm.others; import java.util.ArrayList; diff --git a/algorithm/sort/WaveSort.java b/algorithm/sort/WaveSort.java new file mode 100644 index 0000000..962f285 --- /dev/null +++ b/algorithm/sort/WaveSort.java @@ -0,0 +1,65 @@ +package Algorithms.algorithm.sort; + +import java.util.Arrays; + +/* + * 给定一个未排序的数组,请给出波浪状排序: + * Example: + * input: 1 2 5 4 3 9 + * output: 1 4 3 5 2 9 + * + * input: 1 2 2 5 3 9 + * output: 1 5 2 3 2 9 + * */ +public class WaveSort { + public static void main(String[] str) { + int[] in = {1,2,5,4,3,9,9,9, 12}; + + for (int i: in) { + System.out.print(i + " "); + } + System.out.println(); + + waveSort(in); + for (int i: in) { + System.out.print(i + " "); + } + } + + public static void waveSort(int[] in) { + if (in == null) { + return; + } + + // there should be at least 3 numbers. + if (in.length <= 2) { + return; + } + + int len = in.length; + + Arrays.sort(in); + + for (int i: in) { + System.out.print(i + " "); + } + System.out.println(); + + for (int i = 0; i < len; i++) { + if (i % 2 == 0) { + for (int j = i + 1; j < len; j++) { + if (in[j] != in[i]) { + int tmp = in[i]; + in[i] = in[j]; + in[j] = tmp; + break; + } + } + } + } + } + + public static void findKthNumber(int[] in, int k) { + + } +} diff --git a/array/FindMedianSortedArrays.java b/array/FindMedianSortedArrays.java new file mode 100644 index 0000000..3d13baa --- /dev/null +++ b/array/FindMedianSortedArrays.java @@ -0,0 +1,62 @@ +package Algorithms.array; + +public class FindMedianSortedArrays { + public static void main(String[] strs) { + int A[] = {100000}; + int B[] = {100001}; + + System.out.println(findMedianSortedArrays(A, B)); + } + + public static double findMedianSortedArrays(int A[], int B[]) { + if (A == null || B == null) { + return 0; + } + + int len = A.length + B.length; + + double ret = 0; + // 偶数个元素 + if (len % 2 == 0) { + ret = (findKth(A, B, 0, 0, len / 2) + findKth(A, B, 0, 0, len / 2 + 1)) / (double)2.0; + } else { + // 奇数个元素 + ret = findKth(A, B, 0, 0, len / 2 + 1); + } + + return ret; + } + + // Find the Kth large number. + public static int findKth(int A[], int B[], int indexA, int indexB, int k) { + int lenA = A.length; + int lenB = B.length; + + if (indexA >= lenA) { + return B[indexB + k - 1]; + } else if (indexB >= lenB) { + return A[indexA + k - 1]; + } + + // Base Case, pay attention. 在这里必须要退出。因为k = 1的时候,不可能再分了。 + if (k == 1) { + return Math.min(A[indexA], B[indexB]); + } + + // -1是因为索引本身是从0开始的。而前k大元素含有k个元素。 + int mid = k / 2 - 1; + + // 注意,越界条件是 >= lenA. 怎么老是犯这个错误。。 + int keyA = indexA + mid >= lenA ? Integer.MAX_VALUE: A[indexA + mid]; + int keyB = indexB + mid >= lenB ? Integer.MAX_VALUE: B[indexB + mid]; + + // 因为丢弃了k / 2个元素 + int kNew = k - k / 2; + + if (keyA < keyB) { + return findKth(A, B, indexA + k / 2, indexB, kNew); + } else { + return findKth(A, B, indexA, indexB + k / 2, kNew); + } + } +} diff --git a/array/FirstMissingPositive.java b/array/FirstMissingPositive.java new file mode 100644 index 0000000..2c72c41 --- /dev/null +++ b/array/FirstMissingPositive.java @@ -0,0 +1,63 @@ +package Algorithms.array; + +public class FirstMissingPositive { + public static void main(String[] strs) { + int[] in = {1,4,2,3}; + //int[] in = {3,4,-1,1}; + System.out.println(firstMissingPositive(in)); + } + + public static int firstMissingPositive1(int[] A) { + if (A == null) { + return 0; + } + + int len = A.length; + for (int i = 0; i < len; i++) { + // 1. The number should be in the range. + // 2. The number should be positive. + while (A[i] <= len && A[i] > 0 && A[A[i] - 1] != A[i]) { + swap(A, i, A[i] - 1); + } + } + + for (int i = 0; i < len; i++) { + if (A[i] != i + 1) { + return i + 1; + } + } + + return len + 1; + } + + public static void swap(int[] A, int i, int j) { + int tmp = A[i]; + A[i] = A[j]; + A[j] = tmp; + } + + // SOLUTION 2: + public static int firstMissingPositive(int[] A) { + // bug 3: when length is 0, return 1; + if (A == null) { + return 0; + } + + for (int i = 0; i < A.length; i++) { + // 1: A[i] is in the range; + // 2: A[i] > 0. + // 3: The target is different; + while (A[i] <= A.length && A[i] > 0 && A[A[i] - 1] != A[i]) { + swap(A, i, A[i] - 1); + } + } + + for (int i = 0; i < A.length; i++) { + if (A[i] != i + 1) { + return i + 1; + } + } + + return A.length + 1; + } +} \ No newline at end of file diff --git a/array/GenerateMatrix1.java b/array/GenerateMatrix1.java new file mode 100644 index 0000000..7f0fc78 --- /dev/null +++ b/array/GenerateMatrix1.java @@ -0,0 +1,166 @@ +package Algorithms.array; + +public class GenerateMatrix1 { + public int[][] generateMatrix1(int n) { + int[][] ret = new int[n][n]; + + if (n == 0) { + // return a [] not a NULL. + return ret; + } + + int number = 0; + int rows = n; + + int x1 = 0; + int y1 = 0; + + while (rows > 0) { + int x2 = x1 + rows - 1; + int y2 = y1 + rows - 1; + + // the Whole first row. + for (int i = y1; i <= y2; i++) { + number++; + ret[x1][i] = number; + } + + // the right column except the first and last line. + for (int i = x1 + 1; i < x2; i++) { + number++; + ret[i][y2] = number; + } + + // This line is very important. + if (rows <= 1) { + break; + } + + // the WHOLE last row. + for (int i = y2; i >= y1; i--) { + number++; + ret[x2][i] = number; + } + + // the left column. column keep stable + // x: x2-1 --> x1 + 1 + for (int i = x2 - 1; i > x1; i--) { + number++; + ret[i][y1] = number; + } + + // remember this. + rows -= 2; + x1++; + y1++; + } + + return ret; + } + + /* + Solution 2: use direction. + */ + public int[][] generateMatrix2(int n) { + int[][] ret = new int[n][n]; + if (n == 0) { + return ret; + } + + int[] x = {1, 0, -1, 0}; + int[] y = {0, 1, 0, -1}; + + int num = 0; + + int step = 0; + int candElements = 0; + + int visitedRows = 0; + int visitedCols = 0; + + // 0: right, 1: down, 2: left, 3: up. + int direct = 0; + + int startx = 0; + int starty = 0; + + while (true) { + if (x[direct] == 0) { + // visit the Y axis + candElements = n - visitedRows; + } else { + // visit the X axis + candElements = n - visitedCols; + } + + if (candElements <= 0) { + break; + } + + // set the cell. + ret[startx][starty] = ++num; + step++; + + // change the direction. + if (step == candElements) { + step = 0; + visitedRows += x[direct] == 0 ? 0: 1; + visitedCols += y[direct] == 0 ? 0: 1; + + // change the direction. + direct = (direct + 1) % 4; + } + + startx += y[direct]; + starty += x[direct]; + } + + return ret; + } + + /* + Solution 3: 使用四条bound来限制的方法. + */ + public int[][] generateMatrix(int n) { + int[][] ret = new int[n][n]; + if (n == 0) { + return ret; + } + + int top = 0, bottom = n - 1, left = 0, right = n - 1; + int num = 1; + while (top <= bottom) { + if (top == bottom) { + ret[top][top] = num++; + break; + } + + // first line. + for (int i = left; i < right; i++) { + ret[top][i] = num++; + } + + // right line; + for (int i = top; i < bottom; i++) { + ret[i][right] = num++; + } + + // bottom line; + for (int i = right; i > left; i--) { + ret[bottom][i] = num++; + } + + // left line; + for (int i = bottom; i > top; i--) { + ret[i][left] = num++; + } + + top++; + bottom--; + left++; + right--; + } + + return ret; + } +} \ No newline at end of file diff --git a/array/Interval.java b/array/Interval.java new file mode 100644 index 0000000..f288682 --- /dev/null +++ b/array/Interval.java @@ -0,0 +1,16 @@ +package Algorithms.array; + +public class Interval { + int start; + int end; + + Interval() { + start = 0; + end = 0; + } + + Interval(int s, int e) { + start = s; + end = e; + } +} diff --git a/array/LargestRectangleArea.java b/array/LargestRectangleArea.java new file mode 100644 index 0000000..86a94e2 --- /dev/null +++ b/array/LargestRectangleArea.java @@ -0,0 +1,44 @@ +package Algorithms.array; + +import java.util.Stack; + +public class LargestRectangleArea { + public static void main(String[] strs) { + int[] height = {0}; + System.out.println(largestRectangleArea(height)); + } + + public static int largestRectangleArea(int[] height) { + if (height == null || height.length == 0) { + return 0; + } + + Stack s = new Stack(); + + int max = 0; + + int len = height.length; + int i = 0; + + while (i <= len) { + // BUG 1: should use height[s.peek()] instead of s.peek(). + // BUG 2: should put i < length after the s.isEmpty. + // The last step: Length is also put into the stack and will break at last. + if (s.isEmpty() || (i < len && height[i] >= height[s.peek()])) { + s.push(i); + i++; + // Keep a Ascending sequence in the stack. + } else { + // Stack is not empty, and the current node is smaller than the one in the stack. + // When we come to the end of the array, we will also should count all the solutions. + // BUG 3: should use height[s.pop] instead of s.pop + // When the i come to the end, the rectangle will be counted again. + int h = height[s.pop()]; + int width = s.isEmpty() ? i: i - s.peek() - 1; + max = Math.max(max, h * width); + } + } + + return max; + } +} \ No newline at end of file diff --git a/array/MaxProduct.java b/array/MaxProduct.java new file mode 100644 index 0000000..1cf4054 --- /dev/null +++ b/array/MaxProduct.java @@ -0,0 +1,66 @@ +package Algorithms.array; + +public class MaxProduct { + public static int maxProduct(int[] A) { + if (A == null || A.length == 0) { + return 0; + } + + // record the max value in the last node. + int DMax = A[0]; + + // record the min value in the last node. + int DMin = A[0]; + + // This is very important, should recode the A[0] as the initial value. + int max = A[0]; + + for (int i = 1; i < A.length; i++) { + int n1 = DMax * A[i]; + int n2 = DMin * A[i]; + + // we can select the former nodes, or just discade them. + DMax = Math.max(A[i], Math.max(n1, n2)); + max = Math.max(max, DMax); + + // we can select the former nodes, or just discade them. + DMin = Math.min(A[i], Math.min(n1, n2)); + } + + return max; + } + + /* + * 2014.12.20 Redo + * */ + public int maxProduct2(int[] A) { + if (A == null || A.length == 0) { + return 0; + } + + int max = 1; + int min = 1; + + int ret = Integer.MIN_VALUE; + for (int i = 0; i < A.length; i++) { + int n1 = max * A[i]; + int n2 = min * A[i]; + + max = Math.max(A[i], Math.max(n1, n2)); + min = Math.min(A[i], Math.min(n1, n2)); + + ret = Math.max(max, ret); + } + + return ret; + } + + /* + * 作法是找到连续的正数,不断相乘即可。 + * */ + public static void main(String[] strs) { + int[] A = {2, 3, -2, 4}; + + System.out.println(maxProduct(A)); + } +} 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; + } +} diff --git a/array/MaxSubArray_1220_2014.java b/array/MaxSubArray_1220_2014.java new file mode 100644 index 0000000..175e79e --- /dev/null +++ b/array/MaxSubArray_1220_2014.java @@ -0,0 +1,24 @@ +package Algorithms.array; + +public class MaxSubArray_1220_2014 { + public int maxSubArray(int[] A) { + if (A == null || A.length == 0) { + return 0; + } + + int max = Integer.MIN_VALUE; + int sum = 0; + + int len = A.length; + for (int i = 0; i < len; i++) { + if (sum < 0) { + sum = 0; + } + + sum += A[i]; + max = Math.max(max, sum); + } + + return max; + } +} \ No newline at end of file diff --git a/array/MaximalRectangle.java b/array/MaximalRectangle.java new file mode 100644 index 0000000..dc6700f --- /dev/null +++ b/array/MaximalRectangle.java @@ -0,0 +1,57 @@ +package Algorithms.array; + +import java.util.Stack; + +public class MaximalRectangle { + public int maximalRectangle(char[][] matrix) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + return 0; + } + + int rows = matrix.length; + int cols = matrix[0].length; + + int[][] h = new int[rows][cols]; + + int max = 0; + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + + h[i][j] = matrix[i][j] == '1' ? 1: 0; + + if (i != 0 && h[i][j] != 0) { + h[i][j] = h[i - 1][j] + 1; + } + + if (j == cols - 1) { + max = Math.max(max, maxArea(h[i])); + } + } + } + + return max; + } + + public int maxArea(int[] h) { + Stack s = new Stack(); + + int max = 0; + int i = 0; + + // 注意,这里使用<= 因为当i到达最后,需要计算一次。 + while (i <= h.length) { + // + if (s.isEmpty() || i < h.length && h[i] >= h[s.peek()]) { + s.push(i); + i++; + } else { + int height = h[s.pop()]; + int width = s.isEmpty() ? i: i - s.peek() - 1; + max = Math.max(max, height * width); + } + } + + return max; + } +} \ No newline at end of file diff --git a/array/Merge.java b/array/Merge.java new file mode 100644 index 0000000..3720883 --- /dev/null +++ b/array/Merge.java @@ -0,0 +1,57 @@ +package Algorithms.array; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +/** + * Definition for an interval. + * public class Interval { + * int start; + * int end; + * Interval() { start = 0; end = 0; } + * Interval(int s, int e) { start = s; end = e; } + * } + */ +public class Merge { + public List merge(List intervals) { + List ret = new ArrayList(); + if (intervals == null || intervals.size() == 0) { + return ret; + } + + Collections.sort(intervals, new Comparator() { + public int compare(Interval o1, Interval o2) { + // sort the intervals by the start. + return o1.start - o2.start; + } + }); + + // 作为最后一个插入的区间 + Interval last = intervals.get(0); + + // 这里要考虑性能。使用iterator的话,对linkedlist会更快. + Iterator itor = intervals.iterator(); + while (itor.hasNext()) { + Interval cur = itor.next(); + // cur 在last的右边 + if (cur.start > last.end) { + // 将cur作为新的last. + ret.add(last); + last = cur; + // cur与last有重合的部分,合并之 + } else { + int s = last.start; + int e = Math.max(last.end, cur.end); + last = new Interval(s, e); + } + } + + // 把最后一个区间加上 + ret.add(last); + + return ret; + } +} \ No newline at end of file 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; + } +} diff --git a/array/PlusOne.java b/array/PlusOne.java new file mode 100644 index 0000000..2fdc38b --- /dev/null +++ b/array/PlusOne.java @@ -0,0 +1,41 @@ +package Algorithms.array; + +public class PlusOne { + public int[] plusOne(int[] digits) { + if (digits == null) { + return null; + } + + int overFlow = 0; + + int len = digits.length; + int[] ret = new int[len]; + + for (int i = len - 1; i >= 0; i--) { + int sum = digits[i] + overFlow; + if (i == len - 1) { + // 只有最后一位需要加1 + sum++; + } + + // 溢出的话,置溢出位。 + if (sum > 9) { + overFlow = 1; + } else { + overFlow = 0; + } + + // 把高位去掉,因为我们要0-9 + ret[i] = sum % 10; + } + + if (overFlow == 1) { + int[] retOver = new int[len + 1]; + System.arraycopy(retOver, 1, ret, 0, len); + retOver[0] = 1; + return retOver; + } + + return ret; + } +} 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; + } +} 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 + " "); + } + } +} diff --git a/array/RemoveElement.java b/array/RemoveElement.java new file mode 100644 index 0000000..5972e26 --- /dev/null +++ b/array/RemoveElement.java @@ -0,0 +1,21 @@ +package Algorithms.array; + +public class RemoveElement { + public int removeElement(int[] A, int elem) { + if (A == null || A.length == 0) { + return 0; + } + + int cur = 0; + int len = 0; + while (cur < A.length) { + if (A[cur] != elem) { + A[len++] = A[cur++]; + } else { + cur++; + } + } + + return len; + } +} diff --git a/array/Rotate.java b/array/Rotate.java new file mode 100644 index 0000000..1df4899 --- /dev/null +++ b/array/Rotate.java @@ -0,0 +1,38 @@ +package Algorithms.array; + +public class Rotate { + public void rotate(int[][] matrix) { + if (matrix == null || matrix.length == 0 + || matrix[0].length == 0) { + return; + } + + int n = matrix.length; + int top = 0, down = n - 1, left = 0, right = n - 1; + + while (n > 1) { + for (int i = 0; i < n - 1; i++) { + int tmp = matrix[top][left + i]; + // 另上边等于左边 + matrix[top][left + i] = matrix[down - i][left]; + + // 另左边等于下边 + matrix[down - i][left] = matrix[down][right - i]; + + // 另下边等于右边 + matrix[down][right - i] = matrix[top + i][right]; + + // 另右边等于上边 + matrix[top + i][right] = tmp; + } + top++; + right--; + left++; + down--; + + n -= 2; + } + + return; + } +} \ No newline at end of file diff --git a/array/SearchInRotatedSortedArray.java b/array/SearchInRotatedSortedArray.java new file mode 100644 index 0000000..19c5ec4 --- /dev/null +++ b/array/SearchInRotatedSortedArray.java @@ -0,0 +1,121 @@ +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; + } + + // 2015.1.1 redo: + public int search1(int[] A, int target) { + if (A == null || A.length == 0) { + return -1; + } + + int l = 0; + int r = A.length - 1; + + while (l < r - 1) { + int mid = l + (r - l) / 2; + + if (A[mid] == target) { + return mid; + } + + // left side is sorted. + // BUG 1: if don't use >= , and use L < r in while loop, than there is some problem. + if (A[mid] > A[l]) { + if (target > A[mid] || target < A[l]) { + // move to right; + l = mid + 1; + } else { + r = mid - 1; + } + } else { + if (target < A[mid] || target > A[r]) { + // move to left; + r = mid - 1; + } else { + l = mid + 1; + } + } + } + + if (A[l] == target) { + return l; + } else if (A[r] == target) { + return r; + } + + return -1; + } + + public int search2(int[] A, int target) { + if (A == null || A.length == 0) { + return -1; + } + + int l = 0; + int r = A.length - 1; + + while (l <= r) { + int mid = l + (r - l) / 2; + + if (A[mid] == target) { + return mid; + } + + // left side is sorted. + // BUG 1: if don't use >= , and use L < r in while loop, than there is some problem. + if (A[mid] >= A[l]) { + if (target > A[mid] || target < A[l]) { + // move to right; + l = mid + 1; + } else { + r = mid - 1; + } + } else { + if (target < A[mid] || target > A[r]) { + // move to left; + r = mid - 1; + } else { + l = mid + 1; + } + } + } + + return -1; + } +} diff --git a/array/SearchInRotatedSortedArray2.java b/array/SearchInRotatedSortedArray2.java new file mode 100644 index 0000000..040d341 --- /dev/null +++ b/array/SearchInRotatedSortedArray2.java @@ -0,0 +1,146 @@ +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; + } + + /* + * 2015.1.1 Redo: + * */ + public boolean search1(int[] A, int target) { + if (A == null || A.length == 0) { + return false; + } + + int l = 0; + int r = A.length - 1; + + while (l < r - 1) { + int mid = l + (r - l) / 2; + + if (A[mid] == target) { + return true; + } + + // left sort + if (A[mid] > A[l]) { + // out of range. + if (target > A[mid] || target < A[l]) { + l = mid + 1; + } else { + r = mid - 1; + } + // right sort. + } else if (A[mid] < A[l]) { + // out of range. + if (target < A[mid] || target > A[r]) { + r = mid - 1; + } else { + l = mid + 1; + } + } else { + // move one node. + l++; + } + } + + if (A[l] == target || A[r] == target) { + return true; + } + + return false; + } + + // Version 2: + public boolean search2(int[] A, int target) { + if (A == null || A.length == 0) { + return false; + } + + int l = 0; + int r = A.length - 1; + + while (l <= r) { + int mid = l + (r - l) / 2; + + if (A[mid] == target) { + return true; + } + + // left sort + if (A[mid] > A[l]) { + // out of range. + if (target > A[mid] || target < A[l]) { + l = mid + 1; + } else { + r = mid - 1; + } + // right sort. + } else if (A[mid] < A[l]) { + // out of range. + if (target < A[mid] || target > A[r]) { + r = mid - 1; + } else { + l = mid + 1; + } + } else { + // move one node. + l++; + } + } + + return false; + } +} diff --git a/array/SetZeroes.java b/array/SetZeroes.java new file mode 100644 index 0000000..b303909 --- /dev/null +++ b/array/SetZeroes.java @@ -0,0 +1,139 @@ +package Algorithms.array; + +public class SetZeroes { + public static void main(String[] strs) { + int[][] matrix = { + {0,0,0,5},{4,3,1,4},{0,1,1,4},{1,2,1,3},{0,0,1,1} + }; + + setZeroes(matrix); + } + + public static void setZeroes(int[][] matrix) { + if (matrix == null || matrix.length == 0 + || matrix[0].length == 0) { + return; + } + + boolean row1Zero = false; + boolean col1Zero = false; + + int rows = matrix.length; + int cols = matrix[0].length; + + // Determine if the first column should be Zero. + for (int i = 0; i < rows; i++) { + if (matrix[i][0] == 0) { + col1Zero = true; + break; + } + } + + // Determine if the first row should be Zero. + for (int i = 0; i < cols; i++) { + if (matrix[0][i] == 0) { + row1Zero = true; + break; + } + } + + // we use the first row and the first col as the flag to record the + // cells whether or not set to 0. + for (int i = 1; i < rows; i++) { + for (int j = 1; j < cols; j++) { + if (matrix[i][j] == 0) { + // set the flag in the first line and the first column + matrix[i][0] = 0; + matrix[0][j] = 0; + } + } + } + + // set the inner cells. + // Be careful: i, j start from 1. + for (int i = 1; i < rows; i++) { + for (int j = 1; j < cols; j++) { + if (matrix[i][0] == 0 + || matrix[0][j] == 0) { + matrix[i][j] = 0; + } + } + } + + // set the first row. + if (row1Zero) { + for (int i = 0; i < cols; i++) { + matrix[0][i] = 0; + } + } + + // set the first col. + if (col1Zero) { + for (int i = 0; i < rows; i++) { + matrix[i][0] = 0; + } + } + + return; + } + + // solution 2: combine the first 3 loop. + public void setZeroes2(int[][] matrix) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + return; + } + + boolean row1 = false; + boolean col1 = false; + + int rows = matrix.length; + int cols = matrix[0].length; + + // set flags. + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (matrix[i][j] != 0) { + continue; + } + + // set the flag of a column and a row. + matrix[0][j] = 0; + matrix[i][0] = 0; + + // get flag of first row. + if (i == 0) { + row1 = true; + } + + // get flag of first column. + if (j == 0) { + col1 = true; + } + } + } + + // set the matrix. + for (int i = 1; i < rows; i++) { + for (int j = 1; j < cols; j++) { + if (matrix[0][j] == 0 || matrix[i][0] == 0) { + matrix[i][j] = 0; + } + } + } + + // set first column + if (col1) { + for (int i = 0; i < rows; i++) { + // bug 1: can't use matrix[i][j] + matrix[i][0] = 0; + } + } + + // set first row. + if (row1) { + for (int i = 0; i < cols; i++) { + matrix[0][i] = 0; + } + } + } +} diff --git a/array/SpiralOrder.java b/array/SpiralOrder.java new file mode 100644 index 0000000..a65a4f9 --- /dev/null +++ b/array/SpiralOrder.java @@ -0,0 +1,281 @@ +package Algorithms.array; + +import java.util.ArrayList; +import java.util.List; + +public class SpiralOrder { + public static void main(String[] strs) { + int[][] matrix = { + {1, 2}, + {3, 4} + }; + spiralOrder(matrix); + } + + public List spiralOrder1(int[][] matrix) { + List ret = new ArrayList(); + if (matrix == null || matrix.length == 0 + || matrix[0].length == 0) { + return ret; + } + + rec(matrix, 0, 0, matrix.length, matrix[0].length, ret); + + return ret; + } + + public static void rec(int[][] matrix, int x, int y, int rows, int cols, List ret) { + if (rows <= 0 || cols <= 0) { + return; + } + + // first line + for (int i = 0; i < cols; i++) { + ret.add(matrix[x][y + i]); + } + + // right column + for (int i = 1; i < rows - 1; i++) { + ret.add(matrix[x + i][y + cols - 1]); + } + + // down row + if (rows > 1) { + for (int i = cols - 1; i >= 0; i--) { + ret.add(matrix[x + rows - 1][y + i]); + } + } + + // left column. GO UP. + if (cols > 1) { + for (int i = rows - 2; i > 0; i--) { + ret.add(matrix[x + i][y]); + } + } + + rec (matrix, x + 1, y + 1, rows - 2, cols - 2, ret); + } + + /* + Solution 2: + REF: http://blog.csdn.net/fightforyourdream/article/details/16876107?reload + 此算法比较不容易算错 + */ + public List spiralOrder2(int[][] matrix) { + List ret = new ArrayList(); + if (matrix == null || matrix.length == 0 + || matrix[0].length == 0) { + return ret; + } + + int x1 = 0; + int y1 = 0; + + int rows = matrix.length; + int cols = matrix[0].length; + + while (rows >= 1 && cols >= 1) { + // Record the right down corner of the matrix. + int x2 = x1 + rows - 1; + int y2 = y1 + cols - 1; + + // go through the WHOLE first line. + for (int i = y1; i <= y2; i++) { + ret.add(matrix[x1][i]); + } + + // go through the right column. + for (int i = x1 + 1; i < x2; i++) { + ret.add(matrix[i][y2]); + } + + // go through the WHOLE last row. + if (rows > 1) { + for (int i = y2; i >= y1; i--) { + ret.add(matrix[x2][i]); + } + } + + // the left column. + if (cols > 1) { + for (int i = x2 - 1; i > x1; i--) { + ret.add(matrix[i][y1]); + } + } + + // in one loop we deal with 2 rows and 2 cols. + rows -= 2; + cols -= 2; + x1++; + y1++; + } + + return ret; + } + + /* + Solution 3: + 使用方向矩阵来求解 + */ + public static List spiralOrder(int[][] matrix) { + List ret = new ArrayList(); + if (matrix == null || matrix.length == 0 + || matrix[0].length == 0) { + return ret; + } + + int rows = matrix.length; + int cols = matrix[0].length; + + int visitedRows = 0; + int visitedCols = 0; + + // indicate the direction of x + + // 1: means we are visiting the row by the right direction. + // -1: means we are visiting the row by the left direction. + int[] x = {1, 0, -1, 0}; + + // 1: means we are visiting the colum by the down direction. + // -1: means we are visiting the colum by the up direction. + int[] y = {0, 1, 0, -1}; + + // 0: right, 1: down, 2: left, 3: up. + int direct = 0; + + int startx = 0; + int starty = 0; + + int candidateNum = 0; + int step = 0; + while (true) { + if (x[direct] == 0) { + // visit Y axis. + candidateNum = rows - visitedRows; + } else { + // visit X axis + candidateNum = cols - visitedCols; + } + + if (candidateNum <= 0) { + break; + } + + ret.add(matrix[startx][starty]); + step++; + + if (step == candidateNum) { + step = 0; + visitedRows += x[direct] == 0 ? 0: 1; + visitedCols += y[direct] == 0 ? 0: 1; + + // move forward the direction. + direct ++; + direct = direct%4; + } + + // 根据方向来移动横坐标和纵坐标。 + startx += y[direct]; + starty += x[direct]; + } + + return ret; + } + + // Solution 4: Use Four corners. + public List spiralOrder4(int[][] matrix) { + List ret = new ArrayList(); + if (matrix == null ||matrix.length == 0) { + // 注意在非法的时候,应该返回空解,而不是一个NULL值 + return ret; + } + + // Record how many rows and cols we still have. + int rows = matrix.length; + int cols = matrix[0].length; + + // The four corners. + int top = 0; + int left = 0; + int bottom = rows - 1; + int right = cols - 1; + + // every time we go through two rows and two cols. + for (; rows > 0 && cols > 0; rows -= 2, cols -= 2, top++, left++, bottom--, right--) { + // the first line. + for (int i = left; i <= right; i++) { + ret.add(matrix[top][i]); + } + + // the right column. + for (int i = top + 1; i < bottom; i++) { + ret.add(matrix[i][right]); + } + + // the down line; + if (rows > 1) { + for (int j = right; j >= left; j--) { + ret.add(matrix[bottom][j]); + } + } + + // the left column. + if (cols > 1) { + for (int i = bottom - 1; i > top; i --) { + ret.add(matrix[i][left]); + } + } + } + + return ret; + } + + // Solution 4.2: don't use rows and cols. + public List spiralOrder3(int[][] matrix) { + List ret = new ArrayList(); + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + return ret; + } + + int rows = matrix.length; + int cols = matrix[0].length; + + int left = 0; + int right = cols - 1; + int top = 0; + int bottom = rows - 1; + + while (left <= right && top <= bottom) { + // line top. + for (int i = left; i <= right; i++) { + ret.add(matrix[top][i]); + } + + // line right; + for (int i = top + 1; i <= bottom - 1; i++) { + ret.add(matrix[i][right]); + } + + // line bottom. + if (top != bottom) { + for (int i = right; i >= left; i--) { + ret.add(matrix[bottom][i]); + } + } + + // line left; + if (left != right) { + for (int i = bottom - 1; i >= top + 1; i--) { + ret.add(matrix[i][left]); + } + } + + left++; + right--; + top++; + bottom--; + } + + return ret; + } +} diff --git a/array/SpiralOrder_1201.java b/array/SpiralOrder_1201.java new file mode 100644 index 0000000..422da10 --- /dev/null +++ b/array/SpiralOrder_1201.java @@ -0,0 +1,53 @@ +package Algorithms.array; + +import java.util.ArrayList; +import java.util.List; + +public class SpiralOrder_1201 { + public List spiralOrder(int[][] matrix) { + List ret = new ArrayList(); + if (matrix == null ||matrix.length == 0) { + // 注意在非法的时候,应该返回空解,而不是一个NULL值 + return ret; + } + + // Record how many rows and cols we still have. + int rows = matrix.length; + int cols = matrix[0].length; + + // The four coners. + int top = 0; + int left = 0; + int bottom = rows - 1; + int right = cols - 1; + + // every time we go through two rows and two cols. + for (; rows > 0 && cols > 0; rows -= 2, cols -= 2, top++, left++, bottom--, right--) { + // the first line. + for (int i = left; i <= right; i++) { + ret.add(matrix[top][i]); + } + + // the right column. + for (int i = top + 1; i < bottom; i++) { + ret.add(matrix[i][right]); + } + + // the down line; + if (rows > 1) { + for (int j = right; j >= left; j--) { + ret.add(matrix[bottom][j]); + } + } + + // the left column. + if (cols > 1) { + for (int i = bottom - 1; i > top; i --) { + ret.add(matrix[i][left]); + } + } + } + + return ret; + } +} \ No newline at end of file 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/array/Trap.java b/array/Trap.java new file mode 100644 index 0000000..8ef3fb0 --- /dev/null +++ b/array/Trap.java @@ -0,0 +1,35 @@ +package Algorithms.array; + +public class Trap { + public int trap(int[] A) { + if (A == null) { + return 0; + } + + int max = 0; + + int len = A.length; + int[] left = new int[len]; + int[] right = new int[len]; + + // count the highest bar from the left to the current. + for (int i = 0; i < len; i++) { + left[i] = i == 0 ? A[i]: Math.max(left[i - 1], A[i]); + } + + // count the highest bar from right to current. + for (int i = len - 1; i >= 0; i--) { + right[i] = i == len - 1 ? A[i]: Math.max(right[i + 1], A[i]); + } + + // count the largest water which can contain. + for (int i = 0; i < len; i++) { + int height = Math.min(right[i], left[i]); + if (height > A[i]) { + max += height - A[i]; + } + } + + return max; + } +} \ No newline at end of file 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/bfs/CloneGraph.java b/bfs/CloneGraph.java new file mode 100644 index 0000000..abd6d17 --- /dev/null +++ b/bfs/CloneGraph.java @@ -0,0 +1,65 @@ +package Algorithms.bfs; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class CloneGraph { + class UndirectedGraphNode { + int label; + List neighbors; + + UndirectedGraphNode(int x) { + label = x; + neighbors = new ArrayList(); + } + }; + + public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) { + if (node == null) { + return null; + } + + HashMap map = + new HashMap(); + + Queue q = new LinkedList(); + Queue qCopy = new LinkedList(); + + q.offer(node); + UndirectedGraphNode rootCopy = new UndirectedGraphNode(node.label); + qCopy.offer(rootCopy); + + // BFS the graph. + while (!q.isEmpty()) { + UndirectedGraphNode cur = q.poll(); + UndirectedGraphNode curCopy = qCopy.poll(); + + // bfs all the childern node. + for (UndirectedGraphNode child : cur.neighbors) { + // the node has already been copied. Just connect it and don't + // need to copy. + if (map.containsKey(child)) { + curCopy.neighbors.add(map.get(child)); + continue; + } + + // put all the children into the queue. + q.offer(child); + + // create a new child and add it to the parent. + UndirectedGraphNode childCopy = new UndirectedGraphNode( + child.label); + + curCopy.neighbors.add(childCopy); + qCopy.offer(childCopy); + + map.put(child, childCopy); + } + } + + return rootCopy; + } +} diff --git a/bfs/LadderLength.java b/bfs/LadderLength.java new file mode 100644 index 0000000..7ac5773 --- /dev/null +++ b/bfs/LadderLength.java @@ -0,0 +1,57 @@ +package Algorithms.bfs; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; + +public class LadderLength { + public int ladderLength(String start, String end, Set dict) { + if (start == null || end == null) { + return 0; + } + + // we use BFS to solve the problem. use a QUEUE to store all the solutions in one level. + Queue q = new LinkedList(); + + int level = 0; + + q.offer(start); + + // 避免计算到重复的字符串 + HashSet set = new HashSet(); + set.add(start); + + while (!q.isEmpty()) { + int size = q.size(); + + level++; + for (int i = 0; i < size; i++) { + String s = q.poll(); + + int len = s.length(); + for (int j = 0; j < len; j++) { + StringBuilder sb = new StringBuilder(s); + // 注意,这时是char + for (char c = 'a'; c <= 'z'; c++) { + sb.setCharAt(j, c); + + String tmp = sb.toString(); + + if (tmp.equals(end)) { + return level + 1; + } + + if (!set.contains(tmp) && dict.contains(tmp)) { + set.add(tmp); + q.offer(tmp); + } + } + } + + } + } + + return 0; + } +} diff --git a/bfs/LadderLength_1218_2014.java b/bfs/LadderLength_1218_2014.java new file mode 100644 index 0000000..99800ad --- /dev/null +++ b/bfs/LadderLength_1218_2014.java @@ -0,0 +1,73 @@ +package Algorithms.bfs; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; + +public class LadderLength_1218_2014 { + public static void main(String[] strs) { + HashSet set = new HashSet(); + set.add("hot"); + set.add("dot"); + set.add("dog"); + set.add("lot"); + set.add("log"); + set.add("cog"); + System.out.println(ladderLength("hit", "cog", set)); + } + + public static int ladderLength(String start, String end, Set dict) { + if (start == null || end == null || dict == null) { + return 0; + } + + // Bug 1: quese is a interface not a class + Queue q = new LinkedList(); + q.offer(start); + + HashSet set = new HashSet(); + set.add(start); + + // Bug 3: lever start from 1; + int level = 1; + + while (!q.isEmpty()) { + int size = q.size(); + + level++; + + for (int i = 0; i < size; i++) { + String s = q.poll(); + + int len = s.length(); + + for (int j = 0; j < len; j++) { + StringBuilder sb = new StringBuilder(s); + for (char c = 'a'; c <= 'z'; c++) { + // Bug 2: setCharAt + sb.setCharAt(j, c); + String tmp = sb.toString(); + + // Should be in the dict and not in the hashset. + if (set.contains(tmp) || !dict.contains(tmp)) { + continue; + } + + if (tmp.equals(end)) { + return level; + } + + set.add(tmp); + q.offer(tmp); + } + } + + } + } + + // When not found, return 0; + // "hot", "dog", ["hot","dog"] + return 0; + } +} \ No newline at end of file diff --git a/bfs/Solve.java b/bfs/Solve.java new file mode 100644 index 0000000..1b8ee48 --- /dev/null +++ b/bfs/Solve.java @@ -0,0 +1,118 @@ +package Algorithms.bfs; + +import java.util.LinkedList; +import java.util.Queue; + +//https://oj.leetcode.com/problems/surrounded-regions/ +public class Solve { + public static void main(String[] strs) { + char[][] board = { + {'X','O','X','O','X','O'}, + {'O','X','O','X','O','X'}, + {'X','O','X','O','X','O'}, + {'O','X','O','X','O','X'} + }; + + //solve(board); + } + + public void solve(char[][] board) { + if (board == null || board.length == 0 || board[0].length == 0) { + return; + } + + int rows = board.length; + int cols = board[0].length; + + // the first line and the last line. + for (int j = 0; j < cols; j++) { + bfs(board, 0, j); + bfs(board, rows - 1, j); + } + + // the left and right column + for (int i = 0; i < rows; i++) { + bfs(board, i, 0); + bfs(board, i, cols - 1); + } + + // capture all the nodes. + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (board[i][j] == 'O') { + board[i][j] = 'X'; + } else if (board[i][j] == 'B') { + board[i][j] = 'O'; + } + } + } + + return; + } + + public void bfs1(char[][] board, int i, int j) { + int rows = board.length; + int cols = board[0].length; + + Queue q = new LinkedList(); + q.offer(i * cols + j); + + while (!q.isEmpty()) { + int index = q.poll(); + + // Index is out of bound. + if (index < 0 || index >= rows * cols) { + continue; + } + + int x = index / cols; + int y = index % cols; + + if (board[x][y] != 'O') { + continue; + } + + board[x][y] = 'B'; + q.offer(index + 1); + q.offer(index - 1); + q.offer(index + cols); + q.offer(index - cols); + } + } + + public void bfs(char[][] board, int i, int j) { + int rows = board.length; + int cols = board[0].length; + + Queue q = new LinkedList(); + q.offer(i * cols + j); + + while (!q.isEmpty()) { + int index = q.poll(); + + int x = index / cols; + int y = index % cols; + + if (board[x][y] != 'O') { + continue; + } + + board[x][y] = 'B'; + if (y < cols - 1) { + q.offer(index + 1); + } + + if (y > 0) { + q.offer(index - 1); + } + + if (x > 0) { + q.offer(index - cols); + } + + if (x < rows - 1) { + q.offer(index + cols); + } + } + } +} \ No newline at end of file diff --git a/bfs/Solve_SurroundedRegions.java b/bfs/Solve_SurroundedRegions.java new file mode 100644 index 0000000..73e1944 --- /dev/null +++ b/bfs/Solve_SurroundedRegions.java @@ -0,0 +1,99 @@ +package Algorithms.bfs; + +import java.util.LinkedList; +import java.util.Queue; + +public class Solve_SurroundedRegions { + public void solve(char[][] board) { + if (board == null || board.length == 0 || board[0].length == 0) { + return; + } + + int rows = board.length; + int cols = board[0].length; + + // bfs the left and right side. + for (int i = 0; i < rows; i++) { + bfs(board, i, 0); + bfs(board, i, cols - 1); + } + + // bfs the first and the last line. + for (int i = 0; i < cols; i++) { + bfs(board, 0, i); + bfs(board, rows - 1, i); + } + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (board[i][j] == 'B') { + board[i][j] = 'O'; + } else if (board[i][j] == 'O') { + board[i][j] = 'X'; + } + } + } + + return; + } + + public void bfs(char[][] board, int i, int j) { + Queue q = new LinkedList(); + int cols = board[0].length; + + q.offer(i * cols + j); + + while(!q.isEmpty()) { + int index = q.poll(); + visit(board, index, q); + } + + } + + public void visit(char[][] board, int index, Queue q) { + int rows = board.length; + int cols = board[0].length; + + int i = index/cols; + int j = index%cols; + + // out of bound or visited. + if (i < 0 || i >= rows || j < 0 || j >= cols) { + return; + } + + if (board[i][j] != 'O') { + return; + } + + board[i][j] = 'B'; + + // 注意index的计算 + q.offer(index - 1); + q.offer(index + 1); + q.offer(index - cols); + q.offer(index + cols); + } + + public void dfs(char[][] board, int i, int j) { + int rows = board.length; + int cols = board[0].length; + + // out of bound or visited. + if (i < 0 || i >= rows || j < 0 || j >= cols) { + return; + } + + if (board[i][j] != 'O') { + return; + } + + board[i][j] = 'B'; + + // dfs the sorrounded regions. + dfs(board, i + 1, j); + dfs(board, i - 1, j); + dfs(board, i, j + 1); + dfs(board, i, j - 1); + } +} diff --git a/binarySearch/Divide.java b/binarySearch/Divide.java new file mode 100644 index 0000000..4f073ce --- /dev/null +++ b/binarySearch/Divide.java @@ -0,0 +1,90 @@ +package Algorithms.binarySearch; + +public class Divide { + public static void main(String[] strs) { + System.out.println(divide(-2147483648, -1)); + } + + public int divide1(int dividend, int divisor) { + long a = Math.abs((long)dividend); + + // ref : http://blog.csdn.net/kenden23/article/details/16986763 + // Note: ȡlongabsintСֵabsҲԭֵ + long b = Math.abs((long)divisor); + + int ret = 0; + // = ΪʱҲԼ + while (a >= b) { + // ж >= + for (long deduce = b, cnt = 1; a >= deduce; deduce <<= 1, cnt <<= 1) { + a -= deduce; + ret += cnt; + } + } + + // ȡλݳĹϵ + return (dividend > 0) ^ (divisor > 0) ? -ret: ret; + } + + public static int divide(int dividend, int divisor) { + if (divisor == 0) { + return Integer.MAX_VALUE; + } + + // Note: ȡlongabsintСֵabsҲԭֵ + long dividendTmp = Math.abs((long)dividend); + long divisorTmp = Math.abs((long)divisor); + + // bug 3: ret should use Long to avoid overflow. + long ret = 0; + // bug 2: should use dividentTmp > divisor as the while judge. + while (dividendTmp >= divisorTmp) { + // bug 1: should use Long for tmp. + long tmp = divisorTmp; + int rst = 1; + while(tmp <= dividendTmp) { + // bug 3: the two statement should inside the while LOOP. + ret += rst; + dividendTmp -= tmp; + + tmp <<= 1; + rst <<= 1; + } + } + // bug 4: out of range: + /* + Input: -2147483648, -1 + Output: -2147483648 + Expected: 2147483647 + */ + //ret = ((dividend > 0) ^ (divisor > 0)) ? -ret: ret; + ret = ((((dividend ^ divisor) >> 31) & 1) == 1) ? -ret: ret; + + if (ret > Integer.MAX_VALUE || ret < Integer.MIN_VALUE) { + return Integer.MAX_VALUE; + } else { + return (int)ret; + } + } + + public int divide3(int dividend, int divisor) { + long a = Math.abs((long)dividend); + long b = Math.abs((long)divisor); + + long ret = 0; + + while (a >= b) { + for (long tmp = b, cnt = 1; a >= tmp; tmp <<= 1, cnt <<= 1) { + ret += cnt; + a -= tmp; + } + } + + ret = (((dividend ^ divisor) >> 31) & 1) == 1 ? -ret: ret; + if (ret > Integer.MAX_VALUE || ret < Integer.MIN_VALUE) { + return Integer.MAX_VALUE; + } + + return (int)ret; + } +} \ No newline at end of file diff --git a/binarySearch/FindMin.java b/binarySearch/FindMin.java new file mode 100644 index 0000000..8855696 --- /dev/null +++ b/binarySearch/FindMin.java @@ -0,0 +1,78 @@ +package Algorithms.binarySearch; + +public class FindMin { + // Solution 1: + public int findMin1(int[] num) { + if (num == null || num.length == 0) { + return 0; + } + + if (num.length == 1) { + return num[0]; + } + + + // 至少有2个元素,才有讨论的价值 + int l = 0; + int r = num.length - 1; + + while (l < r) { + int mid = l + (r - l)/2; + // Means that there is no rotate. + if (num[mid] >= num[l] && num[mid] <= num[r]) { + return num[0]; + } + + // rotate > 0的情况 + if (l == r - 1) { + // 当只余下2个元素的时候,这里是断点,右边的是小值 + return num[r]; + } + + if (num[mid] >= num[l]) { + // The left side is sorted. Discard left. + l = mid; + } else { + // The right side is sorted. + r = mid; + } + } + + return 0; + } + + // solution 2: + public int findMin(int[] A) { + if (A == null || A.length == 0) { + return 0; + } + + if (A.length == 1) { + return A[0]; + } else if (A.length == 2) { + return Math.min(A[0], A[1]); + } + + // 至少有3个元素,才有讨论的价值 + int l = 0; + int r = A.length - 1; + + while (l < r - 1) { + int m = l + (r - l) / 2; + + // means that there is no rotate. + if (A[r] > A[l]) { + return A[0]; + } + + // left side is sorted. + if (A[m] > A[l]) { + l = m; + } else { + r = m; + } + } + + return A[r]; + } +} \ No newline at end of file diff --git a/binarySearch/FindMin2.java b/binarySearch/FindMin2.java new file mode 100644 index 0000000..d521f00 --- /dev/null +++ b/binarySearch/FindMin2.java @@ -0,0 +1,55 @@ +package Algorithms.binarySearch; + + +/* + * Find Minimum in Rotated Sorted Array II Total Accepted: 2541 Total Submissions: 9558 My Submissions Question Solution +Follow up for "Find Minimum in Rotated Sorted Array": +What if duplicates are allowed? + +Would this affect the run-time complexity? How and why? +Suppose a sorted array is rotated at some pivot unknown to you beforehand. + +(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). + +Find the minimum element. + +The array may contain duplicates. + * */ +public class FindMin2 { + public int findMin(int[] num) { + if (num == null || num.length == 0) { + return 0; + } + + int len = num.length; + if (len == 1) { + return num[0]; + } else if (len == 2) { + return Math.min(num[0], num[1]); + } + + int left = 0; + int right = len - 1; + + while (left < right - 1) { + int mid = left + (right - left) / 2; + // In this case, the array is sorted. + // 这一句很重要,因为我们移除一些元素后,可能会使整个数组变得有序... + if (num[left] < num[right]) { + return num[left]; + } + + // left side is sorted. CUT the left side. + if (num[mid] > num[left]) { + left = mid; + // left side is unsorted, right side is sorted. CUT the right side. + } else if (num[mid] < num[left]) { + right = mid; + } else { + left++; + } + } + + return Math.min(num[left], num[right]); + } +} diff --git a/binarySearch/FindPeakElement.java b/binarySearch/FindPeakElement.java new file mode 100644 index 0000000..836ae1a --- /dev/null +++ b/binarySearch/FindPeakElement.java @@ -0,0 +1,66 @@ +package Algorithms.binarySearch; + +public class FindPeakElement { + public int findPeakElement1(int[] num) { + if (num == null) { + return 0; + } + + if (num.length == 1) { + return 0; + } + + for (int i = 0; i < num.length; i++) { + if (i == 0) { + if (num[i] > num[i + 1]) { + return i; + } + continue; + } + + if (i == num.length - 1) { + if (num[i] > num[i - 1]) { + return i; + } + continue; + } + + if (num[i] > num[i + 1] && num[i] > num[i - 1]) { + return i; + } + } + + return -1; + } + + public int findPeakElement(int[] num) { + if (num == null) { + return 0; + } + + if (num.length == 1) { + return 0; + } + + int l = 0; + int r = num.length - 1; + + while (l < r - 1) { + int mid = l + (r - l) / 2; + if (num[mid] > num[mid + 1] && num[mid] > num[mid - 1]) { + return mid; + } + + if (num[mid] > num[mid - 1] && num[mid] < num[mid + 1]) { + // rising area. move right; + l = mid; + } else if (num[mid] < num[mid - 1] && num[mid] > num[mid + 1]) { + r = mid; + } else { + l = mid; + } + } + + return num[l] > num[r] ? l: r; + } +} \ No newline at end of file diff --git a/binarySearch/SearchRange.java b/binarySearch/SearchRange.java new file mode 100644 index 0000000..84770f6 --- /dev/null +++ b/binarySearch/SearchRange.java @@ -0,0 +1,71 @@ +package Algorithms.binarySearch; + +public class SearchRange { + public static void main(String[] strs) { + int[] A = {1}; + + System.out.println(searchRange(A, 0)[0] + " " + searchRange(A, 0)[1]); + } + + public static int[] searchRange(int[] A, int target) { + int[] ret = {-1, -1}; + + if (A == null || A.length == 0) { + return ret; + } + + int len = A.length; + int left = 0; + int right = len - 1; + + // so when loop end, there will be 2 elements in the array. + // search the left bound. + while (left < right - 1) { + int mid = left + (right - left) / 2; + if (target == A[mid]) { + // 如果相等,继续往左寻找边界 + right = mid; + } else if (target > A[mid]) { + // move right; + left = mid; + } else { + right = mid; + } + } + + if (A[left] == target) { + ret[0] = left; + } else if (A[right] == target) { + ret[0] = right; + } else { + return ret; + } + + left = 0; + right = len - 1; + // so when loop end, there will be 2 elements in the array. + // search the right bound. + while (left < right - 1) { + int mid = left + (right - left) / 2; + if (target == A[mid]) { + // 如果相等,继续往右寻找右边界 + left = mid; + } else if (target > A[mid]) { + // move right; + left = mid; + } else { + right = mid; + } + } + + if (A[right] == target) { + ret[1] = right; + } else if (A[left] == target) { + ret[1] = left; + } else { + return ret; + } + + return ret; + } +} diff --git a/binarySearch/searchInsert.java b/binarySearch/searchInsert.java new file mode 100644 index 0000000..370d2ad --- /dev/null +++ b/binarySearch/searchInsert.java @@ -0,0 +1,29 @@ +package Algorithms.binarySearch; + +public class searchInsert { + public static void main(String[] args) { + int[] A = {1,3,5,6}; + int target = 0; + + System.out.println(searchInsert(A, target)); + } + + public static int searchInsert(int[] A, int target) { + int low = 0, high = A.length-1; + int mid = low + (high-low)/2; + + while(low <= high){ + mid = low + (high-low)/2; + if(A[mid] == target){ + return mid; + }else if(target > A[mid]){ + low = mid+1; + }else{ + high = mid-1; + } + } + + // 返回下限值,此时刚好为适合插入的位置 + return low; + } +} diff --git a/combination/CombinationSum.java b/combination/CombinationSum.java new file mode 100644 index 0000000..5c845e3 --- /dev/null +++ b/combination/CombinationSum.java @@ -0,0 +1,42 @@ +package Algorithms.combination; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class CombinationSum { + public List> combinationSum(int[] candidates, int target) { + List> ret = new ArrayList>(); + if (candidates == null || candidates.length == 0) { + return ret; + } + + List path = new ArrayList(); + + // we should sort the candidates than do it. in this case we can get a non-descending order. + Arrays.sort(candidates); + + combinationSum(candidates, target, path, ret, 0); + return ret; + } + + public void combinationSum(int[] candidates, int target, List path, List> ret, int index) { + if (target == 0) { + // add the current set into the result. + ret.add(new ArrayList(path)); + return; + } + + if (target < 0) { + return; + } + + int len = candidates.length; + for (int i = index; i < len; i++) { + int num = candidates[i]; + path.add(num); + combinationSum(candidates, target - num, path, ret, i); + path.remove(path.size() - 1); + } + } +} diff --git a/combination/CombinationSum2.java b/combination/CombinationSum2.java new file mode 100644 index 0000000..d269c04 --- /dev/null +++ b/combination/CombinationSum2.java @@ -0,0 +1,82 @@ +package Algorithms.combination; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class CombinationSum2 { + public List> combinationSum2(int[] num, int target) { + List> ret = new ArrayList>(); + List path = new ArrayList(); + + if (num == null || num.length == 0) { + return ret; + } + + // before solve it, we just need to sort it. + Arrays.sort(num); + + // boolean[] isSelect = new boolean[num.length]; + // for (int i = 0; i < num.length; i++) { + // isSelect[i] = false; + // } + + //combinationSum2Help(num, isSelect, target, path, ret, 0); + + combinationSum2HelpMethod2(num, target, path, ret, 0); + + return ret; + } + + // Solution 1; + public void combinationSum2Help(int[] num, boolean[] isSelect, int target, + List path, List> ret, int index) { + if (target < 0) { + return; + } + + if (target == 0) { + // add a new solution. + ret.add(new ArrayList(path)); + } + + for (int i = index; i < num.length; i++) { + if (i > 0 && num[i] == num[i - 1] && !isSelect[i - 1]) { + continue; + } + path.add(num[i]); + isSelect[i] = true; + combinationSum2Help(num, isSelect, target - num[i], path, ret, i + 1); + path.remove(path.size() - 1); + isSelect[i] = false; + } + } + + // Solution 2; + public void combinationSum2HelpMethod2(int[] num, int target, + List path, List> ret, int index) { + if (target < 0) { + return; + } + + if (target == 0) { + // add a new solution. + ret.add(new ArrayList(path)); + } + + int pre = -1; + for (int i = index; i < num.length; i++) { + // 我们每次都只取第一个,因为我们不能取重复的元素。在所有元素里任何挑一个就行了。 + if (num[i] == pre) { + continue; + } + + pre = num[i]; + + path.add(num[i]); + combinationSum2HelpMethod2(num, target - num[i], path, ret, i + 1); + // 回溯 + path.remove(path.size() - 1); + } + } +} diff --git a/combination/CombinationSum2_1203.java b/combination/CombinationSum2_1203.java new file mode 100644 index 0000000..cb4c4cc --- /dev/null +++ b/combination/CombinationSum2_1203.java @@ -0,0 +1,68 @@ +package Algorithms.combination; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class CombinationSum2_1203 { + public List> combinationSum2(int[] num, int target) { + List> ret = new ArrayList>(); + if (num == null || num.length == 0) { + return ret; + } + + Arrays.sort(num); + + dfs(num, target, new ArrayList(), ret, 0); + return ret; + } + + public void dfs1(int[] num, int target, ArrayList path, List> ret, int index) { + if (target == 0) { + ret.add(new ArrayList(path)); + return; + } + + if (target < 0) { + return; + } + + // 注意,这里从 i = index开始 + // 每次只取第一个,例如 123334,到了333这里,我们第一次只取第1个3,因为我们选任何一个3是对组合来说是一个解。所以只 + // 第一次取就好了。 + int pre = -1; + for (int i = index; i < num.length; i++) { + int n = num[i]; + if (n == pre) { + continue; + } + pre = n; + path.add(n); + dfs(num, target - n, path, ret, i + 1); + path.remove(path.size() - 1); + } + } + + public void dfs(int[] num, int target, ArrayList path, List> ret, int index) { + if (target == 0) { + ret.add(new ArrayList(path)); + return; + } + + if (target < 0) { + return; + } + + // 注意,这里从 i = index开始 + // 每次只取第一个,例如 123334,到了333这里,我们第一次只取第1个3,因为我们选任何一个3是对组合来说是一个解。所以只 + // 第一次取就好了。 + for (int i = index; i < num.length; i++) { + int n = num[i]; + if (i != index && n == num[i - 1]) { + continue; + } + path.add(n); + dfs(num, target - n, path, ret, i + 1); + path.remove(path.size() - 1); + } + } +} \ No newline at end of file diff --git a/combination/CombinationSum_1203.java b/combination/CombinationSum_1203.java new file mode 100644 index 0000000..91d469f --- /dev/null +++ b/combination/CombinationSum_1203.java @@ -0,0 +1,43 @@ +package Algorithms.combination; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class CombinationSum_1203 { + public List> combinationSum(int[] candidates, int target) { + List> ret = new ArrayList>(); + if (candidates == null || candidates.length == 0) { + return ret; + } + + // Sort to avoid duplicate solutions. + Arrays.sort(candidates); + + dfs(candidates, target, new ArrayList(), ret, 0); + return ret; + } + + public void dfs(int[] candidates, int target, List path, List> ret, int index) { + if (target < 0) { + return; + } + + if (target == 0) { + ret.add(new ArrayList(path)); + return; + } + + // i 的起始值是跟排列的最主要区别。因为与顺序无关,所以我们必须只能是升序,也就是说下一个取值只能是i本身 + // 或是i的下一个。 + // 但是排列的话,可以再取前同的。1, 2 与2 1是不同的排列,但是同一个组合 + for (int i = index; i < candidates.length; i++) { + int num = candidates[i]; + path.add(num); + + // 注意,最后的参数是i,不是index!! + dfs(candidates, target - num, path, ret, i); + path.remove(path.size() - 1); + } + } +} \ No newline at end of file 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 diff --git a/combination/Combine_1203.java b/combination/Combine_1203.java new file mode 100644 index 0000000..eeda5b6 --- /dev/null +++ b/combination/Combine_1203.java @@ -0,0 +1,55 @@ +package Algorithms.combination; +import java.util.ArrayList; +import java.util.List; + +public class Combine_1203 { + public List> combine(int n, int k) { + List> ret = new ArrayList>(); + if (k == 0) { + ret.add(new ArrayList()); + return ret; + } + + // 注意:start应该从1开始。因为我们的数字是1 + dfs(n, k, new ArrayList(), ret, 1); + return ret; + } + + // SOLUTION 1: + // 注意,因为求的是组合,所以我们要考虑一下顺序问题,只需要考虑升序。这样的话就不会有重复的 + // 的组合。 + public void dfs1(int n, int k, List path, List> ret, int start) { + if (path.size() == k) { + ret.add(new ArrayList(path)); + return; + } + + // 注意这里的条件i <= n 取n也是合法的! + // Example: + for (int i = start; i <= n; i++) { + path.add(i); + + // 注意,最后一个参数是i + 1,不是start + 1!! + dfs(n, k, path, ret, i + 1); + path.remove(path.size() - 1); + } + } + + // SOLUTION 2: + public void dfs(int n, int k, List path, List> ret, int start) { + if (0 == k) { + ret.add(new ArrayList(path)); + return; + } + + // 注意这里的条件i <= n 取n也是合法的! + // Example: + for (int i = start; i <= (n - k + 1); i++) { + path.add(i); + + // 注意,最后一个参数是i + 1,不是start + 1!! + dfs(n, k - 1, path, ret, i + 1); + path.remove(path.size() - 1); + } + } +} \ No newline at end of file diff --git a/combination/LetterCombinations.java b/combination/LetterCombinations.java new file mode 100644 index 0000000..95ea2bc --- /dev/null +++ b/combination/LetterCombinations.java @@ -0,0 +1,35 @@ +package Algorithms.combination; + +import java.util.ArrayList; +import java.util.List; + +public class LetterCombinations { + String[] map = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; + + public List letterCombinations(String digits) { + List ret = new ArrayList(); + if (digits == null) { + return ret; + } + + dfs(digits, new StringBuilder(), ret, 0); + return ret; + } + + public void dfs(String digits, StringBuilder sb, List ret, int index) { + int len = digits.length(); + if (index == len) { + ret.add(sb.toString()); + return; + } + + // get the possiable selections. + String s = map[digits.charAt(index) - '0']; + for (int i = 0; i < s.length(); i++) { + sb.append(s.charAt(i)); + dfs(digits, sb, ret, index + 1); + sb.deleteCharAt(sb.length() - 1); + } + } + +} \ No newline at end of file diff --git a/dfs/Exist.java b/dfs/Exist.java new file mode 100644 index 0000000..3d53964 --- /dev/null +++ b/dfs/Exist.java @@ -0,0 +1,152 @@ +package Algorithms.dfs; + +public class Exist { + public boolean exist1(char[][] board, String word) { + if (board == null || word == null + || board.length == 0 || board[0].length == 0) { + return false; + } + + int rows = board.length; + int cols = board[0].length; + + boolean[][] visit = new boolean[rows][cols]; + + // i means the index. + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + // dfs all the characters in the matrix + if (dfs1(board, i, j, word, 0, visit)) { + return true; + } + } + } + + return false; + } + + public boolean dfs1(char[][] board, int i, int j, String word, int wordIndex, boolean[][] visit) { + int rows = board.length; + int cols = board[0].length; + + int len = word.length(); + if (wordIndex >= len) { + return true; + } + + // the index is out of bound. + if (i < 0 || i >= rows || j < 0 || j >= cols) { + return false; + } + + // the character is wrong. + if (word.charAt(wordIndex) != board[i][j]) { + return false; + } + + // 不要访问访问过的节点 + if (visit[i][j] == true) { + return false; + } + + visit[i][j] = true; + + // 递归 + // move down + if (dfs1(board, i + 1, j, word, wordIndex + 1, visit)) { + return true; + } + + // move up + if (dfs1(board, i - 1, j, word, wordIndex + 1, visit)) { + return true; + } + + // move right + if (dfs1(board, i, j + 1, word, wordIndex + 1, visit)) { + return true; + } + + // move left + if (dfs1(board, i, j - 1, word, wordIndex + 1, visit)) { + return true; + } + + // 回溯 + visit[i][j] = false; + return false; + } + + /* + * Solution 2: 可以省掉一个visit的数组 + * */ + public boolean exist(char[][] board, String word) { + if (board == null || word == null + || board.length == 0 || board[0].length == 0) { + return false; + } + + int rows = board.length; + int cols = board[0].length; + + // i means the index. + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + // dfs all the characters in the matrix + if (dfs(board, i, j, word, 0)) { + return true; + } + } + } + + return false; + } + + public boolean dfs(char[][] board, int i, int j, String word, int wordIndex) { + int rows = board.length; + int cols = board[0].length; + + int len = word.length(); + if (wordIndex >= len) { + return true; + } + + // the index is out of bound. + if (i < 0 || i >= rows || j < 0 || j >= cols) { + return false; + } + + // the character is wrong. + if (word.charAt(wordIndex) != board[i][j]) { + return false; + } + + // mark it to be '#', so we will not revisit this. + board[i][j] = '#'; + + // 递归 + // move down + if (dfs(board, i + 1, j, word, wordIndex + 1)) { + return true; + } + + // move up + if (dfs(board, i - 1, j, word, wordIndex + 1)) { + return true; + } + + // move right + if (dfs(board, i, j + 1, word, wordIndex + 1)) { + return true; + } + + // move left + if (dfs(board, i, j - 1, word, wordIndex + 1)) { + return true; + } + + // 回溯 + board[i][j] = word.charAt(wordIndex); + return false; + } +} \ No newline at end of file diff --git a/dfs/FiveChessman.java b/dfs/FiveChessman.java new file mode 100644 index 0000000..9e0c33f --- /dev/null +++ b/dfs/FiveChessman.java @@ -0,0 +1,148 @@ +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 代表我们现在正在扫描的点的坐标 + // 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) { + return null; + } + + // if it is 0, just return. + if (in[row][col] == 0) { + return null; + } + + // 必须是同边的棋子。例如,都是1,或都是2. + 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; + } +} 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/dfs/Partition.java b/dfs/Partition.java new file mode 100644 index 0000000..72b4fa1 --- /dev/null +++ b/dfs/Partition.java @@ -0,0 +1,125 @@ +package Algorithms.dfs; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class Partition { + public List> partition1(String s) { + List> ret = new ArrayList>(); + List path = new ArrayList(); + + if (s == null) { + return ret; + } + + HashMap map = new HashMap(); + + dfs(s, path, ret, 0, map); + + return ret; + } + + public boolean isPalindrom(String s) { + int len = s.length(); + if (len <= 1) { + return true; + } + + int left = 0; + int right = len - 1; + for (; left < right; left++, right--) { + if (s.charAt(right) != s.charAt(left)) { + return false; + } + } + + return true; + } + + /* + we use a map to store the solutions to reduce the times of computing. + */ + public void dfs(String s, List path, List> ret, int index, HashMap map) { + if (index == s.length()) { + ret.add(new ArrayList(path)); + return; + } + + for (int i = index; i < s.length(); i++) { + String sub = s.substring(index, i + 1); + + Boolean flag = map.get(sub); + if (flag == null) { + flag = isPalindrom(sub); + map.put(sub, flag); + } + + if (!flag) { + continue; + } + + path.add(sub); + dfs(s, path, ret, i + 1, map); + path.remove(path.size() - 1); + } + } + + public List> partition(String s) { + List> ret = new ArrayList>(); + List path = new ArrayList(); + + if (s == null) { + return ret; + } + + boolean[][] isPalindrom = buildPalindromDP(s); + + dfs2(s, path, ret, 0, isPalindrom); + + return ret; + } + + /* + * Solution 2: Use DP to reduce the duplicate count. + * */ + boolean[][] buildPalindromDP(String s) { + int len = s.length(); + boolean[][] D = new boolean[len][len]; + + for (int j = 0; j < len; j++) { + for (int i = 0; i <= j; i++) { + if (j == 0) { + D[i][j] = true; + continue; + } + + D[i][j] = s.charAt(i) == s.charAt(j) + && (j - i <= 2 || D[i + 1][j - 1]); + } + } + + return D; + } + + /* + we use a map to store the solutions to reduce the times of computing. + */ + public void dfs2(String s, List path, List> ret, int index, boolean[][] isPalindromDP) { + if (index == s.length()) { + ret.add(new ArrayList(path)); + return; + } + + for (int i = index; i < s.length(); i++) { + String sub = s.substring(index, i + 1); + if (!isPalindromDP[index][i]) { + continue; + } + + path.add(sub); + dfs2(s, path, ret, i + 1, isPalindromDP); + path.remove(path.size() - 1); + } + } +} diff --git a/dfs/Partition_2014_1229.java b/dfs/Partition_2014_1229.java new file mode 100644 index 0000000..46cbe91 --- /dev/null +++ b/dfs/Partition_2014_1229.java @@ -0,0 +1,149 @@ +package Algorithms.dfs; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class Partition_2014_1229 { + // Solution 1: The DFS version. + public List> partition1(String s) { + List> ret = new ArrayList>(); + if (s == null) { + return ret; + } + + dfs(s, 0, new ArrayList(), ret); + return ret; + } + + public static void dfs(String s, int index, List path, List> ret) { + int len = s.length(); + if (index == len) { + ret.add(new ArrayList(path)); + return; + } + + for (int i = index; i < len; i++) { + String sub = s.substring(index, i + 1); + if (!isPalindrome(sub)) { + continue; + } + + path.add(sub); + dfs(s, i + 1, path, ret); + path.remove(path.size() - 1); + } + } + + public static boolean isPalindrome(String s) { + int len = s.length(); + int left = 0; + int right = len - 1; + + while (left < right) { + if (s.charAt(left) != s.charAt(right)) { + return false; + } + left++; + right--; + } + + return true; + } + + // Solution 2: The DFS version with memory. + public List> partition2(String s) { + List> ret = new ArrayList>(); + if (s == null) { + return ret; + } + + // bug: new map error. + dfs2(s, 0, new ArrayList(), ret, new HashMap()); + return ret; + } + + public static void dfs2(String s, int index, List path, List> ret, HashMap map) { + int len = s.length(); + if (index == len) { + ret.add(new ArrayList(path)); + return; + } + + for (int i = index; i < len; i++) { + String sub = s.substring(index, i + 1); + if (!isPalindromeHash(sub, map)) { + continue; + } + + path.add(sub); + dfs2(s, i + 1, path, ret, map); + path.remove(path.size() - 1); + } + } + + // BUG 3: use boolean instead of Boolean. + public static boolean isPalindromeHash(String s, HashMap map) { + int len = s.length(); + int left = 0; + int right = len - 1; + + if (map.get(s) != null) { + return map.get(s); + } + + map.put(s, true); + while (left < right) { + if (s.charAt(left) != s.charAt(right)) { + map.put(s, false); + return false; + } + left++; + right--; + } + + return true; + } + + // Solution 3: Use DP to determine the palindrome first. + public List> partition(String s) { + List> ret = new ArrayList>(); + if (s == null) { + return ret; + } + + int len = s.length(); + + // D[i][j]: if this a palindrom for s.substring(i, j + 1). + boolean[][] D = new boolean[len][len]; + + for (int j = 0; j < len; j++) { + for (int i = 0; i <= j; i++) { + D[i][j] = s.charAt(i) == s.charAt(j) && (j - i <= 2 || D[i + 1][j - 1]); + } + } + + // bug: new map error. + dfs3(s, 0, new ArrayList(), ret, D); + return ret; + } + + public static void dfs3(String s, int index, List path, List> ret, boolean[][] D) { + int len = s.length(); + if (index == len) { + ret.add(new ArrayList(path)); + return; + } + + for (int i = index; i < len; i++) { + String sub = s.substring(index, i + 1); + if (!D[index][i]) { + continue; + } + + path.add(sub); + dfs3(s, i + 1, path, ret, D); + path.remove(path.size() - 1); + } + } +} \ No newline at end of file diff --git a/dfs/Permute.java b/dfs/Permute.java new file mode 100644 index 0000000..9fd4254 --- /dev/null +++ b/dfs/Permute.java @@ -0,0 +1,34 @@ +package Algorithms.dfs; + +import java.util.ArrayList; +import java.util.List; + +public class Permute { + public List> permute(int[] num) { + List> ret = new ArrayList>(); + if (num == null || num.length == 0) { + return ret; + } + + dfs(num, new ArrayList(), ret); + return ret; + } + + public void dfs(int[] num, List path, List> ret) { + int len = num.length; + if (path.size() == len) { + ret.add(new ArrayList(path)); + return; + } + + for (int i = 0; i < len; i++) { + if (path.contains(num[i])) { + continue; + } + + path.add(num[i]); + dfs(num, path, ret); + path.remove(path.size() - 1); + } + } +} \ No newline at end of file diff --git a/dfs/SolveNQueens.java b/dfs/SolveNQueens.java new file mode 100644 index 0000000..dc6d6f6 --- /dev/null +++ b/dfs/SolveNQueens.java @@ -0,0 +1,99 @@ +package Algorithms.dfs; + +import java.util.ArrayList; +import java.util.List; + +public class SolveNQueens { + public static void main(String[] strs) { + List list = solveNQueens(9); + + for (String[] strss: list) { + for (String s: strss) { + //System.out.println(s); + } + + } + + Long ret = Long.MAX_VALUE; + int a = Integer.MAX_VALUE; + if (ret == a) { + System.out.println(true); + } + + //System.out.println(solveNQueens(4).toString()); + } + + public static List solveNQueens(int n) { + List ret = new ArrayList(); + if (n == 0) { + return ret; + } + + StringBuilder[] path = new StringBuilder[n]; + for (int i = 0; i < n; i++) { + path[i] = new StringBuilder(); + for (int j = 0; j < n; j++) { + path[i].append('.'); + } + } + dfs(n, path, ret, 0); + + return ret; + } + + // 递归定义为:棋盘上已经有一些棋子,还需要放n个皇后,求所有的可能的解. + // 那么 我们可以先放1个,这里有多种可能,然后再用递归继续求解即可。 + public static void dfs(int n, StringBuilder[] path, List ret, int index) { + int rows = path.length; + + if (n == 0) { + String[] strs = new String[rows]; + for (int i = 0; i < rows; i++) { + strs[i] = path[i].toString(); + } + ret.add(strs); + return; + } + + // index out of bound; + if (index >= rows * rows) { + return; + } + + // 找到一个地方先放一个棋子 + for (int i = index; i < rows*rows; i++) { + int row = i / rows; + int col = i % rows; + + if (!canPut(path, row, col)) { + // 这个位置必须是可放置的 + continue; + } + path[row].setCharAt(col, 'Q'); + + // 向下一级递归 + dfs(n - 1, path, ret, i + 1); + + //回溯 + path[row].setCharAt(col, '.'); + + } + + return; + } + + // put a chessman, and disable some positions in the chessboard. + public static boolean canPut(StringBuilder[] path, int row, int col) { + for (int i = 0; i < path.length; i++) { + for (int j = 0; j < path.length; j++) { + if (path[i].charAt(j) == 'Q' && + (i == row || j == col || Math.abs(i - row) == Math.abs(j - col)) + ) { + return false; + } + } + } + + return true; + } +} diff --git a/dfs/SolveNQueens_v2.java b/dfs/SolveNQueens_v2.java new file mode 100644 index 0000000..d2af945 --- /dev/null +++ b/dfs/SolveNQueens_v2.java @@ -0,0 +1,104 @@ +package Algorithms.dfs; + +import java.util.ArrayList; +import java.util.List; + +/* + * N-Queens Total Accepted: 16418 Total Submissions: 63309 My Submissions +The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other. + + + +Given an integer n, return all distinct solutions to the n-queens puzzle. + +Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively. + +For example, +There exist two distinct solutions to the 4-queens puzzle: + +[ + [".Q..", // Solution 1 + "...Q", + "Q...", + "..Q."], + + ["..Q.", // Solution 2 + "Q...", + "...Q", + ".Q.."] +] + * */ +public class SolveNQueens_v2 { + public static List solveNQueens(int n) { + List ret = new ArrayList(); + if (n == 0) { + return ret; + } + + ArrayList cols = new ArrayList(); + + solveNQueensHelp(n, cols, ret); + + return ret; + } + + // 根据列值把解集合算出来 + public static String[] createSol(int n, ArrayList cols) { + String[] ret = new String[n]; + + for (int i = 0; i < n; i++) { + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < n; j++) { + sb.append('.'); + } + sb.setCharAt(cols.get(i), 'Q'); + ret[i] = sb.toString(); + } + + return ret; + } + + public static boolean isValid(ArrayList cols, int c) { + for (int i = 0; i < cols.size(); i++) { + // 与某皇后在同一列 + if (c == cols.get(i)) { + return false; + } + + // 在交叉2个方向 + // cols.size() 是新插入的皇后的行数 + if (cols.size() - i == Math.abs(c - cols.get(i))) { + return false; + } + } + + return true; + } + + /* + * n: 表示需要放多少个皇后 + * cols: 存放每一行皇后的列值。 我们在每一行放一个皇后,所以只需要算出第一行皇后的列值即可 + * ret: 返回值 + * */ + public static void solveNQueensHelp(int n, ArrayList cols, List ret) { + // 每一行的皇后的坐标都确定了。 + if (cols.size() == n) { + String[] sol = createSol(n, cols); + ret.add(sol); + return; + } + + // DFS 某一行中所有的位置,看是否可以放置一个皇后. + // 如果这一行根本没有找到解,会直接返回 + for (int i = 0; i < n; i++) { + // 判断这个位置是否与已经放好的皇后冲突 + if (!isValid(cols, i)) { + continue; + } + + cols.add(i); + solveNQueensHelp(n, cols, ret); + cols.remove(cols.size() - 1); + } + } +} \ No newline at end of file diff --git a/dfs/Subsets.java b/dfs/Subsets.java new file mode 100644 index 0000000..478fe14 --- /dev/null +++ b/dfs/Subsets.java @@ -0,0 +1,67 @@ +package Algorithms.dfs; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Subsets { + public List> subsets(int[] S) { + List> ret = new ArrayList>(); + List path = new ArrayList(); + + if (S == null) { + return ret; + } + + Arrays.sort(S); + + subsets(S, path, ret, 0); + + return ret; + } + + public void subsets(int[] S, List path, List> ret, int index) { + // 把当前的结果可以添加到结果集中. 空集也算是一种集合 + ret.add(new ArrayList(path)); + + for (int i = index; i < S.length; i++) { + path.add(S[i]); + + // 注意!这里的index要填写i + 1,而不是index,开始老是会犯错。 + subsets(S, path, ret, i + 1); + path.remove(path.size() - 1); + } + } + + public List> subsets2(int[] S) { + List> ret = new ArrayList>(); + if (S == null || S.length == 0) { + return ret; + } + + int len = S.length; + Arrays.sort(S); + + // forget to add (long). + long numOfSet = (long)Math.pow(2, len); + + for (int i = 0; i < numOfSet; i++) { + // bug 3: should use tmp - i. + long tmp = i; + + ArrayList list = new ArrayList(); + while (tmp != 0) { + // bug 2: use error NumberOfTrailingZeros. + int indexOfLast1 = Long.numberOfTrailingZeros(tmp); + list.add(S[indexOfLast1]); + + // clear the bit. + tmp ^= (1 << indexOfLast1); + } + + ret.add(list); + } + + return ret; + } +} + diff --git a/dfs/SubsetsWithDup.java b/dfs/SubsetsWithDup.java new file mode 100644 index 0000000..5fa39b2 --- /dev/null +++ b/dfs/SubsetsWithDup.java @@ -0,0 +1,38 @@ +package Algorithms.dfs; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class SubsetsWithDup { + public List> subsetsWithDup(int[] num) { + List> ret = new ArrayList>(); + + if (num == null) { + return ret; + } + + Arrays.sort(num); + + dfs(num, new ArrayList(), ret, 0); + + return ret; + } + + public void dfs(int[] num, List path, List> ret, int index) { + ret.add(new ArrayList(path)); + + for (int i = index; i < num.length; i++) { + // skip the duplicate. + if (i > index && num[i] == num[i - 1]) { + continue; + } + + path.add(num[i]); + // 注意:这里是i + 1不是index + 1!!! + dfs(num, path, ret, i + 1); + path.remove(path.size() - 1); + } + + } +} diff --git a/dfs/TotalNQueens.java b/dfs/TotalNQueens.java new file mode 100644 index 0000000..47d9ec5 --- /dev/null +++ b/dfs/TotalNQueens.java @@ -0,0 +1,55 @@ +package Algorithms.dfs; + +import java.util.ArrayList; + +public class TotalNQueens { + public int totalNQueens(int n) { + if (n == 0) { + return 0; + } + + ArrayList cols = new ArrayList(); + + return dfs(n, cols, 0); + } + + public int dfs(int n, ArrayList cols, int row) { + // 如果row 超过范围,返回1 + // base case 已经完成任务,应该是1种解法 因为前面已经固定,现在也不能再放了 + if (row == n) { + return 1; + } + + int sum = 0; + + // 在当前行,尝试放置棋子 + for (int i = 0; i < n; i++) { + // 不能放的位置 跳过 + if (!isValid(cols, i)) { + continue; + } + + cols.add(i); + sum += dfs(n, cols, row + 1); + cols.remove(cols.size() - 1); + } + + return sum; + } + + public boolean isValid(ArrayList cols, int col) { + for (int i = 0; i < cols.size(); i++) { + if (col == cols.get(i)) { + // same column. + return false; + } + + // diagonal. From the left up to the right down. + if (cols.size() - i == Math.abs(col - cols.get(i))) { + return false; + } + } + + return true; + } +} \ No newline at end of file diff --git a/dfs/totalNQueens_1218_2014.java b/dfs/totalNQueens_1218_2014.java new file mode 100644 index 0000000..5c7e7ce --- /dev/null +++ b/dfs/totalNQueens_1218_2014.java @@ -0,0 +1,55 @@ +package Algorithms.dfs; + +import java.util.ArrayList; + +public class TotalNQueens_1218_2014 { + public int totalNQueens(int n) { + if (n == 0) { + return 0; + } + + // Bug 1: forget to modify the parameters of the function. + return dfs(n, 0, new ArrayList()); + } + + public int dfs(int n, int row, ArrayList path) { + if (row == n) { + // The base case: 当最后一行,皇后只有1种放法(就是不放) + return 1; + } + + int num = 0; + + // The queen can select any of the slot. + for (int i = 0; i < n; i++) { + if (!isValid(path, i)) { + continue; + } + path.add(i); + + // All the solutions is all the possibilities are add up. + num += dfs(n, row + 1, path); + path.remove(path.size() - 1); + } + + return num; + } + + public boolean isValid(ArrayList path, int col) { + int size = path.size(); + for (int i = 0; i < size; i++) { + // The same column with any of the current queen. + if (col == path.get(i)) { + return false; + } + + // diagonally lines. + // Bug 2: forget to add a ')' + if (size - i == Math.abs(col - path.get(i))) { + return false; + } + } + + return true; + } +} \ No newline at end of file diff --git a/divide2/Pow.java b/divide2/Pow.java new file mode 100644 index 0000000..3f01170 --- /dev/null +++ b/divide2/Pow.java @@ -0,0 +1,36 @@ +package Algorithms.divide2; + +public class Pow { + 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; + } + + if (x == 1 || n == 0) { + return 1; + } + + // Because when we deal with -2147483648, we can't get right -n + // cause -n == n when it is -2147483648. + if (n < 0) { + double ret1 = x * pow(x, -(1 + n)); + return 1/(double)ret1; + } + + int m = n%2; + + // count + double ret = pow(x, n/2); + ret *= ret; + if (m == 1) { + ret *= x; + } + + return ret; + } +} \ No newline at end of file diff --git a/divide2/Pow_1219_2014.java b/divide2/Pow_1219_2014.java new file mode 100644 index 0000000..c7b5044 --- /dev/null +++ b/divide2/Pow_1219_2014.java @@ -0,0 +1,36 @@ +package Algorithms.divide2; + +public class Pow_1219_2014 { + public double pow(double x, int n) { + if (x == 0) { + return 0; + } + + // base case: when n = 0, the result is 1; + if (n == 0) { + return 1; + } + + /* + 递归的主体部分 + */ + + // X^(-n) = X^(n + 1) * X + // X^n = 1/(x^(-n)) + if (n < 0) { + double ret = x * pow(x, -(n + 1)); + return (double)1/ret; + } + + // 将求pow对半分。再将结果相乘 + double ret = pow(x, n / 2); + ret = ret * ret; + + //如果有余数,再乘以x本身。 + if (n % 2 != 0) { + ret = ret * x; + } + + return ret; + } +} \ No newline at end of file diff --git a/divide2/SearchInsert.java b/divide2/SearchInsert.java new file mode 100644 index 0000000..cd9a58f --- /dev/null +++ b/divide2/SearchInsert.java @@ -0,0 +1,60 @@ +package Algorithms.divide2; + +public class SearchInsert { + public int searchInsert1(int[] A, int target) { + if (A == null || A.length == 0) { + return 0; + } + + int left = 0; + int right = A.length - 1; + + while (left < right - 1) { + int mid = left + (right - left) / 2; + int num = A[mid]; + + if (num == target) { + return mid; + } else if (num < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + // bug 1: should use <= + if (target <= A[left]) { + return left; + // bug 2: should use <= . consider that may the result exit in left or right. + } else if (target <= A[right]) { + return right; + } + + return right + 1; + } + + // sol 2: + public int searchInsert(int[] A, int target) { + if (A == null || A.length == 0) { + return 0; + } + + int left = 0; + int right = A.length - 1; + + while (left <= right) { + int mid = left + (right - left) / 2; + int num = A[mid]; + + if (num == target) { + return mid; + } else if (num < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + return left; + } +} \ No newline at end of file diff --git a/divide2/SearchMatrix.java b/divide2/SearchMatrix.java new file mode 100644 index 0000000..b58055d --- /dev/null +++ b/divide2/SearchMatrix.java @@ -0,0 +1,36 @@ +package Algorithms.divide2; + +public class SearchMatrix { + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + return false; + } + + int rows = matrix.length; + int cols = matrix[0].length; + + int num = rows * cols; + + int left = 0; + int right = num - 1; + + while (left <= right) { + int mid = left + (right - left) / 2; + + int row = mid / cols; + int col = mid % cols; + + int n = matrix[row][col]; + + if (n == target) { + return true; + } else if (n < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + return false; + } +} diff --git a/divide2/SearchRange.java b/divide2/SearchRange.java new file mode 100644 index 0000000..5ac4afa --- /dev/null +++ b/divide2/SearchRange.java @@ -0,0 +1,55 @@ +package Algorithms.divide2; + +public class SearchRange { + public int[] searchRange(int[] A, int target) { + int[] ret = {-1, -1}; + if (A == null || A.length == 0) { + return ret; + } + + int l = 0; + int r = A.length - 1; + + // Find the left bound. + while (l < r - 1) { + int mid = l + (r - l) / 2; + if (A[mid] == target) { + r = mid; + } else if (A[mid] > target) { + r = mid; + } else { + l = mid; + } + } + + if (A[l] == target) { + ret[0] = l; + } else if (A[r] == target) { + ret[0] = r; + } else { + return ret; + } + + l = 0; + r = A.length - 1; + // Find the right bound. + while (l < r - 1) { + int mid = l + (r - l) / 2; + if (A[mid] == target) { + l = mid; + } else if (A[mid] > target) { + r = mid; + } else { + l = mid; + } + } + + if (A[r] == target) { + ret[1] = r; + } else { + ret[1] = l; + } + + return ret; + } +} \ No newline at end of file diff --git a/divide2/Sqrt.java b/divide2/Sqrt.java new file mode 100644 index 0000000..7e8a9df --- /dev/null +++ b/divide2/Sqrt.java @@ -0,0 +1,28 @@ +package Algorithms.divide2; + +public class Sqrt { + public int sqrt(int x) { + if (x == 1 || x == 0) { + return x; + } + + int left = 1; + int right = x; + + while (left < right - 1) { + int mid = left + (right - left) / 2; + int quo = x / mid; + + if (quo == mid) { + return quo; + // mid is too big + } else if (quo < mid) { + right = mid; + } else { + left = mid; + } + } + + return left; + } +} \ No newline at end of file diff --git a/dp/CanJump.java b/dp/CanJump.java new file mode 100644 index 0000000..7efe4e9 --- /dev/null +++ b/dp/CanJump.java @@ -0,0 +1,82 @@ +package Algorithms.dp; + +public class CanJump { + public static void main(String[] strs) { + //int[] A = { 2, 2, 3, 4, 5 }; + } + + // DP1. + public boolean canJump1(int[] A) { + if (A == null || A.length == 0) { + return false; + } + + int len = A.length; + boolean[] can = new boolean[len]; + can[0] = true; + + for (int i = 1; i < len; i++) { + can[i] = false; + for (int j = 0; j < i; j++) { + // j can arrive and can jump to i. + if (can[j] && A[j] >= i - j) { + can[i] = true; + break; + } + } + } + + return can[len - 1]; + } + + // DP2. + public boolean canJump2(int[] A) { + if (A == null || A.length == 0) { + return false; + } + + int len = A.length; + + for (int i = 1; i < len; i++) { + boolean can = false; + for (int j = 0; j < i; j++) { + // j can arrive and can jump to i. + if (A[j] >= i - j) { + // 说明i是可达的,置标记位 + can = true; + break; + } + } + + // 优化:如果某一步已经到不了了,后面的也不必再计算了. + if (!can) { + return false; + } + } + + return true; + } + + // 3. DFS. + public static boolean canJump3(int[] A) { + if (A == null || A.length == 0) { + return false; + } + + return canJump(A, A.length - 1); + } + + public static boolean canJump(int[] A, int index) { + if (index == 0) { + return true; + } + + for (int i = 0; i <= index - 1; i++) { + if (A[i] >= index - i) { + return canJump(A, i); + } + } + + return false; + } +} diff --git a/dp/Candy.java b/dp/Candy.java new file mode 100644 index 0000000..443423f --- /dev/null +++ b/dp/Candy.java @@ -0,0 +1,34 @@ +package Algorithms.dp; + +public class Candy { + public int candy(int[] ratings) { + if (ratings == null || ratings.length == 0) { + return 0; + } + + + int len = ratings.length; + int[] num = new int[len]; + + // go from left to right; + for (int i = 0; i < len; i++) { + if (i > 0 && ratings[i] > ratings[i - 1]) { + num[i] = num[i - 1] + 1; + } else { + num[i] = 1; + } + } + + // go from right to left; + int sum = 0; + for (int i = len - 1; i >= 0; i--) { + if (i < len - 1 && ratings[i] > ratings[i + 1]) { + num[i] = Math.max(num[i], num[i + 1] + 1); + } + sum += num[i]; + } + + return sum; + } +} + diff --git a/dp/Fibonacci.java b/dp/Fibonacci.java new file mode 100644 index 0000000..e376d9e --- /dev/null +++ b/dp/Fibonacci.java @@ -0,0 +1,84 @@ +package Algorithms.dp; + +import java.util.ArrayList; +import java.util.HashMap; + +/************************************************************************* + * 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, 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 second + first; + } + + 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(10, new HashMap()) + " "); +// for (int i = 1; i <= N; i++) { +// System.out.print(fib(i) + " "); +// } + + ArrayList list = fibDp(10); + System.out.println(list.toString()); + } + +} diff --git a/dp/GetRow.java b/dp/GetRow.java new file mode 100644 index 0000000..aa2828c --- /dev/null +++ b/dp/GetRow.java @@ -0,0 +1,51 @@ +package Algorithms.dp; + +import java.util.ArrayList; +import java.util.List; + +public class GetRow { + public List getRow1(int rowIndex) { + List pre = new ArrayList(); + List cur = new ArrayList(); + + if (rowIndex < 0) { + return cur; + } + + // 娉ㄦ剰杩欓噷鐨剅owIndex璺熶笂涓�鐨勬剰涔変笉涓�牱锛佽繖涓槸绱㈠紩锛宱rz... + // 鎵�互鎴戜滑瑕佺敤<= + for (int i = 0; i <= rowIndex; i++) { + // 绗琲琛屾湁i + 1涓厓绱� + cur = new ArrayList(); + for (int j = 0; j < i + 1; j++) { + if (j == 0 || j == i) { + cur.add(1); + } else { + cur.add(pre.get(j) + pre.get(j - 1)); + } + } + pre = cur; + } + + return cur; + } + + // SOLUTION 2: DO IT just inplace + public List getRow(int rowIndex) { + List ret = new ArrayList(); + + for (int i = 0; i <= rowIndex; i++) { + for (int j = i; j >= 0; j--) { + if (j == i) { + ret.add(1); + } else if (j != 0) { + // ERROR: use add instead of set + //ret.add(ret.get(j) + ret.get(j - 1)); + ret.set(j, ret.get(j) + ret.get(j - 1)); + } + } + } + + return ret; + } +} \ No newline at end of file diff --git a/dp/IsInterleave.java b/dp/IsInterleave.java new file mode 100644 index 0000000..395fc29 --- /dev/null +++ b/dp/IsInterleave.java @@ -0,0 +1,181 @@ +package Algorithms.dp; + +public class IsInterleave { + public static void main(String[] strs) { + // String s1 = "aabcc"; + // String s2 = "dbbca"; + String s1 = "a"; + String s2 = ""; + String s3 = "a"; + + // String s3 = "aadbbcbcac"; + // String s31 = "aadbbbaccc"; + // + + System.out.println(isInterleave(s1, s2, s3)); + } + + // Solution1: Recursion with memory + public static boolean isInterleave1(String s1, String s2, String s3) { + if (s1 == null || s2 == null || s3 == null) { + return false; + } + + int len1 = s1.length(); + int len2 = s2.length(); + int len3 = s3.length(); + + // The length is not equal, just return false. + if (len1 + len2 != len3) { + return false; + } + + int[][][] memory = new int[len1 + 1][len2 + 1][len3 + 1]; + for (int i = 0; i <= len1; i++) { + for (int j = 0; j <= len2; j++) { + for (int k = 0; k <= len3; k++) { + memory[i][j][k] = -1; + } + } + } + + return recMemory(s1, 0, s2, 0, s3, 0, memory); + } + + public static boolean recMemory(String s1, int index1, String s2, + int index2, String s3, int index3, int[][][] memory) { + int len1 = s1.length(); + int len2 = s2.length(); + int len3 = s3.length(); + + if (index3 == len3 && index1 == len1 && index2 == len2) { + return true; + } + + if (memory[index1][index2][index3] != -1) { + return memory[index1][index2][index3] == 1; + } + + // 第一个字符,有2种可能:来自s1, 或是来自s2 + boolean ret = false; + if (index1 < len1 && s1.charAt(index1) == s3.charAt(index3)) { + ret = recMemory(s1, index1 + 1, s2, index2, s3, index3 + 1, memory); + } + + // 如果不成功(首字母不来自于s1),尝试另一种可能 + if (!ret && index2 < len2 && s2.charAt(index2) == s3.charAt(index3)) { + ret = recMemory(s1, index1, s2, index2 + 1, s3, index3 + 1, memory); + } + + memory[index1][index2][index3] = ret ? 1 : 0; + return ret; + } + + // Solution2: Recursion with memory + // 思考了一下看了一下过去的代码,发现其实我们用不到三维数组,因为len1 + len2 = len3, + // 所以第三维根本可以省略嘛 + public static boolean isInterleave2(String s1, String s2, String s3) { + if (s1 == null || s2 == null || s3 == null) { + return false; + } + + int len1 = s1.length(); + int len2 = s2.length(); + int len3 = s3.length(); + + // The length is not equal, just return false. + if (len1 + len2 != len3) { + return false; + } + + int[][] memory = new int[len1 + 1][len2 + 1]; + for (int i = 0; i <= len1; i++) { + for (int j = 0; j <= len2; j++) { + memory[i][j] = -1; + } + } + + return recMemory2(s1, 0, s2, 0, s3, 0, memory); + } + + public static boolean recMemory2(String s1, int index1, String s2, + int index2, String s3, int index3, int[][] memory) { + int len1 = s1.length(); + int len2 = s2.length(); + int len3 = s3.length(); + + // index3 走到最后了,其实意思即是这个字符串为空,因为len1+len2+len3相等,说明其它两个也是空,必然返回true + if (index3 == len3) { + return true; + } + + if (memory[index1][index2] != -1) { + return memory[index1][index2] == 1; + } + + // 第一个字符,有2种可能:来自s1, 或是来自s2 + boolean ret = false; + // 注意,一定要判定index1 是否越界,否则会出问题 + if (index1 < len1 && s1.charAt(index1) == s3.charAt(index3)) { + ret = recMemory2(s1, index1 + 1, s2, index2, s3, index3 + 1, memory); + } + + // 如果不成功(首字母不来自于s1),尝试另一种可能,即有可能是来自s2的 + // 注意,一定要判定index2 是否越界,否则会出问题 + // 另外,我们判断!ret 的目的是省去重复计算,如果前一个判断已经是TRUE了,这里就不必再算了。 + if (!ret && index2 < len2 && s2.charAt(index2) == s3.charAt(index3)) { + ret = recMemory2(s1, index1, s2, index2 + 1, s3, index3 + 1, memory); + } + + memory[index1][index2] = ret ? 1 : 0; + return ret; + } + + // Solution3: + // DP解法 + // D[i][j]: 定义为s1 (前i个字符) s2(前j个字符) s3(i+j) 是不是交叉字符 + // (s1.i == s3.(i+j) && D[i-1][j]) || (s2.j == s3.(i+j) && D[i][j - 1]) + public static boolean isInterleave(String s1, String s2, String s3) { + if (s1 == null || s2 == null || s3 == null) { + return false; + } + + int len1 = s1.length(); + int len2 = s2.length(); + int len3 = s3.length(); + + // The length is not equal, just return false. + if (len1 + len2 != len3) { + return false; + } + + // 注意,这里要用len1 + 1,因为我们要从0算到len1 (0表示s1取空) + // D[0][0] = true + boolean[][] D = new boolean[len1 + 1][len2 + 1]; + for (int i = 0; i <= len1; i++) { + for (int j = 0; j <= len2; j++) { + if (i == 0 && j == 0) { + D[i][j] = true; + } else { + boolean b1 = false; + // the index in s3. + int index = i + j - 2; + if (i > 0 && s1.charAt(i - 1) == s2.charAt(index) + && D[i - 1][j]) { + b1 = true; + } + + boolean b2 = false; + if (j > 0 && s2.charAt(j - 1) == s2.charAt(index) + && D[i][j - 1]) { + b2 = true; + } + + D[i][j] = b1 | b2; + } + } + } + + return D[len1][len2]; + } +} diff --git a/dp/IsMatch.java b/dp/IsMatch.java new file mode 100644 index 0000000..f5dd65c --- /dev/null +++ b/dp/IsMatch.java @@ -0,0 +1,123 @@ +package Algorithms.dp; + +public class IsMatch { + public static void main(String[] strs) { +// System.out.println(isMatch("aa","a")); +// System.out.println(isMatch("aa","aa**")); +// System.out.println(isMatch("aaa","aa")); + System.out.println(isMatch("hi", "*?")); +// System.out.println(isMatch("aa","a*")); +// System.out.println(isMatch("ab","?*")); +// System.out.println(isMatch("aab", "c*a*b")); + } + + public static boolean isMatch1(String s, String p) { + if (s == null || p == null) { + return false; + } + + int lens = s.length(); + int lenp = p.length(); + + boolean[][] D = new boolean[lens + 1][lenp + 1]; + + boolean flag = false; + + for (int i = 0; i <= lens; i++) { + flag = false; + for (int j = 0; j <= lenp; j++) { + // both is empty. + if (i == 0 && j == 0) { + D[i][j] = true; + flag = true; + continue; + } + + // if P is empty, s is not empty, it is false. + if (j == 0) { + D[i][j] = false; + continue; + } + + // if S is empty, P is not empty + if (i == 0) { + D[i][j] = D[i][j - 1] && p.charAt(j - 1) == '*'; + } else { + D[i][j] = (matchChar(s.charAt(i - 1), p.charAt(j - 1)) && D[i - 1][j - 1]) + || (p.charAt(j - 1) == '*' && (D[i][j - 1] || D[i - 1][j])); + } + + if (D[i][j]) { + flag = true; + } + + if (D[i][j] && p.charAt(j - 1) == '*' && j == lenp) { + return true; + } + } + + if (!flag) { + return false; + } + } + + return D[lens][lenp]; + } + + public static boolean matchChar(char c, char p) { + return (p == '?' || p == c); + } + + public static boolean isMatch(String s, String p) { + if (s == null || p == null) { + return false; + } + + int indexS = 0; + int indexP = 0; + + int lenS = s.length(); + int lenP = p.length(); + + int preS = 0; + int preP = 0; + + boolean back = false; + + while (indexS < lenS) { + if (indexP < lenP && matchChar(s.charAt(indexS), p.charAt(indexP))) { + indexS++; + indexP++; + } else if (indexP < lenP && p.charAt(indexP) == '*') { + while (indexP < lenP && p.charAt(indexP) == '*') { + indexP++; + } + + if (indexP == lenP) { + return true; + } + + back = true; + preS = indexS; + preP = indexP; + } else { + if (back) { + indexS = ++preS; + indexP = preP; + } else { + return false; + } + } + } + + while (indexP < lenP && p.charAt(indexP) == '*') { + indexP++; + } + + if (indexS == lenS && indexP == lenP) { + return true; + } + + return false; + } +} diff --git a/dp/IsScramble.java b/dp/IsScramble.java new file mode 100644 index 0000000..115c774 --- /dev/null +++ b/dp/IsScramble.java @@ -0,0 +1,251 @@ +package Algorithms.dp; + +import java.util.Arrays; + +public class IsScramble { + public static void main(String[] strs) { + System.out.println(isScramble("a", "a")); + + } + + public static boolean isScramble1(String s1, String s2) { + if (s1 == null || s2 == null) { + return false; + } + + int len1 = s1.length(); + int len2 = s2.length(); + + // the two strings should be the same length. + if (len1 != len2) { + return false; + } + + return rec(s1, s2); + } + + // Solution 1: The recursion version. + public static boolean rec1(String s1, String s2) { + int len = s1.length(); + + // the base case. + if (len == 1) { + return s1.equals(s2); + } + + // 鍒掑垎2涓瓧绗︿覆 + for (int i = 1; i < len; i++) { + // we have two situation; + // the left-left right-right & left-right right-left + if (rec1(s1.substring(0, i), s2.substring(0, i)) + && rec1(s1.substring(i, len), s2.substring(i, len))) { + return true; + } + + if (rec1(s1.substring(0, i), s2.substring(len - i, len)) + && rec1(s1.substring(i, len), s2.substring(0, len - i))) { + return true; + } + } + + return false; + } + + // Solution 2: The recursion version with sorting. + // 鎺掑簭涔嬪悗鐨勫壀鏋濆彲浠ラ�杩嘗eetCode鐨勬鏌� + public static boolean rec(String s1, String s2) { + int len = s1.length(); + + // the base case. + if (len == 1) { + return s1.equals(s2); + } + + // sort to speed up. + char[] s1ch = s1.toCharArray(); + Arrays.sort(s1ch); + String s1Sort = new String(s1ch); + + char[] s2ch = s2.toCharArray(); + Arrays.sort(s2ch); + String s2Sort = new String(s2ch); + + if (!s1Sort.equals(s2Sort)) { + return false; + } + + // 鍒掑垎2涓瓧绗︿覆 + for (int i = 1; i < len; i++) { + // we have two situation; + // the left-left right-right & left-right right-left + if (rec(s1.substring(0, i), s2.substring(0, i)) + && rec(s1.substring(i, len), s2.substring(i, len))) { + return true; + } + + if (rec(s1.substring(0, i), s2.substring(len - i, len)) + && rec(s1.substring(i, len), s2.substring(0, len - i))) { + return true; + } + } + + return false; + } + + // Solution 3: The recursion version with memory. + // 閫氳繃璁板繂鐭╅樀鏉ュ噺灏戣绠楅噺 + public static boolean isScramble3(String s1, String s2) { + if (s1 == null || s2 == null) { + return false; + } + + int len1 = s1.length(); + int len2 = s2.length(); + + // the two strings should be the same length. + if (len1 != len2) { + return false; + } + + int[][][] mem = new int[len1][len1][len1]; + for (int i = 0; i < len1; i++) { + for (int j = 0; j < len1; j++) { + for (int k = 0; k < len1; k++) { + // -1 means unseted. + mem[i][j][k] = -1; + } + } + } + + return recMem(s1, 0, s2, 0, len1, mem); + } + + // Solution 3: The recursion version with memory. + // 閫氳繃璁板繂鐭╅樀鏉ュ噺灏戣绠楅噺 + public static boolean recMem(String s1, int index1, String s2, int index2, + int len, int[][][] mem) { + // the base case. + if (len == 1) { + return s1.charAt(index1) == s2.charAt(index2); + } + + // LEN: 1 - totalLen-1 + int ret = mem[index1][index2][len - 1]; + if (ret != -1) { + return ret == 1 ? true : false; + } + + // 鍒濆鍖栦负false + ret = 0; + + // 鍒掑垎2涓瓧绗︿覆. i means the length of the left side in S1 + for (int i = 1; i < len; i++) { + // we have two situation; + // the left-left right-right & left-right right-left + if (recMem(s1, index1, s2, index2, i, mem) + && recMem(s1, index1 + i, s2, index2 + i, len - i, mem)) { + ret = 1; + break; + } + + if (recMem(s1, index1, s2, index2 + len - i, i, mem) + && recMem(s1, index1 + i, s2, index2, len - i, mem)) { + ret = 1; + break; + } + } + + mem[index1][index2][len - 1] = ret; + return ret == 1 ? true : false; + } + + /* + * Solution 4: The DP Version. + */ + public static boolean isScramble4(String s1, String s2) { + if (s1 == null || s2 == null) { + return false; + } + + int len1 = s1.length(); + int len2 = s2.length(); + + // the two strings should be the same length. + if (len1 != len2) { + return false; + } + + /* + * i: The index of string 1. j: The index of string 2. k: The length of + * the two string. 1 ~ len1 + * + * D[i][j][k] = + */ + boolean[][][] D = new boolean[len1][len1][len1 + 1]; + for (int subLen = 1; subLen <= len1; subLen++) { + for (int i1 = 0; i1 <= len1 - subLen; i1++) { + for (int i2 = 0; i2 <= len1 - subLen; i2++) { + if (subLen == 1) { + D[i1][i2][subLen] = s1.charAt(i1) == s2.charAt(i2); + continue; + } + + D[i1][i2][subLen] = false; + for (int l = 1; l < subLen; l++) { + if (D[i1][i2][l] && D[i1 + l][i2 + l][subLen - l] + || D[i1][i2 + subLen - l][l] && D[i1 + l][i2][subLen - l] + ) { + D[i1][i2][subLen] = true; + break; + } + } + } + } + } + + return D[0][0][len1]; + } + + /* + * Solution 4: The DP Version. REDO + */ + public static boolean isScramble(String s1, String s2) { + if (s1 == null || s2 == null) { + return false; + } + + int len = s1.length(); + + if (s2.length() != len) { + return false; + } + + boolean[][][] D = new boolean[len][len][len + 1]; + + // D[i][j][k] = D[i][] + for (int k = 1; k <= len; k++) { + // 注意这里的边界选取。 如果选的不对,就会发生越界的情况.. orz.. + // attention: should use "<=" + for (int i = 0; i <= len - k; i++) { + for (int j = 0; j <= len - k; j++) { + if (k == 1) { + D[i][j][k] = s1.charAt(i) == s2.charAt(j); + continue; + } + + D[i][j][k] = false; + for (int l = 1; l <= k - 1; l++) { + if (D[i][j][l] && D[i + l][j + l][k - l] + || D[i][j + k - l][l] && D[i + l][j][k - l] ) { + D[i][j][k] = true; + break; + } + } + } + } + } + + return D[0][0][len]; + } + +} diff --git a/dp/LongestPalindrome.java b/dp/LongestPalindrome.java new file mode 100644 index 0000000..321d83f --- /dev/null +++ b/dp/LongestPalindrome.java @@ -0,0 +1,49 @@ +package Algorithms.dp; + +public class LongestPalindrome { + public static void main(String[] args) { + String s = "9cadfasdfsadfabaabaed"; + System.out.println(longestPalindrome(s)); + + System.out.println(Character.toLowerCase('9')); + + } + + // Solution 1: Brute Force + public static String longestPalindrome(String s) { + if (s == null) { + return null; + } + + int len = s.length(); + + int max = 0; + int begin = 0; + int end = 0; + for (int i = 0; i < len; i++) { + for (int j = i; j < len; j++) { + if (dfs(s, i, j)) { + if (j - i + 1 > max) { + max = j - i + 1; + begin = i; + end = j; + } + } + } + } + + return s.substring(begin, end + 1); + } + + public static boolean dfs(String s, int i, int j) { + if (i >= j) { + return true; + } + + if (s.charAt(i) == s.charAt(j)) { + return dfs(s, i + 1, j - 1); + } + + return false; + } +} diff --git a/dp/LongestPalindrome_dp1.java b/dp/LongestPalindrome_dp1.java new file mode 100644 index 0000000..745fb1c --- /dev/null +++ b/dp/LongestPalindrome_dp1.java @@ -0,0 +1,164 @@ +package Algorithms.dp; + +public class LongestPalindrome_dp1 { + public static void main(String[] args) { + String s = "cabaabad"; + System.out.println(longestPalindrome(s)); + } + + // solution 1: DP. + public static String longestPalindrome1(String s) { + if (s == null) { + return null; + } + + int len = s.length(); + + // Record i-j is a palindrome. + boolean[][] D = new boolean[len][len]; + + int max = 0; + int retB = 0; + int retE = 0; + for (int j = 0; j < len; j++) { + for (int i = 0; i <= j; i++) { + if (s.charAt(i) == s.charAt(j) + && (j - i <= 2 || D[i + 1][j - 1]) + ) { + D[i][j] = true; + + if (j - i + 1 > max) { + retB = i; + retE = j; + max = j - i + 1; + } + } else { + D[i][j] = false; + } + } + } + + return s.substring(retB, retE + 1); + } + + // SOLUTION 1: Re do 2014.12.26 + public String longestPalindrome4(String s) { + if (s == null) { + return null; + } + + String ret = null; + + int len = s.length(); + int max = 0; + + boolean[][] D = new boolean[len][len]; + + for (int j = 0; j < len; j++) { + for (int i = 0; i <= j; i++) { + D[i][j] = s.charAt(i) == s.charAt(j) && (j - i <= 2 || D[i + 1][j - 1]); + if (D[i][j]) { + if (j - i + 1 > max) { + max = j - i + 1; + ret = s.substring(i, j + 1); + } + } + } + } + + return ret; + } + + // solution 2: 中心展开法 空间复杂度O(1) + public static String longestPalindrome(String s) { + if (s == null) { + return null; + } + + int len = s.length(); + + if (len <= 0) { + return ""; + } + + int max = 0; + String ret = ""; + + for (int i = 0; i < len; i++) { + // 鑰冭檻濂囨暟瀛楃涓� + String s1 = expandAround(s, i, i); + if (s1.length() > max) { + ret = s1; + max = s1.length(); + } + + // 鑰冭檻鍋舵暟闀垮害鐨勫瓧绗︿覆 + String s2 = expandAround(s, i, i + 1); + if (s2.length() > max) { + ret = s2; + max = s2.length(); + } + } + + return ret; + } + + public static String expandAround(String s, int c1, int c2) { + int len = s.length(); + + while (c1 >= 0 && c2 <= len - 1) { + if (s.charAt(c1) != s.charAt(c2)) { + break; + } + + c1--; + c2++; + } + + // 娉ㄦ剰锛屾牴鎹�substring鐨勫畾涔夛紝c2涓嶈鍑� + return s.substring(c1 + 1, c2); + } + + // SOLUTION 2: Redo 2014.12.26 + public String longestPalindrome3(String s) { + if (s == null) { + return null; + } + + String ret = null; + + int len = s.length(); + int max = 0; + for (int i = 0; i < len; i++) { + String s1 = getLongest(s, i, i); + String s2 = getLongest(s, i, i + 1); + + if (s1.length() > max) { + max = Math.max(max, s1.length()); + ret = s1; + } + + if (s2.length() > max) { + max = Math.max(max, s2.length()); + ret = s2; + } + } + + return ret; + } + + public String getLongest(String s, int left, int right) { + int len = s.length(); + while (left >= 0 && right < len) { + // when i is in the center. + if (s.charAt(left) != s.charAt(right)) { + break; + } + + left--; + right++; + } + + return s.substring(left + 1, right); + } +} diff --git a/dp/MaxProfit.java b/dp/MaxProfit.java new file mode 100644 index 0000000..6d01bbb --- /dev/null +++ b/dp/MaxProfit.java @@ -0,0 +1,35 @@ +package Algorithms.dp; + +public class MaxProfit { + public int maxProfit(int[] prices) { + if (prices == null) { + return 0; + } + + int len = prices.length; + int maxProfit = 0; + int minPrice = Integer.MAX_VALUE; + for (int i = 0; i < len; i++) { + minPrice = Math.min(minPrice, prices[i]); + maxProfit = Math.max(maxProfit, prices[i] - minPrice); + } + + return maxProfit; + } + + public int maxProfit2(int[] prices) { + if (prices == null) { + return 0; + } + + int maxProfit = 0; + int minValue = Integer.MAX_VALUE; + + for (int i: prices) { + minValue = Math.min(minValue, i); + maxProfit = Math.max(maxProfit, i - minValue); + } + + return maxProfit; + } +} \ No newline at end of file diff --git a/dp/MaxProfit2.java b/dp/MaxProfit2.java new file mode 100644 index 0000000..6e5ca69 --- /dev/null +++ b/dp/MaxProfit2.java @@ -0,0 +1,40 @@ +package Algorithms.dp; + +public class MaxProfit2 { + public int maxProfit(int[] prices) { + if (prices == null) { + return 0; + } + + int profit = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i] - prices[i - 1] > 0) { + profit += prices[i] - prices[i - 1]; + } + } + + return profit; + } + + /* + * 2015.1.3 + * */ + public int maxProfit2(int[] prices) { + if (prices == null) { + return 0; + } + + int maxProfit = 0; + + int len = prices.length; + for (int i = 1; i < len; i++) { + int dif = prices[i] - prices[i - 1]; + + if (dif > 0) { + maxProfit += dif; + } + } + + return maxProfit; + } +} \ No newline at end of file diff --git a/dp/MaxProfit3.java b/dp/MaxProfit3.java new file mode 100644 index 0000000..0bf412a --- /dev/null +++ b/dp/MaxProfit3.java @@ -0,0 +1,97 @@ +package Algorithms.dp; + +public class MaxProfit3 { + public int maxProfit(int[] prices) { + if (prices == null || prices.length == 0) { + return 0; + } + + int len = prices.length; + int[] left = new int[len]; + int[] right = new int[len]; + + int min = prices[0]; + left[0] = 0; + for (int i = 1; i < len; i++) { + min = Math.min(min, prices[i]); + left[i] = Math.max(left[i - 1], prices[i] - min); + } + + int max = prices[len - 1]; + right[len - 1] = 0; + for (int i = len - 2; i >= 0; i--) { + max = Math.max(max, prices[i]); + right[i] = Math.max(right[i + 1], max - prices[i]); + } + + int rst = 0; + for (int i = 0; i < len; i++) { + rst = Math.max(rst, left[i] + right[i]); + } + + return rst; + } + + // 2015.1.3: redo + public int maxProfit2(int[] prices) { + if (prices == null) { + return 0; + } + + int ret = 0; + + int len = prices.length; + int[] leftProfile = new int[len]; + int profile = 0; + + int min = Integer.MAX_VALUE; + for (int i = 0; i < len; i++) { + min = Math.min(min, prices[i]); + profile = Math.max(profile, prices[i] - min); + leftProfile[i] = profile; + } + + int max = Integer.MIN_VALUE; + profile = 0; + for (int i = len - 1; i >= 0; i--) { + max = Math.max(max, prices[i]); + profile = Math.max(profile, max - prices[i]); + + // sum the left profit and the right profit. + ret = Math.max(ret, profile + leftProfile[i]); + } + + return ret; + } + + // DP solution: + public int maxProfit3(int[] prices) { + if (prices == null || prices.length == 0) { + return 0; + } + + int ret = 0; + + int len = prices.length; + int[] leftProfile = new int[len]; + + int min = prices[0]; + leftProfile[0] = 0; + for (int i = 1; i < len; i++) { + min = Math.min(min, prices[i]); + leftProfile[i] = Math.max(leftProfile[i - 1], prices[i] - min); + } + + int max = Integer.MIN_VALUE; + int profile = 0; + for (int i = len - 1; i >= 0; i--) { + max = Math.max(max, prices[i]); + profile = Math.max(profile, max - prices[i]); + + // sum the left profit and the right profit. + ret = Math.max(ret, profile + leftProfile[i]); + } + + return ret; + } +} \ No newline at end of file diff --git a/dp/MinCut.java b/dp/MinCut.java new file mode 100644 index 0000000..c8b4ffb --- /dev/null +++ b/dp/MinCut.java @@ -0,0 +1,39 @@ +package Algorithms.dp; + +public class MinCut { + public int minCut(String s) { + if (s == null || s.length() == 0) { + return 0; + } + + int len = s.length(); + + // D[i] 的定义: 第i个字符到len - 1个字符的最小切割数。 + 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[Len],所以这里直接 + // 将D[i]置为0,意思就是这时不需要任何的划分。 + D[i] = 0; + } else { + // 如果前半部分是回文,那么我们可以分解为第一个回文 + 后半部分的最小分割数 + D[i] = Math.min(D[i], D[j + 1] + 1); + } + } + } + } + + return D[0]; + } +} diff --git a/dp/MinCut_1206.java b/dp/MinCut_1206.java new file mode 100644 index 0000000..a30e33c --- /dev/null +++ b/dp/MinCut_1206.java @@ -0,0 +1,5 @@ +package Algorithms.dp; + +public class MinCut_1206 { + +} diff --git a/dp/MinDistance.java b/dp/MinDistance.java new file mode 100644 index 0000000..51ba723 --- /dev/null +++ b/dp/MinDistance.java @@ -0,0 +1,169 @@ +package Algorithms.dp; + +public class MinDistance { + public static void main(String[] strs) { + String str1 = "abcdafasdfsaf", str2 = "acadsadsfsfqweiruiijadsfsadfsadfdwqfjljfaffiuweqro"; + + System.out.println(minDistance(str1, str2)); + + int[][] record = new int[str1.length() + 1][str2.length() + 1]; + for (int i = 0; i < str1.length() + 1; i++) { + for (int j = 0; j < str2.length() + 1; j++) { + record[i][j] = -1; + } + } + + System.out.println(dfs(str1, str1.length(), str2, str2.length(), record)); + +// String str3 = "abc"; +// String str4 = "abcd"; + String str3 = "febc"; + String str4 = "afebc"; + System.out.println(disLessThenTwo(str3, str4)); + } + + public static int dfs(String word1, int len1, String word2, int len2, int[][] record) { + if (len1 <= 0) { + return len2; + } + + if (len2 <= 0) { + return len1; + } + + if (record[len1][len2] != -1) { + return record[len1][len2]; + } + + int ret = 0; + + int index1 = word1.length() - len1; + int index2 = word2.length() - len2; + if (word1.charAt(index1) == word2.charAt(index2)) { + ret = dfs(word1, len1 - 1, word2, len2 - 1, record); + } else { + int del = dfs(word1, len1 - 1, word2, len2, record) + 1; + int add = dfs(word1, len1, word2, len2 - 1, record) + 1; + int replace = dfs(word1, len1 - 1, word2, len2 - 1, record) + 1; + + ret = Math.min(del, add); + ret = Math.min(ret, replace); + } + + record[len1][len2] = ret; + return ret; + } + + public static boolean disLessThenTwo(String word1, String word2) { + if (word1 == null || word2 == null) { + return false; + } + + int len1 = word1.length(); + int len2 = word2.length(); + + int dis = 1; + + for (int p1 = 0, p2 = 0; p1 < len1 && p2 < len2; p1++, p2++) { + if (word1.charAt(p1) != word2.charAt(p2)) { + dis--; + if (dis < 0) { + return false; + } else { + // If str1 < str2, just move forward the point of STR2 + if (len1 < len2) { + p1--; + // If str1 > str2, just move forward the point of STR1 + } else if (len1 > len2) { + p2--; + } + } + } + } + + return dis >= 0; + } + + public static int minDistance(String word1, String word2) { + // THE DP FORMULA + // D[i][j]: The min operations to change from s1 to s2. + // s1: 0-i in word1, s2: 0-j in word2. + // D[i][j] = + + if (word1 == null || word2 == null) { + return -1; + } + + int len1 = word1.length(); + int len2 = word2.length(); + + // create a DP array. + // 注意:一定要多分配1个。 + // 取0表示从string中一个都不取 + int[][] D = new int[len1 + 1][len2 + 1]; + + for (int i = 0; i <= len1; i++) { + for (int j = 0; j <= len2; j++) { + if (i == 0 && j == 0) { + D[i][j] = 0; + } else if (i == 0) { + // Need to add a new element to do it. + D[i][j] = D[i][j - 1] + 1; + } else if (j == 0) { + // Need to delete a element to get the string 2. + D[i][j] = D[i - 1][j] + 1; + } else { + // we can come from 3 options: + // 1. D[i][j - 1] + // 2. D[i - 1][j] + // 3. D[i - 1][j - 1] + D[i][j] = Math.min(D[i][j - 1] + 1, D[i - 1][j] + 1); + + if (word1.charAt(i - 1) == word2.charAt(j - 1)) { + // 最后一个字符相等,不需要变化 + D[i][j] = Math.min(D[i][j], D[i - 1][j - 1]); + } else { + // 最后一个字符不等,需要replace. + D[i][j] = Math.min(D[i][j], D[i - 1][j - 1] + 1); + } + } + } + } + + return D[len1][len2]; + } + + /* + * DP: 2014.12.28 Redo. + * */ + public int minDistance2(String word1, String word2) { + if (word1 == null || word2 == null) { + return 0; + } + + int len1 = word1.length(); + int len2 = word2.length(); + + int[][] D = new int[len1 + 1][len2 + 1]; + + for (int i = 0; i <= len1; i++) { + for (int j = 0; j <= len2; j++) { + if (i == 0) { + D[i][j] = j; + } else if (j == 0) { + D[i][j] = i; + } else { + if (word1.charAt(i - 1) == word2.charAt(j - 1)) { + D[i][j] = D[i - 1][j - 1]; + } else { + D[i][j] = Math.min(D[i - 1][j - 1], D[i][j - 1]); + D[i][j] = Math.min(D[i][j], D[i - 1][j]); + D[i][j]++; + } + } + } + } + + return D[len1][len2]; + } +} diff --git a/dp/MinPathSum.java b/dp/MinPathSum.java new file mode 100644 index 0000000..185342c --- /dev/null +++ b/dp/MinPathSum.java @@ -0,0 +1,79 @@ +package Algorithms.dp; + +public class MinPathSum { + public int minPathSum2(int[][] grid) { + if (grid == null || grid.length == 0 || grid[0].length == 0) { + return 0; + } + + // This is a simple DP. + // 表达式: D[i][j]: 从左下到本点的最小值 + // 递推公式: D[i][j] = Math.mn(D[i - 1][j], D[i][j - 1]) + grid[i][j] + // 初始化: D[i][j] = grid[i][j]. + + int rows = grid.length; + int cols = grid[0].length; + int[][] D = new int[rows][cols]; + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + D[i][j] = grid[i][j]; + if (i == 0 && j == 0) { + continue; + } else if (i == 0) { + D[i][j] += D[i][j - 1]; + } else if (j == 0) { + D[i][j] += D[i - 1][j]; + } else { + D[i][j] += Math.min(D[i][j - 1], D[i - 1][j]); + } + } + } + + return D[rows - 1][cols - 1]; + } + + public int minPathSum(int[][] grid) { + if (grid == null || grid.length == 0 || grid[0].length == 0) { + return 0; + } + + int rows = grid.length; + int cols = grid[0].length; + int[][] visit = new int[rows][cols]; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + visit[i][j] = -1; + } + } + + return dfs(grid, 0, 0, visit); + } + + public int dfs(int[][] grid, int i, int j, int[][] visit) { + int row = grid.length; + int col = grid[0].length; + + // 符合递归的终止条件,因为我已经到达了终点 + if (i == row - 1 && j == col - 1) { + return grid[i][j]; + } + + if (i >= row || j >= col || i < 0 || j < 0) { + // 表示不可达 + return Integer.MAX_VALUE; + } + + // 已经搜索过的点不需要重复搜索 + if (visit[i][j] != -1) { + return visit[i][j]; + } + + // 开始dfs 可能的路径,目前我们只有2种可能 + int right = dfs(grid, i, j + 1, visit); + int down = dfs(grid, i + 1, j, visit); + + visit[i][j] = Math.min(down, right) + grid[i][j]; + return visit[i][j]; + } +} \ No newline at end of file diff --git a/dp/MinPathSum_1222_2014.java b/dp/MinPathSum_1222_2014.java new file mode 100644 index 0000000..8b61c5e --- /dev/null +++ b/dp/MinPathSum_1222_2014.java @@ -0,0 +1,81 @@ +package Algorithms.dp; + +public class MinPathSum_1222_2014 { + // Solution 1: DP + public int minPathSum1(int[][] grid) { + if (grid == null || grid.length == 0 || grid[0].length == 0) { + return 0; + } + + int rows = grid.length; + int cols = grid[0].length; + int[][] D = new int[rows][cols]; + + // This is a simple DP. + // 表达式: D[i][j]: 从左下到本点的最小值 + // 递推公式: D[i][j] = Math.mn(D[i - 1][j], D[i][j - 1]) + grid[i][j] + // 初始化: D[i][j] = grid[i][j]. + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + D[i][j] = grid[i][j]; + + if (i == 0 && j != 0) { + D[i][j] += D[i][j - 1]; + } else if (j == 0 && i != 0) { + D[i][j] += D[i - 1][j]; + } else if (i != 0 && j != 0) { + D[i][j] += Math.min(D[i][j - 1], D[i - 1][j]); + } + } + } + + return D[rows - 1][cols - 1]; + } + + // Solution 2: DFS + memory. + public int minPathSum(int[][] grid) { + if (grid == null || grid.length == 0 || grid[0].length == 0) { + return 0; + } + + int[][] memory = new int[grid.length][grid[0].length]; + + // Bug 1: forget to initilize + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + memory[i][j] = -1; + } + } + + return dfs(grid, 0, 0, memory); + } + + public int dfs (int[][] grid, int i, int j, int[][] memory) { + int rows = grid.length; + int cols = grid[0].length; + + if (i >= rows || j >= cols) { + // 表示不可达 + return Integer.MAX_VALUE; + } + + // The base case: arrive the destination. + if (i == rows - 1 && j == cols - 1) { + return grid[i][j]; + } + + // 已经搜索过的点不需要重复搜索 + if (memory[i][j] != -1) { + return memory[i][j]; + } + + int sum = grid[i][j]; + + // 开始dfs 可能的路径,目前我们只有2种可能 + sum += Math.min(dfs(grid, i + 1, j, memory), dfs(grid, i, j + 1, memory)); + + // Record the memory + memory[i][j] = sum; + return sum; + } +} \ No newline at end of file diff --git a/dp/MinimumTotal.java b/dp/MinimumTotal.java new file mode 100644 index 0000000..4399262 --- /dev/null +++ b/dp/MinimumTotal.java @@ -0,0 +1,65 @@ +package Algorithms.dp; + +import java.util.List; + +public class MinimumTotal { + /* + REC, SOL 1: + */ + public int minimumTotal1(List> triangle) { + if (triangle == null || triangle.size() == 0) { + return 0; + } + + int rows = triangle.size(); + int[][] mem = new int[rows][rows]; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < rows; j++) { + mem[i][j] = Integer.MAX_VALUE; + } + } + + return dfs(triangle, 0, 0, mem); + } + + public int dfs(List> triangle, int row, int col, int[][] mem) { + if (mem[row][col] != Integer.MAX_VALUE) { + return mem[row][col]; + } + + if (row == triangle.size() - 1) { + mem[row][col] = triangle.get(row).get(col); + } else { + int left = dfs(triangle, row + 1, col, mem); + int right = dfs(triangle, row + 1, col + 1, mem); + mem[row][col] = triangle.get(row).get(col) + Math.min(left, right); + } + + return mem[row][col]; + } + + /* + DP, SOL 2: + */ + public int minimumTotal(List> triangle) { + if (triangle == null || triangle.size() == 0) { + return 0; + } + + int rows = triangle.size(); + int[] D = new int[rows]; + + for (int i = rows - 1; i >= 0; i--) { + // 注意:边界条件是 j <= i + for (int j = 0; j <= i; j++) { + if (i == rows - 1) { + D[j] = triangle.get(i).get(j); + } else { + D[j] = triangle.get(i).get(j) + Math.min(D[j], D[j + 1]); + } + } + } + + return D[0]; + } +} \ No newline at end of file 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/dp/NumDecodings.java b/dp/NumDecodings.java new file mode 100644 index 0000000..91ed522 --- /dev/null +++ b/dp/NumDecodings.java @@ -0,0 +1,48 @@ +package Algorithms.dp; + +public class NumDecodings { + public int numDecodings(String s) { + if (s == null || s.length() == 0) { + return 0; + } + + int len = s.length(); + + // D[i] 表示含有i个字符的子串的DECODE WAYS. + int[] D = new int[len + 1]; + + D[0] = 1; + + for (int i = 1; i <= len; i++) { + D[i] = 0; + + // 现在正在考察的字符的索引. + int index = i - 1; + // 最后一个字符独立解码 + if (isValidSingle(s.charAt(index))) { + D[i] += D[i - 1]; + } + + // 最后一个字符与上一个字符一起解码 + if (i > 1 && isValidTwo(s.substring(index - 1, index + 1))) { + D[i] += D[i - 2]; + } + } + + return D[len]; + } + + public boolean isValidSingle(char c) { + if (c >= '1' && c <= '9') { + return true; + } + + return false; + } + + public boolean isValidTwo(String s) { + int num = Integer.parseInt(s); + + return (num >= 10 && num <= 26); + } +} diff --git a/dp/NumDistinct.java b/dp/NumDistinct.java new file mode 100644 index 0000000..523ea08 --- /dev/null +++ b/dp/NumDistinct.java @@ -0,0 +1,220 @@ +package Algorithms.dp; + +public class NumDistinct { + public int numDistinct1(String S, String T) { + if (S == null || T == null) { + return 0; + } + + int lenS = S.length(); + int lenT = T.length(); + + if (lenS < lenT) { + return 0; + } + + int[][] D = new int[lenS + 1][lenT + 1]; + + // BUG 1: forget to use <= instead of <.... + for (int i = 0; i <= lenS; i++) { + for (int j = 0; j <= lenT; j++) { + // both are empty. + if (i == 0 && j == 0) { + D[i][j] = 1; + } else if (i == 0) { + // S is empty, can't form a non-empty string. + D[i][j] = 0; + } else if (j == 0) { + // T is empty. S is not empty. + D[i][j] = 1; + } else { + D[i][j] = 0; + // keep the last character of S. + if (S.charAt(i - 1) == T.charAt(j - 1)) { + D[i][j] += D[i - 1][j - 1]; + } + + // discard the last character of S. + D[i][j] += D[i - 1][j]; + } + } + } + + return D[lenS][lenT]; + } + + // SOLUTION 2: recursion version. TLE + public int numDistinct2(String S, String T) { + if (S == null || T == null) { + return 0; + } + + return rec(S, T, 0, 0); + } + + public int rec(String S, String T, int indexS, int indexT) { + int lenS = S.length(); + int lenT = T.length(); + + // base case: + if (indexT >= lenT) { + // T is empty. + return 1; + } + + if (indexS >= lenS) { + // S is empty but T is not empty. + return 0; + } + + int sum = 0; + // use the first character in S. + if (S.charAt(indexS) == T.charAt(indexT)) { + sum += rec(S, T, indexS + 1, indexT + 1); + } + + // Don't use the first character in S. + sum += rec(S, T, indexS + 1, indexT); + + return sum; + } + + // SOLUTION 3: recursion version with memory. + public int numDistinct3(String S, String T) { + if (S == null || T == null) { + return 0; + } + + int lenS = S.length(); + int lenT = T.length(); + + int[][] memory = new int[lenS + 1][lenT + 1]; + for (int i = 0; i <= lenS; i++) { + for (int j = 0; j <= lenT; j++) { + memory[i][j] = -1; + } + } + + return rec(S, T, 0, 0, memory); + } + + public int rec(String S, String T, int indexS, int indexT, int[][] memory) { + int lenS = S.length(); + int lenT = T.length(); + + // base case: + if (indexT >= lenT) { + // T is empty. + return 1; + } + + if (indexS >= lenS) { + // S is empty but T is not empty. + return 0; + } + + if (memory[indexS][indexT] != -1) { + return memory[indexS][indexT]; + } + + int sum = 0; + // use the first character in S. + if (S.charAt(indexS) == T.charAt(indexT)) { + sum += rec(S, T, indexS + 1, indexT + 1, memory); + } + + // Don't use the first character in S. + sum += rec(S, T, indexS + 1, indexT, memory); + + // record the solution. + memory[indexS][indexT] = sum; + return sum; + } + + // SOLUTION 4: improved recursion version + public int numDistinct4(String S, String T) { + if (S == null || T == null) { + return 0; + } + + int lenS = S.length(); + int lenT = T.length(); + + int[][] memory = new int[lenS + 1][lenT + 1]; + for (int i = 0; i <= lenS; i++) { + for (int j = 0; j <= lenT; j++) { + memory[i][j] = -1; + } + } + + return rec4(S, T, 0, 0, memory); + } + + public int rec4(String S, String T, int indexS, int indexT, int[][] memory) { + int lenS = S.length(); + int lenT = T.length(); + + // base case: + if (indexT >= lenT) { + // T is empty. + return 1; + } + + if (indexS >= lenS) { + // S is empty but T is not empty. + return 0; + } + + if (memory[indexS][indexT] != -1) { + return memory[indexS][indexT]; + } + + int sum = 0; + for (int i = indexS; i < lenS; i++) { + // choose which character in S to choose as the first character of T. + if (S.charAt(i) == T.charAt(indexT)) { + sum += rec4(S, T, i + 1, indexT + 1, memory); + } + } + + // record the solution. + memory[indexS][indexT] = sum; + return sum; + } + + // SOLUTION 5: improved recursion version without memory. + public int numDistinct(String S, String T) { + if (S == null || T == null) { + return 0; + } + + return rec5(S, T, 0, 0); + } + + public int rec5(String S, String T, int indexS, int indexT) { + int lenS = S.length(); + int lenT = T.length(); + + // base case: + if (indexT >= lenT) { + // T is empty. + return 1; + } + + if (indexS >= lenS) { + // S is empty but T is not empty. + return 0; + } + + int sum = 0; + for (int i = indexS; i < lenS; i++) { + // choose which character in S to choose as the first character of T. + if (S.charAt(i) == T.charAt(indexT)) { + sum += rec5(S, T, i + 1, indexT + 1); + } + } + + return sum; + } + +} \ No newline at end of file diff --git a/dp/UniquePaths.java b/dp/UniquePaths.java new file mode 100644 index 0000000..3d596be --- /dev/null +++ b/dp/UniquePaths.java @@ -0,0 +1,67 @@ +package Algorithms.dp; + +public class UniquePaths { + public int uniquePaths(int m, int n) { + if (m == 0 || n == 0) { + return 0; + } + + // 经典DP题 + // 1. 状态表达式: D[i][j]: 代表从起点到这一点的所有的路径数目 + // 2. 递推公式: D[i][j] = D[i - 1][j] + D[i][j - 1] + // 3. 初始化: D[0][0] = 1 原点只有一种方法到达 + + int[][] D = new int[m][n]; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (i == 0 && j == 0) { + D[i][j] = 1; + } else if (i == 0) { + D[i][j] = D[i][j - 1]; + } else if (j == 0) { + D[i][j] = D[i - 1][j]; + } else { + D[i][j] = D[i - 1][j] + D[i][j - 1]; + } + } + } + + return D[m - 1][n - 1]; + } + + public int uniquePaths2(int m, int n) { + if (m == 0 || n == 0) { + return 0; + } + + // 经典DP题 + // 1. 状态表达式: D[i][j]: 代表从起点到这一点的所有的路径数目 + // 2. 递推公式: D[i][j] = D[i - 1][j] + D[i][j - 1] + // 3. 初始化: D[0][0] = 1 原点只有一种方法到达 + + int[][] D = new int[m][n]; + + // initiate. + D[0][0] = 1; + + // initiate the first line + for (int j = 1; j < n; j++) { + D[0][j] = D[0][j - 1]; + } + + // initiate the first column + for (int i = 1; i < m; i++) { + D[i][0] = D[i - 1][0]; + } + + // get the result. + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + D[i][j] = D[i - 1][j] + D[i][j - 1]; + } + } + + return D[m - 1][n - 1]; + } +} \ No newline at end of file diff --git a/dp/UniquePathsWithObstacles.java b/dp/UniquePathsWithObstacles.java new file mode 100644 index 0000000..3e14967 --- /dev/null +++ b/dp/UniquePathsWithObstacles.java @@ -0,0 +1,36 @@ +package Algorithms.dp; + +public class UniquePathsWithObstacles { + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + if (obstacleGrid == null || obstacleGrid.length == 0 + || obstacleGrid[0].length == 0) { + return 0; + } + + int rows = obstacleGrid.length; + int cols = obstacleGrid[0].length; + + int[][] D = new int[rows][cols]; + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (obstacleGrid[i][j] == 1) { + D[i][j] = 0; + continue; + } + + if (i == 0 && j == 0) { + D[i][j] = 1; + } else if (i == 0) { + D[i][j] = D[i][j - 1]; + } else if (j == 0) { + D[i][j] = D[i - 1][j]; + } else { + D[i][j] = D[i - 1][j] + D[i][j - 1]; + } + } + } + + return D[rows - 1][cols - 1]; + } +} \ No newline at end of file diff --git a/dp/WordBreak.java b/dp/WordBreak.java new file mode 100644 index 0000000..33338bf --- /dev/null +++ b/dp/WordBreak.java @@ -0,0 +1,40 @@ +package Algorithms.dp; + +import java.util.Set; + +public class WordBreak { + public boolean wordBreak(String s, Set dict) { + if (s == null) { + return false; + } + + int len = s.length(); + if (len == 0) { + return true; + } + + boolean[] D = new boolean[len + 1]; + + // initiate the DP. 注意,这里设置为true是不得已,因为当我们划分字串为左边为0,右边为n的时候, + // 而右边的n是一个字典string,那么左边必然要设置为true,才能使结果为true。所以空字符串我们需要 + // 认为true + D[0] = true; + + // D[i] 表示i长度的字符串能否被word break. + for (int i = 1; i <= len; i++) { + // 把子串划分为2部分,分别讨论, j 表示左边的字符串的长度 + // 成立的条件是:左边可以break, 而右边是一个字典单词 + D[i] = false; + for (int j = 0; j < i; j++) { + if (D[j] && dict.contains(s.substring(j, i))) { + // 只要找到任意一个符合条件,我们就可以BREAK; 表示我们检查的 + // 这一个子串符合题意 + D[i] = true; + break; + } + } + } + + return D[len]; + } +} \ No newline at end of file diff --git a/dp/WordBreak2.java b/dp/WordBreak2.java new file mode 100644 index 0000000..0bfa79a --- /dev/null +++ b/dp/WordBreak2.java @@ -0,0 +1,360 @@ +package Algorithms.dp; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class WordBreak2 { + public static void main(String[] strs) { + String s = "aaaaaaaaaaaaaaaaaaaaaaa"; + Set dict = new HashSet(); + dict.add("bin"); + dict.add("apple"); + dict.add("app"); + dict.add("le"); + dict.add("aaaaaa"); + dict.add("aaaaa"); + dict.add("aaaa"); + dict.add("aaa"); + dict.add("aa"); + dict.add("a"); + dict.add("aaaaaaa"); + dict.add("aaaaaaaa"); + dict.add("aaaaaaaaa"); + + System.out.println("Test"); + + Algorithms.permutation.Stopwatch timer2 = new Algorithms.permutation.Stopwatch(); + + // HASH保存记忆 + wordBreak1(s, dict); + + System.out + .println("Computing time with DFS1: " + + timer2.elapsedTime() + " millisec."); + + Algorithms.permutation.Stopwatch timer1 = new Algorithms.permutation.Stopwatch(); + + // 递归模板,加剪枝 + wordBreak2(s, dict); + + System.out + .println("Computing time with DFS2: " + + timer1.elapsedTime() + " millisec."); + + Algorithms.permutation.Stopwatch timer3 = new Algorithms.permutation.Stopwatch(); + + // DFS+ 剪枝 3: 设置Flag 变量 + //http://fisherlei.blogspot.com/2013/11/leetcode-wordbreak-ii-solution.html + wordBreak3(s, dict); + + System.out + .println("Computing time with DFS3: " + + timer3.elapsedTime() + " millisec."); + + Algorithms.permutation.Stopwatch timer4 = new Algorithms.permutation.Stopwatch(); + + // DP + DFS + wordBreak4(s, dict); + + System.out + .println("Computing time with DFS4: " + + timer4.elapsedTime() + " millisec."); + + //System.out.println(list.toString()); + } + + // 我们用DFS来解决这个问题吧 + public static List wordBreak1(String s, Set dict) { + HashMap> map = new HashMap>(); + if (s == null || s.length() == 0 || dict == null) { + return null; + } + + return dfs(s, dict, map); + } + + // 解法1:我们用DFS来解决这个问题吧 + public static List dfs(String s, Set dict, HashMap> map) { + if (map.containsKey(s)) { + return map.get(s); + } + + List list = new ArrayList(); + int len = s.length(); + + if (len == 0) { + list.add(""); + } else { + // i 表示左边字符串的长度 + for (int i = 1; i <= len; i++) { + String sub = s.substring(0, i); + + // 左边的子串可以为空,或是在字典内 + if (!dict.contains(sub)) { + continue; + } + + // 字符串划分为2边,计算右边的word break. + List listRight = dfs(s.substring(i, len), dict, map); + + + // 把左字符串加到右字符串中,形成新的解. + for (String r: listRight) { + StringBuilder sb = new StringBuilder(); + sb.append(sub); + if (i != 0 && i != len) { + // 如果左边为空,或是右边为空,不需要贴空格 + sb.append(" "); + } + sb.append(r); + list.add(sb.toString()); + } + } + } + + map.put(s, list); + return list; + } + + /* + // 解法2:我们用普通的递归模板来试一下。 + */ + + // 我们用DFS来解决这个问题吧 + public static List wordBreak2(String s, Set dict) { + if (s == null || s.length() == 0 || dict == null) { + return null; + } + + List ret = new ArrayList(); + + // 记录切割过程中生成的字母 + List path = new ArrayList(); + + dfs2(s, dict, path, ret, 0); + + return ret; + } + + // 我们用DFS模板来解决这个问题吧 + public static void dfs2(String s, Set dict, + List path, List ret, int index) { + int len = s.length(); + if (index == len) { + // 结束了。index到了末尾 + StringBuilder sb = new StringBuilder(); + for (String str: path) { + sb.append(str); + sb.append(" "); + } + // remove the last " " + sb.deleteCharAt(sb.length() - 1); + ret.add(sb.toString()); + return; + } + + // 如果不加上这一行会超时。就是说不能break的时候,可以直接返回 + // 但这也许只是一个treak, 其实这种方法还是不大好。 + if (!iswordBreak(s.substring(index), dict)) { + return; + } + + for (int i = index; i < len; i++) { + // 注意这些索引的取值。左字符串的长度从0到len + String left = s.substring(index, i + 1); + if (!dict.contains(left)) { + // 如果左字符串不在字典中,不需要继续递归 + continue; + } + + path.add(left); + dfs2(s, dict, path, ret, i + 1); + path.remove(path.size() - 1); + } + } + + public static boolean iswordBreak(String s, Set dict) { + if (s == null) { + return false; + } + + int len = s.length(); + if (len == 0) { + return true; + } + + boolean[] D = new boolean[len + 1]; + + // initiate the DP. 注意,这里设置为true是不得已,因为当我们划分字串为左边为0,右边为n的时候, + // 而右边的n是一个字典string,那么左边必然要设置为true,才能使结果为true。所以空字符串我们需要 + // 认为true + D[0] = true; + + // D[i] 表示i长度的字符串能否被word break. + for (int i = 1; i <= len; i++) { + // 把子串划分为2部分,分别讨论, j 表示左边的字符串的长度 + // 成立的条件是:左边可以break, 而右边是一个字典单词 + D[i] = false; + for (int j = 0; j < i; j++) { + if (D[j] && dict.contains(s.substring(j, i))) { + // 只要找到任意一个符合条件,我们就可以BREAK; 表示我们检查的 + // 这一个子串符合题意 + D[i] = true; + break; + } + } + } + + return D[len]; + } + + /* + // 解法3:重新剪枝。 + */ + // 我们用DFS来解决这个问题吧 + public static List wordBreak3(String s, Set dict) { + if (s == null || s.length() == 0 || dict == null) { + return null; + } + + List ret = new ArrayList(); + + // 记录切割过程中生成的字母 + List path = new ArrayList(); + + int len = s.length(); + + // 注意:一定要分配 Len+1 否则会爆哦. + boolean canBreak[] = new boolean[len + 1]; + for (int i = 0; i < len + 1; i++) { + canBreak[i] = true; + } + + dfs3(s, dict, path, ret, 0, canBreak); + + return ret; + } + + // 我们用DFS模板来解决这个问题吧 + public static void dfs3(String s, Set dict, + List path, List ret, int index, + boolean canBreak[]) { + int len = s.length(); + if (index == len) { + // 结束了。index到了末尾 + StringBuilder sb = new StringBuilder(); + for (String str: path) { + sb.append(str); + sb.append(" "); + } + // remove the last " " + sb.deleteCharAt(sb.length() - 1); + ret.add(sb.toString()); + return; + } + + // if can't break, we exit directly. + if (!canBreak[index]) { + return; + } + + // cut branch. + int beforeChange = ret.size(); + for (int i = index; i < len; i++) { + // 注意这些索引的取值。左字符串的长度从0到len + String left = s.substring(index, i + 1); + if (!dict.contains(left)) { + // 如果左字符串不在字典中,不需要继续递归 + continue; + } + + // if can't find any solution, return false, other set it + // to be true; + path.add(left); + dfs3(s, dict, path, ret, i + 1, canBreak); + + path.remove(path.size() - 1); + } + + // 注意这些剪枝的代码. 关键在于此以减少复杂度 + if (ret.size() == beforeChange) { + canBreak[index] = false; + } + } + + /* + // 解法4:先用DP来求解某些字段是否能word break,然后再做 + */ + public static List wordBreak4(String s, Set dict) { + if (s == null || s.length() == 0 || dict == null) { + return null; + } + + List ret = new ArrayList(); + + List path = new ArrayList(); + + int len = s.length(); + + // i: 表示从i索引开始的字串可以word break. + boolean[] D = new boolean[len + 1]; + D[len] = true; + for (int i = len - 1; i >= 0; i--) { + for (int j = i; j <= len - 1; j++) { + // 左边从i 到 j + D[i] = false; + if (D[j + 1] && dict.contains(s.substring(i, j + 1))) { + D[i] = true; + break; + } + } + } + + dfs4(s, dict, path, ret, 0, D); + + return ret; + } + + public static void dfs4(String s, Set dict, + List path, List ret, int index, + boolean canBreak[]) { + int len = s.length(); + if (index == len) { + // 结束了。index到了末尾 + StringBuilder sb = new StringBuilder(); + for (String str: path) { + sb.append(str); + sb.append(" "); + } + // remove the last " " + sb.deleteCharAt(sb.length() - 1); + ret.add(sb.toString()); + return; + } + + // if can't break, we exit directly. + if (!canBreak[index]) { + return; + } + + for (int i = index; i < len; i++) { + // 注意这些索引的取值。左字符串的长度从0到len + String left = s.substring(index, i + 1); + if (!dict.contains(left)) { + // 如果左字符串不在字典中,不需要继续递归 + continue; + } + + // if can't find any solution, return false, other set it + // to be true; + path.add(left); + dfs4(s, dict, path, ret, i + 1, canBreak); + path.remove(path.size() - 1); + } + + } +} \ No newline at end of file diff --git a/greedy/CanCompleteCircuit.java b/greedy/CanCompleteCircuit.java new file mode 100644 index 0000000..4160dea --- /dev/null +++ b/greedy/CanCompleteCircuit.java @@ -0,0 +1,35 @@ +package Algorithms.greedy; + +public class CanCompleteCircuit { + public int canCompleteCircuit(int[] gas, int[] cost) { + if (gas == null || cost == null || gas.length == 0 || cost.length == 0) { + // Bug 0: should not return false; + return -1; + } + + int total = 0; + int sum = 0; + + int startIndex = 0; + + int len = gas.length; + for (int i = 0; i < len; i++) { + int dif = gas[i] - cost[i]; + sum += dif; + + if (sum < 0) { + // Means that from 0 to this gas station, none of them can be the solution. + startIndex = i + 1; // Begin from the next station. + sum = 0; // reset the sum. + } + + total += dif; + } + + if (total < 0) { + return -1; + } + + return startIndex; + } +} \ No newline at end of file diff --git a/greedy/Jump.java b/greedy/Jump.java new file mode 100644 index 0000000..2e94b92 --- /dev/null +++ b/greedy/Jump.java @@ -0,0 +1,34 @@ +package Algorithms.greedy; + +public class Jump { + public static void main(String[] strs) { + int[] A = {2, 3, 1, 1, 4}; + System.out.println(jump(A)); + } + + public static int jump(int[] A) { + if (A == null || A.length == 0) { + return 0; + } + + int len = A.length; + + int sum = 0; + + int des = len - 1; + while (des > 0) { // destination index + for (int i = 0; i < des; i++) { // 不断向前移动dest + if (A[i] + i >= des) { // 说明从i位置能1步到达dest的位置 + sum++; + des = i; // 更新dest位置,下一步就是计算要几步能调到当前i的位置 + //break; // 没必要再继续找,因为越早找到的i肯定越靠前,说明这一跳的距离越远 + // 这一行可以去掉, des = i,不符合for的条件,会自动break. + System.out.println("sum:" + sum); + System.out.println("des:" + des); + } + } + } + + return sum; + } +} \ No newline at end of file diff --git a/hash/Anagrams.java b/hash/Anagrams.java new file mode 100644 index 0000000..9348692 --- /dev/null +++ b/hash/Anagrams.java @@ -0,0 +1,90 @@ +package Algorithms.hash; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Anagrams { + public List anagrams(String[] strs) { + List ret = new ArrayList(); + + if (strs == null) { + return ret; + } + + HashMap> map = new HashMap>(); + + int len = strs.length; + for (int i = 0; i < len; i++) { + String s = strs[i]; + + // Sort the string. + char[] chars = s.toCharArray(); + Arrays.sort(chars); + String strSort = new String(chars); + + // Create a ArrayList for the sorted string. + if (!map.containsKey(strSort)) { + map.put(strSort, new ArrayList()); + } + + // Add a new string to the list of the hashmap. + map.get(strSort).add(s); + } + + // go through the map and add all the strings into the result. + for (Map.Entry> entry: map.entrySet()) { + List list = entry.getValue(); + + // skip the entries which only have one string. + if (list.size() == 1) { + continue; + } + + // add the strings into the list. + ret.addAll(list); + } + + return ret; + } + + public static void main(String[] strs1) { + String[] strs = {"str1", "str2", "s1tr"}; + System.out.println(anagrams2(strs)); + } + + public static List anagrams2(String[] strs) { + List ret = new ArrayList(); + if (strs == null) { + return ret; + } + + HashMap> map = new HashMap>(); + for (int i = 0; i < strs.length; i++) { + String s = strs[i]; + char[] chars = s.toCharArray(); + + Arrays.sort(chars); + String sSort = new String(chars); + + if (map.containsKey(sSort)) { + map.get(sSort).add(s); + } else { + List list = new ArrayList(); + list.add(s); + map.put(sSort, list); + } + } + + for (Map.Entry> entry: map.entrySet()) { + List list = entry.getValue(); + if (list.size() > 1) { + ret.addAll(list); + } + } + + return ret; + } +} \ No newline at end of file diff --git a/hash/IsValidSudoku.java b/hash/IsValidSudoku.java new file mode 100644 index 0000000..b296596 --- /dev/null +++ b/hash/IsValidSudoku.java @@ -0,0 +1,74 @@ +package Algorithms.hash; + +import java.util.HashSet; + +public class IsValidSudoku { + public static void main(String[] strs) { + + } + + public static boolean isValidSudoku(char[][] board) { + if (board == null || board.length != 9 || + board[0].length != 9) { + return false; + } + + HashSet set = new HashSet(); + + // check the rows. + for (int i = 0; i < 9; i++) { + // clear the set at every row. + set.clear(); + for (int j = 0; j < 9; j++) { + if (!isValidChar(board[i][j], set)) { + return false; + } + } + } + + // check the columns. + for (int i = 0; i < 9; i++) { + // clear the set at every column. + set.clear(); + for (int j = 0; j < 9; j++) { + if (!isValidChar(board[j][i], set)) { + return false; + } + } + } + + // check the blocks. + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + // clear the set at every block. + set.clear(); + for (int k = 0; k < 9; k++) { + if (!isValidChar(board[i*3 + k / 3][j*3 + k % 3], set)) { // here is a bug + return false; + } + } + } + } + + return true; + } + + public static boolean isValidChar(char c, HashSet set) { + if (c == '.') { + return true; + } + + if (c < '0' || c > '9') { + return false; + } + + // Check if the character exit in the hashset. + if (set.contains(c)) { + return false; + } + + set.add(c); + + return true; + } +} diff --git a/hash/LRUCache.java b/hash/LRUCache.java new file mode 100644 index 0000000..82b2bc2 --- /dev/null +++ b/hash/LRUCache.java @@ -0,0 +1,90 @@ +package Algorithms.hash; + +import java.util.HashMap; + +public class LRUCache { + private class DLink { + DLink pre; + DLink next; + int val; + int key; + DLink(int key, int val) { + this.val = val; + this.key = key; + pre = null; + next = null; + } + } + + HashMap map; + + DLink head; + DLink tail; + + int capacity; + + public void removeFist() { + removeNode(head.next); + } + + public void removeNode(DLink node) { + node.pre.next = node.next; + node.next.pre = node.pre; + } + + // add a node to the tail. + public void addToTail(DLink node) { + tail.pre.next = node; + + node.pre = tail.pre; + node.next = tail; + + tail.pre = node; + } + + public LRUCache(int capacity) { + map = new HashMap(); + + // two dummy nodes. In that case, we can deal with them more conviencely. + head = new DLink(-1, -1); + tail = new DLink(-1, -1); + head.next = tail; + tail.pre = head; + + this.capacity = capacity; + } + + public int get(int key) { + if (map.get(key) == null) { + return -1; + } + + // update the node. + DLink node = map.get(key); + removeNode(node); + addToTail(node); + + return node.val; + } + + public void set(int key, int value) { + DLink node = map.get(key); + if (node == null) { + // create a node and add the key-node pair into the map. + node = new DLink(key, value); + map.put(key, node); + } else { + // update the value of the node. + node.val = value; + removeNode(node); + } + + addToTail(node); + + // if the LRU is full, just remove a node. + if (map.size() > capacity) { + map.remove(head.next.key); + removeFist(); + } + } +} \ No newline at end of file diff --git a/hash/LRUCache2.java b/hash/LRUCache2.java new file mode 100644 index 0000000..8458990 --- /dev/null +++ b/hash/LRUCache2.java @@ -0,0 +1,51 @@ +package Algorithms.hash; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class LRUCache2 { + public static void main(String[] strs) { + LRUCache2 lrc2 = new LRUCache2(2); + lrc2.set(1,3); + lrc2.set(2,2); + lrc2.set(1,4); + lrc2.set(4,2); + + System.out.println(lrc2.get(1)); + } + + LinkedHashMap map; + int capacity; + + public LRUCache2(final int capacity) { + // create a map. + map = new LinkedHashMap(capacity) { + /** + * + */ + private static final long serialVersionUID = 1L; + + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > capacity; + } + }; + this.capacity = capacity; + } + + public int get(int key) { + Integer ret = map.get(key); + if (ret == null) { + return -1; + } else { + map.remove(key); + map.put(key, ret); + } + + return ret; + } + + public void set(int key, int value) { + map.remove(key); + map.put(key, value); + } +} diff --git a/hash/LongestConsecutive.java b/hash/LongestConsecutive.java new file mode 100644 index 0000000..b624144 --- /dev/null +++ b/hash/LongestConsecutive.java @@ -0,0 +1,95 @@ +package Algorithms.hash; + +import java.util.HashMap; +import java.util.HashSet; + +public class LongestConsecutive { + // Solution 1: use hashmap. + public int longestConsecutive1(int[] num) { + if (num == null) { + return 0; + } + + HashMap map = new HashMap(); + + int max = 0; + + int len = num.length; + for (int i = 0; i < len ; i++) { + // 寻找以num[i] 起头或是结尾的,如果找到,则可以跳过,因为我们 + // 不需要重复的数字 + if (map.get(num[i]) != null) { + continue; + } + + int left = num[i]; + int right = num[i]; + + // 寻找左边界 + Integer board = map.get(num[i] - 1); + if (board != null && board < left) { + // 更新左边界 + left = board; + + // 删除左边2个集合 + map.remove(left); + map.remove(num[i] - 1); + } + + // 寻找右边界 + board = map.get(num[i] + 1); + if (board != null && board > right) { + // 更新右边界 + right = board; + + // 删除右边2个集合 + map.remove(right); + map.remove(num[i] + 1); + } + + // 创建新的合并之后的集合 + map.put(left, right); + map.put(right, left); + + max = Math.max(max, right - left + 1); + } + + return max; + } + + // solution 2: use Hashset. + public int longestConsecutive(int[] num) { + if (num == null) { + return 0; + } + + HashSet set = new HashSet(); + for (int i: num) { + set.add(i); + } + + int max = 0; + for (int i: num) { + int cnt = 1; + set.remove(i); + + int tmp = i - 1; + while (set.contains(tmp)) { + set.remove(tmp); + cnt++; + tmp--; + } + + tmp = i + 1; + while (set.contains(tmp)) { + set.remove(tmp); + cnt++; + tmp++; + } + + max = Math.max(max, cnt); + } + + return max; + } +} diff --git a/hash/MaxPoints.java b/hash/MaxPoints.java new file mode 100644 index 0000000..37495bc --- /dev/null +++ b/hash/MaxPoints.java @@ -0,0 +1,50 @@ +package Algorithms.hash; + +import java.awt.Point; +import java.util.HashMap; + +public class MaxPoints { + public int maxPoints(Point[] points) { + int max = 0; + + if (points == null) { + return 0; + } + + int len = points.length; + + for (int i = 0; i < len; i++) { + // Create a map to recode all the numbers of elements of every K. + HashMap map = new HashMap(); + + // ItSelf. + int dup = 0; + + for (int j = i; j < len; j++) { + // the same point. + if (points[i].x == points[j].x && points[i].y == points[j].y) { + dup++; + continue; + } + + double k = Double.MAX_VALUE; + if (points[i].x != points[j].x) { + k = 0 + (double)(points[i].y - points[j].y)/(double)(points[i].x - points[j].x); + } + + if (map.containsKey(k)) { + map.put(k, map.get(k) + 1); + } else { + map.put(k, 1); + } + } + + max = Math.max(max, dup); + for (int n: map.values()) { + max = Math.max(max, n + dup); + } + } + + return max; + } +} \ No newline at end of file diff --git a/hash/SolveSudoku.java b/hash/SolveSudoku.java new file mode 100644 index 0000000..129bb83 --- /dev/null +++ b/hash/SolveSudoku.java @@ -0,0 +1,71 @@ +package Algorithms.hash; + +public class SolveSudoku { + public void solveSudoku(char[][] board) { + dfs(board, 0, 0); + } + + public boolean dfs(char[][] board, int x, int y) { + // go to next row. + if (y == 9) { + y = 0; + x++; + } + + // done + if (x >= 9) { + return true; + } + + // Skip the solved point. + if (board[x][y] != '.') { + return dfs(board, x, y + 1); + } + + // Go throught all the possibilities. + for (int k = 0; k < 9; k++) { + board[x][y] = (char)('1' + k); + // SHOULD RETURN HERE IF INVALID. + if (isValid(board, x, y) && dfs(board, x, y + 1)) { + return true; + } + board[x][y] = '.'; + } + + // because all the possibility is impossiable. + return false; + } + + public boolean isValid(char[][] board, int x, int y) { + // Judge the column. + for (int i = 0; i < 9; i++) { + if (i != x && board[i][y] == board[x][y]) { + return false; + } + } + + // Judge the row. + for (int i = 0; i < 9; i++) { + if (i != y && board[x][i] == board[x][y]) { + return false; + } + } + + // Judge the block. + int i = x / 3 * 3; + int j = y / 3 * 3; + for (int k = 0; k < 9; k++) { + int xIndex = i + k / 3; + int yIndex = j + k % 3; + if (xIndex == x && yIndex == y) { + continue; + } + + if (board[xIndex][yIndex] == board[x][y]) { + return false; + } + } + + return true; + } +} diff --git a/lintcode/array/FindFirstBadVersion.java b/lintcode/array/FindFirstBadVersion.java new file mode 100644 index 0000000..460db23 --- /dev/null +++ b/lintcode/array/FindFirstBadVersion.java @@ -0,0 +1,61 @@ +package Algorithms.lintcode.array; + +/** + * public class VersionControl { + * public static boolean isBadVersion(int k); + * } + * you can use VersionControl.isBadVersion(k) to judge wether + * the kth code version is bad or not. +*/ +class Solution { + /** + * @param n: An integers. + * @return: An integer which is the first bad version. + */ + public int findFirstBadVersion(int n) { + // write your code here + if (n == 1) { + return 1; + } + + int left = 1; + int right = n; + + while (left + 1 < right) { + int mid = left + (right - left) / 2; + if (VersionControl.isBadVersion(mid)) { + right = mid; + } else { + left = mid; + } + } + + if (VersionControl.isBadVersion(left)) { + return left; + } + + return right; + } + + // solution 2. + public int findFirstBadVersion2(int n) { + // write your code here + if (n == 1) { + return 1; + } + + int left = 1; + int right = n; + + while (left < right) { + int mid = left + (right - left) / 2; + if (VersionControl.isBadVersion(mid)) { + right = mid; + } else { + left = mid + 1; + } + } + + return right; + } +} \ No newline at end of file diff --git a/lintcode/array/MinSubArray.java b/lintcode/array/MinSubArray.java new file mode 100644 index 0000000..843387e --- /dev/null +++ b/lintcode/array/MinSubArray.java @@ -0,0 +1,30 @@ +package Algorithms.lintcode.array; + +import java.util.ArrayList; + +public class MinSubArray { + /** + * @param nums: a list of integers + * @return: A integer indicate the sum of minimum subarray + */ + public int minSubArray(ArrayList nums) { + // write your code + + int len = nums.size(); + + int max = Integer.MIN_VALUE; + int sum = 0; + for (int i = 0; i < len; i++) { + if (sum < 0) { + sum = -nums.get(i); + } else { + sum += -nums.get(i); + } + + max = Math.max(max, sum); + } + + return -max; + } +} + diff --git a/lintcode/array/Rerange.java b/lintcode/array/Rerange.java new file mode 100644 index 0000000..15d37c8 --- /dev/null +++ b/lintcode/array/Rerange.java @@ -0,0 +1,344 @@ +package Algorithms.lintcode.array; + +class Rerange { + public static void main(String[] strs) { + int A[] = {1,2,3,4,-1, 2, 5, 5, -5, 6, -7,-8,843,6,1}; + int B[] = {1,2,-3,-4,-1, -2, -5, -5, -5, 6, -7,-8,843,6,1}; + rerange(A); + + for (int i = 0; i < A.length; i++) { + System.out.print(A[i] + " "); + } + + rerange(B); + System.out.println(); + + for (int i = 0; i < B.length; i++) { + System.out.print(B[i] + " "); + } + } + + /** + * @param A: An integer array. + * @return an integer array + */ + // SOLUTION 1: 判断正数多还是负数多。 + public static int[] rerange1(int[] A) { + // write your code here + + // Check the input parameter. + if (A == null || A.length == 0) { + return A; + } + + int len = A.length; + + int left = -1; + int right = A.length; + + // divide the negative and positive integers. + while (true) { + while (left < A.length - 1 && A[++left] < 0); + + while (left < right && A[--right] > 0); + + if (left >= right) { + break; + } + + swap(A, left, right); + } + + // LEFT: point to the first positive number. + int negNum = left; + int posNum = len - left; + + int les = Math.min(negNum, posNum); + int dif = Math.abs(negNum - posNum); + + // 如果负数比较多,把多的负数扔到后面去 + if (negNum > posNum) { + int cnt = dif; + int l = les; + int r = len - 1; + while (cnt > 0) { + swap(A, l, r); + l++; + r--; + cnt--; + } + + // 负数多的时候,负数在前,反之,正数在前 + left = -1; + // 跳过右边不需要交换的值 + right = A.length - dif; + } else { + // 正数在前 + left = -2; + // 跳过右边不需要交换的值 + right = A.length - dif + 1; + } + + /* + -1 -2 -5 -6 3 4 les = 2; + 4 -2 -5 -6 3 -1 + */ + // swap the negative and the positive + while (true) { + left += 2; + right -= 2; + + if (left >= les) { + break; + } + swap(A, left, right); + } + + return A; + } + + public static void swap(int[] A, int n1, int n2) { + int tmp = A[n1]; + A[n1] = A[n2]; + A[n2] = tmp; + } + + /* + Solution 2: + */ + public static int[] rerange2(int[] A) { + // write your code here + + // Check the input parameter. + if (A == null || A.length <= 2) { + return A; + } + + int len = A.length; + + int cntPositive = 0; + + for (int num: A) { + if (num > 0) { + cntPositive++; + } + } + + // If positive numbers are more than negative numbers, + // Put the positive numbers at first. + int posPointer = 1; + int negPointer = 0; + + // means + boolean pos = false; + + if (cntPositive > A.length / 2) { + // Have more Positive numbers; + posPointer = 0; + negPointer = 1; + + pos = true; + } + + int i = 1; + int j = len - 2; + + if (pos) { + while (true) { + // Put the positive numbers at the end. + if (i < len && A[i] < 0) { + i += 2; + } + + if (j > i && A[j] > 0) { + j -= 2; + } + + if (i >= j) { + break; + } + + swap(A, i, j); + } + } else { + while (true) { + // Put the negative numbers at the end. + if (i < len && A[i] > 0) { + i += 2; + } + + if (j > i && A[j] < 0) { + j -= 2; + } + + if (i >= j) { + break; + } + + swap(A, i, j); + } + } + + // Reorder the negative and the positive numbers. + while (true) { + // Should move if it is in the range. + while (posPointer < len && A[posPointer] > 0) { + posPointer += 2; + } + + // Should move if it is in the range. + while (negPointer < len && A[negPointer] < 0) { + negPointer += 2; + } + + if (posPointer >= len || negPointer >= len) { + break; + } + + swap(A, posPointer, negPointer); + } + + return A; + } + + /* + Solution 3: + */ + public static int[] rerange3(int[] A) { + // write your code here + + // Check the input parameter. + if (A == null || A.length <= 2) { + return A; + } + + int len = A.length; + + int cntPositive = 0; + + // store the positive numbers index. + int i1 = 0; + + for (int i2 = 0; i2 < len; i2++) { + if (A[i2] > 0) { + cntPositive++; + + // Put all the positive numbers at in the left part. + swap(A, i1++, i2); + } + } + + // If positive numbers are more than negative numbers, + // Put the positive numbers at first. + int posPointer = 1; + int negPointer = 0; + + if (cntPositive > A.length / 2) { + // Have more Positive numbers; + posPointer = 0; + negPointer = 1; + + // Reverse the array. + int left = 0; + int right = len -1; + while (left < right) { + int tmp = A[left]; + A[left] = A[right]; + A[right] = tmp; + left++; + right--; + } + } + + // Reorder the negative and the positive numbers. + while (true) { + // Should move if it is in the range. + while (posPointer < len && A[posPointer] > 0) { + posPointer += 2; + } + + // Should move if it is in the range. + while (negPointer < len && A[negPointer] < 0) { + negPointer += 2; + } + + if (posPointer >= len || negPointer >= len) { + break; + } + + swap(A, posPointer, negPointer); + } + + return A; + } + + /* + Solution 4: + 把reverse的步骤简化了一下 + */ + public static int[] rerange(int[] A) { + // write your code here + + // Check the input parameter. + if (A == null || A.length <= 2) { + return A; + } + + int len = A.length; + + int cntPositive = 0; + + // store the positive numbers index. + int i1 = 0; + + for (int i2 = 0; i2 < len; i2++) { + if (A[i2] > 0) { + cntPositive++; + + // Put all the positive numbers at in the left part. + swap(A, i1++, i2); + } + } + + // If positive numbers are more than negative numbers, + // Put the positive numbers at first. + int posPointer = 1; + int negPointer = 0; + + if (cntPositive > A.length / 2) { + // Have more Positive numbers; + posPointer = 0; + negPointer = 1; + + // Reverse the array. + int left = 0; + int right = len -1; + while (right >= cntPositive) { + swap(A, left, right); + left++; + right--; + } + } + + // Reorder the negative and the positive numbers. + while (true) { + // Should move if it is in the range. + while (posPointer < len && A[posPointer] > 0) { + posPointer += 2; + } + + // Should move if it is in the range. + while (negPointer < len && A[negPointer] < 0) { + negPointer += 2; + } + + if (posPointer >= len || negPointer >= len) { + break; + } + + swap(A, posPointer, negPointer); + } + + return A; + } +} diff --git a/lintcode/array/SortKColors.java b/lintcode/array/SortKColors.java new file mode 100644 index 0000000..e9f0509 --- /dev/null +++ b/lintcode/array/SortKColors.java @@ -0,0 +1,117 @@ +package Algorithms.lintcode.array; + +class SortKColors { + public static void main(String[] strs) { + int A[] = {2,2,3,1,1,1,2,3,2,2}; + sortKColors(A, 3); + + for (int i = 0; i < A.length; i++) { + System.out.print(" " + A[i]); + } + } + + + /** + * @param colors: A list of integer + * @param k: An integer + * @return: nothing + */ + /* + Solution 1: Using the quick sort. + */ + public static void sortKColors1(int[] colors, int k) { + // write your code here + if (colors == null) { + return; + } + + quickSort(colors, 0, colors.length - 1); + } + + public static void quickSort(int[] colors, int left, int right) { + if (left >= right) { + return; + } + + int pivot = colors[right]; + + int pos = partition(colors, left, right, pivot); + + quickSort(colors, left, pos - 1); + quickSort(colors, pos + 1, right); + } + + public static int partition(int[] colors, int left, int right, int pivot) { + int leftPoint = left - 1; + int rightPoint = right; + + while (true) { + while (colors[++leftPoint] < pivot); + + while (leftPoint < rightPoint && colors[--rightPoint] > pivot); + + if (leftPoint >= rightPoint) { + break; + } + + swap(colors, leftPoint, rightPoint); + } + + swap(colors, leftPoint, right); + return leftPoint; + } + + public static void swap(int[] colors, int left, int right) { + int tmp = colors[left]; + colors[left] = colors[right]; + colors[right] = tmp; + } + + // Solution 2: inplace, O(n) + public static void sortKColors(int[] colors, int k) { + // write your code here + if (colors == null) { + return; + } + + int len = colors.length; + for (int i = 0; i < len; i++) { + // Means need to deal with A[i] + while (colors[i] > 0) { + int num = colors[i]; + if (colors[num - 1] > 0) { + // 1. There is a number in the bucket, + // Store the number in the bucket in position i; + colors[i] = colors[num - 1]; + colors[num - 1] = -1; + } else if (colors[num - 1] < 0) { + // 2. Bucket is using. + colors[num - 1]--; + // delete the A[i]; + colors[i] = 0; + } else if (colors[num - 1] == 0) { + // 3. The bucket is empty. + colors[num - 1] = -1; + // delete the A[i]; + colors[i] = 0; + } + } + } + + int index = len - 1; + for (int i = k - 1; i >= 0; i--) { + int cnt = -colors[i]; + + // Empty number. + if (cnt == 0) { + continue; + } + + while (cnt > 0) { + colors[index--] = i + 1; + cnt--; + } + } + } +} + diff --git a/lintcode/array/SubarraySum.java b/lintcode/array/SubarraySum.java new file mode 100644 index 0000000..eb15717 --- /dev/null +++ b/lintcode/array/SubarraySum.java @@ -0,0 +1,44 @@ +package Algorithms.lintcode.array; + +import java.util.ArrayList; +import java.util.HashMap; + + +public class SubarraySum { + /** + * @param nums: A list of integers + * @return: A list of integers includes the index of the first number + * and the index of the last number + */ + public ArrayList subarraySum(int[] nums) { + // write your code here + int len = nums.length; + + ArrayList ret = new ArrayList(); + + HashMap map = new HashMap(); + + // We set the index -1 sum to be 0 to let us more convient to count. + map.put(0, -1); + + int sum = 0; + for (int i = 0; i < len; i++) { + sum += nums[i]; + + if (map.containsKey(sum)) { + // For example: + // -3 1 2 -3 4 + // SUM: 0 -3 -2 0 -3 1 + // then we got the solution is : 0 - 2 + ret.add(map.get(sum) + 1); + ret.add(i); + return ret; + } + + // Store the key:value of sum:index. + map.put(sum, i); + } + + return ret; + } +} diff --git a/lintcode/array/VersionControl.java b/lintcode/array/VersionControl.java new file mode 100644 index 0000000..97d4ce0 --- /dev/null +++ b/lintcode/array/VersionControl.java @@ -0,0 +1,10 @@ +package Algorithms.lintcode.array; + +public class VersionControl { + + public static boolean isBadVersion(int mid) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/lintcode/dp/LongestCommonSubsequence.java b/lintcode/dp/LongestCommonSubsequence.java new file mode 100644 index 0000000..aad494a --- /dev/null +++ b/lintcode/dp/LongestCommonSubsequence.java @@ -0,0 +1,35 @@ +package Algorithms.lintcode.dp; + +public class LongestCommonSubsequence { + /** + * @param A, B: Two strings. + * @return: The length of longest common subsequence of A and B. + */ + public int longestCommonSubsequence(String A, String B) { + // write your code here + if (A == null || B == null) { + return 0; + } + + int lenA = A.length(); + int lenB = B.length(); + int[][] D = new int[lenA + 1][lenB + 1]; + + for (int i = 0; i <= lenA; i++) { + for (int j = 0; j <= lenB; j++) { + if (i == 0 || j == 0) { + D[i][j] = 0; + } else { + if (A.charAt(i - 1) == B.charAt(j - 1)) { + D[i][j] = D[i - 1][j - 1] + 1; + } else { + D[i][j] = Math.max(D[i - 1][j], D[i][j - 1]); + } + } + } + } + + return D[lenA][lenB]; + } +} + diff --git a/lintcode/dp/LongestCommonSubstring.java b/lintcode/dp/LongestCommonSubstring.java new file mode 100644 index 0000000..bcb662a --- /dev/null +++ b/lintcode/dp/LongestCommonSubstring.java @@ -0,0 +1,41 @@ +package Algorithms.lintcode.dp; + +public class LongestCommonSubstring { + /** + * @param A, B: Two string. + * @return: the length of the longest common substring. + */ + public int longestCommonSubstring(String A, String B) { + // write your code here + if (A == null || B == null) { + return 0; + } + + int lenA = A.length(); + int lenB = B.length(); + + // bug 1: use error init. + int[][] D = new int[lenA + 1][lenB + 1]; + + int max = 0; + + // BUG 2: should use <= instead of < + for (int i = 0; i <= lenA; i++) { + for (int j = 0; j <= lenB; j++) { + if (i == 0 || j == 0) { + D[i][j] = 0; + } else { + if (A.charAt(i - 1) == B.charAt(j - 1)) { + D[i][j] = D[i - 1][j - 1] + 1; + } else { + D[i][j] = 0; + } + } + + max = Math.max(max, D[i][j]); + } + } + + return max; + } +} diff --git a/lintcode/math/FastPower.java b/lintcode/math/FastPower.java new file mode 100644 index 0000000..561af55 --- /dev/null +++ b/lintcode/math/FastPower.java @@ -0,0 +1,91 @@ +package Algorithms.lintcode.math; + +class FastPower { + public static void main(String[] strs) { + System.out.println(fastPower(2147483647, 2147483645, 214748364)); + + //System.out.println(Math.pow(2, 2147483647)); + + System.out.println(9 % (-2)); + } + + /* + * @param a, b, n: 32bit integers + * @return: An integer + */ + /* + * @param a, b, n: 32bit integers + * @return: An integer + */ + public static int fastPower(int a, int b, int n) { + // write your code here + long ret = pow(a, b, n); + + return (int) ret; + } + + // suppose n > 0 + public static long pow1(int a, int b, int n) { + if (a == 0) { + return 0; + } + + // The base case. + if (n == 0) { + return 1 % b; + } + + if (n == 1) { + return a % b; + } + + long ret = 0; + + // (a * b) % p = (a % p * b % p) % p (3) + ret = pow(a, b, n / 2); + ret *= ret; + + // 这一步是为了防止溢出 + ret %= b; + + if (n % 2 == 1) { + ret *= pow(a, b, 1); + } + + // 执行取余操作 + ret = ret % b; + + return ret; + } + + // SOLUTION 2: + // suppose n > 0 + public static long pow(int a, int b, int n) { + if (a == 0) { + return 0; + } + + // The base case. + if (n == 0) { + return 1 % b; + } + + long ret = 0; + + // (a * b) % p = (a % p * b % p) % p (3) + ret = pow(a, b, n / 2); + ret *= ret; + + // 这一步是为了防止溢出 + ret %= b; + + if (n % 2 == 1) { + ret *= (a % b); + } + + // 执行取余操作 + ret = ret % b; + + return ret; + } +}; diff --git a/lintcode/math/MajorityNumber.java b/lintcode/math/MajorityNumber.java new file mode 100644 index 0000000..edab444 --- /dev/null +++ b/lintcode/math/MajorityNumber.java @@ -0,0 +1,49 @@ +package Algorithms.lintcode.math; + +import java.util.ArrayList; + +public class MajorityNumber { + /** + * @param nums: a list of integers + * @return: find a majority number + */ + public int majorityNumber(ArrayList nums) { + // write your code + if (nums == null || nums.size() == 0) { + // No majority number. + return -1; + } + + int candidate = nums.get(0); + + // The phase 1: Voting. + int cnt = 1; + for (int i = 1; i < nums.size(); i++) { + if (nums.get(i) == candidate) { + cnt++; + } else { + cnt--; + if (cnt == 0) { + candidate = nums.get(i); + cnt = 1; + } + } + } + + // The phase 2: Examing. + cnt = 0; + for (int i = 0; i < nums.size(); i++) { + if (nums.get(i) == candidate) { + cnt++; + } + } + + // No majory number. + if (cnt <= nums.size() / 2) { + return -1; + } + + return candidate; + } +} + diff --git a/lintcode/math/MajorityNumber2.java b/lintcode/math/MajorityNumber2.java new file mode 100644 index 0000000..0dfe87a --- /dev/null +++ b/lintcode/math/MajorityNumber2.java @@ -0,0 +1,63 @@ +package Algorithms.lintcode.math; + +import java.util.ArrayList; + +public class MajorityNumber2 { + /** + * @param nums: A list of integers + * @return: The majority number that occurs more than 1/3 + */ + public int majorityNumber(ArrayList nums) { + // write your code + // When there are only 1 or 2 elements in the array, + // there is no solution. + if (nums == null || nums.size() <= 2) { + return -1; + } + + int n1 = 0; + int n2 = 0; + + int cnt1 = 0; + int cnt2 = 0; + + int size = nums.size(); + for (int i = 0; i < size; i++) { + int num = nums.get(i); + if (cnt1 != 0 && num == n1) { + cnt1++; + } else if (cnt2 != 0 && num == n2) { + cnt2++; + } else if (cnt1 == 0) { + cnt1 = 1; + n1 = num; + } else if (cnt2 == 0) { + cnt2 = 1; + n2 = num; + } else { + cnt1--; + cnt2--; + } + } + + // count the two candiates. + cnt1 = 0; + cnt2 = 0; + for (int num: nums) { + if (num == n1) { + cnt1++; + } else if (num == n2) { + cnt2++; + } + } + + if (cnt1 < cnt2) { + return n2; + } + + return n1; + } +} + + + diff --git a/lintcode/stack/StackQueue.java b/lintcode/stack/StackQueue.java new file mode 100644 index 0000000..2886fb7 --- /dev/null +++ b/lintcode/stack/StackQueue.java @@ -0,0 +1,43 @@ +package Algorithms.lintcode.stack; + +import java.util.Stack; + +public class StackQueue { + private Stack stack1; + private Stack stack2; + + public StackQueue() { + // do initialization if necessary + stack1 = new Stack(); + stack2 = new Stack(); + } + + public void push(int element) { + // write your code here + stack1.push(element); + } + + public int pop() { + // write your code here + if (stack2.isEmpty()) { + while (!stack1.isEmpty()) { + stack2.push(stack1.pop()); + } + } + + return stack2.pop(); + } + + public int top() { + // write your code here + // write your code here + if (stack2.isEmpty()) { + while (!stack1.isEmpty()) { + stack2.push(stack1.pop()); + } + } + + return stack2.peek(); + } +} + diff --git a/list/AddTwoNumbers.java b/list/AddTwoNumbers.java new file mode 100644 index 0000000..a46119a --- /dev/null +++ b/list/AddTwoNumbers.java @@ -0,0 +1,75 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class AddTwoNumbers { + public static void main(String[] str) { + ListNode n1 = new ListNode(9); + + ListNode l1 = new ListNode(1); + ListNode l2 = new ListNode(9); + ListNode l3 = new ListNode(9); + ListNode l4 = new ListNode(9); + ListNode l5 = new ListNode(9); + ListNode l6 = new ListNode(9); + ListNode l7 = new ListNode(9); + ListNode l8 = new ListNode(9); + ListNode l9 = new ListNode(9); + ListNode l10 = new ListNode(9); + + l1.next = l2; + l2.next = l3; + l3.next = l4; + l4.next = l5; + l5.next = l6; + l6.next = l7; + l7.next = l8; + l8.next = l9; + l9.next = l10; + + System.out.println(addTwoNumbers(n1, l1).toString()); + } + + public static ListNode addTwoNumbers(ListNode l1, ListNode l2) { + if (l1 == null || l2 == null) { + return null; + } + + ListNode dummy = new ListNode(0); + ListNode tail = dummy; + int carry = 0; + + while (l1 != null || l2 != null || carry == 1) { + int sum = carry; + if (l1 != null) { + sum += l1.val; + l1 = l1.next; + } + + if (l2 != null) { + sum += l2.val; + l2 = l2.next; + } + + carry = sum / 10; + + // create a new node and add it to the tail. + ListNode cur = new ListNode(sum % 10); + tail.next = cur; + tail = tail.next; + } + + return dummy.next; + } +} \ No newline at end of file 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; + } +} diff --git a/list/DeleteDuplicates.java b/list/DeleteDuplicates.java new file mode 100644 index 0000000..aa978a5 --- /dev/null +++ b/list/DeleteDuplicates.java @@ -0,0 +1,40 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.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 diff --git a/list/DeleteDuplicates2.java b/list/DeleteDuplicates2.java new file mode 100644 index 0000000..9fbe983 --- /dev/null +++ b/list/DeleteDuplicates2.java @@ -0,0 +1,60 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.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 diff --git a/list/DetectCycle.java b/list/DetectCycle.java new file mode 100644 index 0000000..1314732 --- /dev/null +++ b/list/DetectCycle.java @@ -0,0 +1,55 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class DetectCycle { + public ListNode detectCycle(ListNode head) { + if (head == null) { + return null; + } + + ListNode s = head; + ListNode f = head; + + ListNode cross = null; + + while (f != null && f.next != null) { + s = s.next; + f = f.next.next; + + if (s == f) { + cross = s; + + // remember to break here, or you will get a loop. + break; + } + } + + // don't detect any cycle. + if (cross == null) { + return null; + } + + // place the slow to the start again. + s = head; + while (true) { + if (s == f) { + return s; + } + + s = s.next; + f = f.next; + } + } +} \ No newline at end of file diff --git a/list/Generate.java b/list/Generate.java new file mode 100644 index 0000000..3dbce0d --- /dev/null +++ b/list/Generate.java @@ -0,0 +1,27 @@ +package Algorithms.list; + +import java.util.ArrayList; +import java.util.List; + +public class Generate { + public List> generate(int numRows) { + List> ret = new ArrayList>(); + + for (int i = 0; i < numRows; i++) { + List list = new ArrayList(); + for (int j = 0; j <= i; j++) { + if (j == 0 || i == j) { + list.add(1); + } else { + int sum = ret.get(i - 1).get(j - 1) + ret.get(i - 1).get(j); + list.add(sum); + } + } + + // BUG 1: forget this statement. + ret.add(list); + } + + return ret; + } +} \ No newline at end of file diff --git a/list/GetIntersectionNode1.java b/list/GetIntersectionNode1.java new file mode 100644 index 0000000..13c5e29 --- /dev/null +++ b/list/GetIntersectionNode1.java @@ -0,0 +1,98 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class GetIntersectionNode1 { + public ListNode getIntersectionNode1(ListNode headA, ListNode headB) { + if (headA == null || headB == null) { + return null; + } + + int lenA = getLen(headA); + int lenB = getLen(headB); + + if (lenA > lenB) { + while (lenA > lenB) { + headA = headA.next; + lenA--; + } + } else { + while (lenA < lenB) { + headB = headB.next; + lenB--; + } + } + + while (headA != null) { + if (headA == headB) { + return headA; + } + headA = headA.next; + headB = headB.next; + } + + return null; + } + + public int getLen(ListNode node) { + int len = 0; + while (node != null) { + len++; + node = node.next; + } + return len; + } + + public ListNode getIntersectionNode(ListNode headA, ListNode headB) { + if (headA == null || headB == null) { + return null; + } + + ListNode pA = headA; + ListNode pB = headB; + + ListNode tailA = null; + ListNode tailB = null; + + while (true) { + if (pA == null) { + pA = headB; + } + + if (pB == null) { + pB = headA; + } + + if (pA.next == null) { + tailA = pA; + } + + if (pB.next == null) { + tailB = pB; + } + + //The two links have different tails. So just return null; + if (tailA != null && tailB != null && tailA != tailB) { + return null; + } + + if (pA == pB) { + return pA; + } + + pA = pA.next; + pB = pB.next; + } + } +} \ No newline at end of file diff --git a/list/HasCycle.java b/list/HasCycle.java new file mode 100644 index 0000000..44ca454 --- /dev/null +++ b/list/HasCycle.java @@ -0,0 +1,35 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class HasCycle { + public boolean hasCycle(ListNode head) { + if (head == null) { + return false; + } + + ListNode slow = head; + ListNode fast = head; + + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + if (slow == fast) { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/list/InsertionSortList.java b/list/InsertionSortList.java new file mode 100644 index 0000000..88d5bb6 --- /dev/null +++ b/list/InsertionSortList.java @@ -0,0 +1,39 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.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) { + ListNode dummy = new ListNode(0); + + while (head != null) { + ListNode pre = dummy; + + // 注意,这里要用<= 来保证算法的稳定性 + // 因为假如有2个数相同,后面的数后找到,也要插入到后面才可以。也就是说当=的时候,是继续往下走 + while (pre.next != null && pre.next.val <= head.val) { + pre = pre.next; + } + + // unlink the node from the original link. And record the next position. + ListNode headNext = head.next; + head.next = pre.next; + + pre.next = head; + head = headNext; + } + + return dummy.next; + } +} \ No newline at end of file diff --git a/list/ListNodeDemo.java b/list/ListNodeDemo.java new file mode 100644 index 0000000..fa03323 --- /dev/null +++ b/list/ListNodeDemo.java @@ -0,0 +1,716 @@ +package Algorithms.list; + +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/list/MergeKLists.java b/list/MergeKLists.java new file mode 100644 index 0000000..6e3cf16 --- /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.algorithm.others.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; + } +} diff --git a/list/MergeKLists_1204.java b/list/MergeKLists_1204.java new file mode 100644 index 0000000..c1da6d4 --- /dev/null +++ b/list/MergeKLists_1204.java @@ -0,0 +1,122 @@ +package Algorithms.list; +import java.util.Comparator; +import java.util.List; +import java.util.PriorityQueue; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class MergeKLists_1204 { + /* + SOL 1: + 使用merge sort和分治法完成 + */ + public ListNode mergeKLists1(List lists) { + // 记得加上这个合法性判断。 + if (lists == null || lists.size() == 0) { + return null; + } + + return helper(lists, 0, lists.size() - 1); + } + + /* + l, r表示list的左右边界 + */ + public ListNode helper(List lists, int l, int r) { + if (l < r) { + int mid = l + (r - l) / 2; + + /* + 分治法。把问题分为2个更小的子问题:左边list的merge,和右边list的merge. + 再把2个生成的解合并在一起。 + */ + return merge(helper(lists, l, mid), helper(lists, mid + 1, r)); + } + + return lists.get(l); + } + + public ListNode merge(ListNode n1, ListNode n2) { + ListNode dummy = new ListNode(0); + ListNode cur = dummy; + + while (n1 != null && n2 != null) { + if (n1.val < n2.val) { + cur.next = n1; + n1 = n1.next; + } else { + cur.next = n2; + n2 = n2.next; + } + + cur = cur.next; + } + + if (n1 != null) { + cur.next = n1; + } else { + cur.next = n2; + } + + return dummy.next; + } + + /* + SOL 2: + 使用 priority Queue. + */ + public ListNode mergeKLists(List lists) { + // 记得加上这个合法性判断。 + if (lists == null || lists.size() == 0) { + return null; + } + + int size = lists.size(); + + PriorityQueue q = new PriorityQueue(size, + new Comparator() { + // 注意,此处参数用ListNode + public int compare(ListNode o1, ListNode o2) { + return o1.val - o2.val; + } + } + ); + + // Add all the head node to the priority queue. + for (ListNode node: lists) { + if (node != null) { + // Should skip the null node.s + q.offer(node); + } + } + + ListNode dummy = new ListNode(0); + ListNode tail = dummy; + + while (!q.isEmpty()) { + // get the smallest node from the queue. + ListNode cur = q.poll(); + + tail.next = cur; + tail = tail.next; + + // 将下一个节点补充进来。 + if (cur.next != null) { + q.offer(cur.next); + } + } + + return dummy.next; + } +} \ No newline at end of file diff --git a/list/MergeTwoLists.java b/list/MergeTwoLists.java new file mode 100644 index 0000000..a1fd02f --- /dev/null +++ b/list/MergeTwoLists.java @@ -0,0 +1,33 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.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; + } +} diff --git a/list/MergeTwoLists_1206.java b/list/MergeTwoLists_1206.java new file mode 100644 index 0000000..d5dd9a6 --- /dev/null +++ b/list/MergeTwoLists_1206.java @@ -0,0 +1,40 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class MergeTwoLists_1206 { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + 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; + } +} \ No newline at end of file diff --git a/list/Partition.java b/list/Partition.java new file mode 100644 index 0000000..b7a65c3 --- /dev/null +++ b/list/Partition.java @@ -0,0 +1,57 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class Partition { + public ListNode partition(ListNode head, int x) { + if (head == null) { + return null; + } + + ListNode dummy = new ListNode(0); + dummy.next = head; + + ListNode pre = dummy; + ListNode cur = head; + + // Record the big list. + ListNode bigDummy = new ListNode(0); + ListNode bigTail = bigDummy; + + while (cur != null) { + if (cur.val >= x) { + // Unlink the cur; + pre.next = cur.next; + + // Add the cur to the tail of the new link. + bigTail.next = cur; + cur.next = null; + + // Refresh the bigTail. + bigTail = cur; + + // 移除了一个元素的时候,pre不需要修改,因为cur已经移动到下一个位置了。 + } else { + pre = pre.next; + } + + cur = pre.next; + } + + // Link the Big linklist to the smaller one. + pre.next = bigDummy.next; + + return dummy.next; + } +} \ No newline at end of file diff --git a/list/PartitionList.java b/list/PartitionList.java new file mode 100644 index 0000000..94e2763 --- /dev/null +++ b/list/PartitionList.java @@ -0,0 +1,51 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.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; + } +} diff --git a/list/RemoveNthFromEnd.java b/list/RemoveNthFromEnd.java new file mode 100644 index 0000000..8b256fd --- /dev/null +++ b/list/RemoveNthFromEnd.java @@ -0,0 +1,47 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.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. + if (pre.next != null) { + pre.next = pre.next.next; + } + + return dummy.next; + } +} \ No newline at end of file diff --git a/list/ReorderList.java b/list/ReorderList.java new file mode 100644 index 0000000..3e0b780 --- /dev/null +++ b/list/ReorderList.java @@ -0,0 +1,109 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.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/list/ReverseBetween.java b/list/ReverseBetween.java new file mode 100644 index 0000000..4708320 --- /dev/null +++ b/list/ReverseBetween.java @@ -0,0 +1,49 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.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; + } + +} diff --git a/list/ReverseKGroup.java b/list/ReverseKGroup.java new file mode 100644 index 0000000..105581f --- /dev/null +++ b/list/ReverseKGroup.java @@ -0,0 +1,124 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class ReverseKGroup { + // Solution 1: + // recursion. + public ListNode reverseKGroup1(ListNode head, int k) { + if (head == null) { + return null; + } + + return rec(head, k); + } + + public ListNode rec(ListNode head, int k) { + ListNode dummy = new ListNode(0); + + dummy.next = head; + + int len = 0; + ListNode cur = head; + while (cur != null) { + ListNode tmp = cur.next; + cur.next = dummy.next; + dummy.next = cur; + cur = tmp; + len++; + + // reverse all the k nodes. + if (len == k) { + // link the tail to the next node in the list. + head.next = rec(tmp, k); + break; + } + } + + if (len != k) { + ListNode node = dummy.next; + dummy.next = null; + + while (node != null) { + ListNode next = node.next; + node.next = dummy.next; + dummy.next = node; + node = next; + } + } + + return dummy.next; + } + + /* + * Solution 2: iteration. + * */ + public ListNode reverseKGroup(ListNode head, int k) { + if (head == null) { + return null; + } + + ListNode dummy = new ListNode(0); + dummy.next = head; + + ListNode cur = head; + ListNode pre = dummy; + + int cnt = 0; + + while (cur != null) { + cnt++; + if (cnt == k) { + cnt = 0; + pre = reverse(pre, cur.next); + } + cur = cur.next; + } + + return dummy.next; + } + + /** + * Reverse a link list between pre and next exclusively + * an example: + * a linked list: + * 0->1->2->3->4->5->6 + * | | + * pre next + * after call pre = reverse(pre, next) + * + * 0->3->2->1->4->5->6 + * | | + * pre next + * @param pre + * @param next + * @return the reversed list's last node, which is the precedence of parameter next + */ + private static ListNode reverse(ListNode pre, ListNode next){ + ListNode cur = pre.next; + + // record the new tail. + ListNode last = cur; + while (cur != next) { + ListNode tmp = cur.next; + cur.next = pre.next; + pre.next = cur; + cur = tmp; + } + + last.next = next; + return last; + } + +} diff --git a/list/ReverseKGroup_1227_2014.java b/list/ReverseKGroup_1227_2014.java new file mode 100644 index 0000000..6323c2c --- /dev/null +++ b/list/ReverseKGroup_1227_2014.java @@ -0,0 +1,201 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class ReverseKGroup_1227_2014 { + public static void main(String[] strs) { + ListNode node1 = new ListNode(1); + ListNode node2 = new ListNode(2); + + node1.next = node2; + + System.out.println(reverseKGroup(node1, 1)); + + } + + public ListNode reverseKGroup1(ListNode head, int k) { + if (head == null) { + return null; + } + + return rec(head, k); + } + + // Solution 1: Recursion. + public ListNode rec(ListNode head, int k) { + // Reverse k and link to the next section. + ListNode dummy = new ListNode(0); + dummy.next = head; + + // find the tail node of the section. If not find, just return. + int cnt = k; + ListNode tail = dummy; + while (cnt > 0 && tail != null) { + cnt--; + tail = tail.next; + } + + // We don't have k nodes to revers. + // bug 1: we should judge that if tail == null to avoid the overflow. + if (tail == null) { + return head; + } + + // cut the 2 list. + ListNode next = tail.next; + tail.next = null; + + // reverse the first list. + ListNode newHead = reverse(head); + + // reverse the next section. + next = rec(next, k); + + // link the 2 sections. + head.next = next; + + return newHead; + } + + public ListNode reverse(ListNode head) { + ListNode dummy = new ListNode(0); + while (head != null) { + ListNode tmp = head.next; + head.next = dummy.next; + dummy.next = head; + + head = tmp; + } + + return dummy.next; + } + + /* + SOLUTION 2: A better rec version. + */ + public ListNode reverseKGroup2(ListNode head, int k) { + if (head == null) { + return null; + } + + return rec2(head, k); + } + + public ListNode rec2(ListNode head, int k) { + if (head == null) { + return null; + } + + ListNode dummy = new ListNode(0); + + ListNode cur = head; + int cnt = 0; + while (cur != null) { + ListNode tmp = cur.next; + cur.next = dummy.next; + dummy.next = cur; + + cur = tmp; + + cnt++; + + // reverse a k group. + if (cnt == k) { + // BUG 1: + head.next = rec2(tmp, k); + return dummy.next; + } + } + + // we don't have k nodes. + if (cnt != k) { + cur = dummy.next; + dummy.next = null; + + // reverse again. + while (cur != null) { + ListNode tmp = cur.next; + cur.next = dummy.next; + dummy.next = cur; + + cur = tmp; + } + } + + return dummy.next; + } + + /* + SOLUTION 3: A Iteration version. + */ + public static ListNode reverseKGroup(ListNode head, int k) { + if (head == null) { + return null; + } + + ListNode dummy = new ListNode(0); + dummy.next = head; + + ListNode pre = dummy; + ListNode cur = pre.next; + + int cnt = 0; + while (cur != null) { + cnt++; + cur = cur.next; + + if (cnt == k) { + cnt = 0; + pre = reverseSection(pre, cur); + cur = pre.next; + } + } + + return dummy.next; + } + + + /** + * Reverse a link list between pre and next exclusively + * an example: + * a linked list: + * 0->1->2->3->4->5->6 + * | | + * pre next + * after call pre = reverse(pre, next) + * + * 0->3->2->1->4->5->6 + * | | + * pre next + * @param pre + * @param next + * @return the reversed list's last node, which is the precedence of parameter next + */ + private static ListNode reverseSection(ListNode pre, ListNode next){ + ListNode cur = pre.next; + + // record the new tail. + ListNode tail = cur; + + while (cur != next) { + ListNode tmp = cur.next; + cur.next = pre.next; + pre.next = cur; + cur = tmp; + } + + tail.next = next; + return tail; + } +} \ No newline at end of file diff --git a/ReverseLinkedList2.java b/list/ReverseLinkedList2.java similarity index 95% rename from ReverseLinkedList2.java rename to list/ReverseLinkedList2.java index 8246c8b..e28e162 100644 --- a/ReverseLinkedList2.java +++ b/list/ReverseLinkedList2.java @@ -1,4 +1,6 @@ -package Algorithms; +package Algorithms.list; + +import Algorithms.algorithm.others.ListNode; public class ReverseLinkedList2 { public static void main(String[] args) { diff --git a/list/RotateList.java b/list/RotateList.java new file mode 100644 index 0000000..c674ef1 --- /dev/null +++ b/list/RotateList.java @@ -0,0 +1,69 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class RotateList { + public static void main(String[] strs) { + ListNode node1 = new ListNode(1); + ListNode ret = rotateRight(node1, 0); + System.out.println(ret.toString()); + } + + public static 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 static int getlen(ListNode head) { + int len = 0; + while (head != null) { + len++; + head = head.next; + } + + return len; + } +} diff --git a/list/RotateRight.java b/list/RotateRight.java new file mode 100644 index 0000000..14c996a --- /dev/null +++ b/list/RotateRight.java @@ -0,0 +1,92 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class RotateRight { + // Solution 1: + public ListNode rotateRight1(ListNode head, int n) { + if (head == null) { + return head; + } + + int len = getLen(head); + + // 不需要重复地rotate. + n = n % len; + + if (n == 0) { + return head; + } + + ListNode end = head; + while (n > 0) { + end = end.next; + n--; + } + + ListNode pre = head; + while (end.next != null) { + pre = pre.next; + end = end.next; + } + + ListNode headNew = pre.next; + end.next = head; + pre.next = null; + + return headNew; + } + + public int getLen(ListNode head) { + int len = 0; + while (head != null) { + len++; + head = head.next; + } + return len; + } + + // Solution 2: 使用dummynode. + public ListNode rotateRight(ListNode head, int n) { + if (head == null) { + return head; + } + + int len = getLen(head); + + // 不需要重复地rotate. + n = n % len; + + ListNode dummy = new ListNode(0); + dummy.next = head; + + ListNode end = dummy; + while (n > 0) { + end = end.next; + n--; + } + + ListNode pre = dummy; + while (end.next != null) { + pre = pre.next; + end = end.next; + } + + end.next = dummy.next; + ListNode headNew = pre.next; + pre.next = null; + + return headNew; + } +} \ No newline at end of file diff --git a/list/SwapPairs.java b/list/SwapPairs.java new file mode 100644 index 0000000..e46cc8b --- /dev/null +++ b/list/SwapPairs.java @@ -0,0 +1,75 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ + +public class SwapPairs { + // Solution 1: recursion. + public ListNode swapPairs1(ListNode head) { + return rec(head); + } + + public ListNode rec(ListNode head) { + // nodes less than 2, do nothing. + if (head == null || head.next == null) { + return head; + } + + // reverse the next part. + ListNode next = rec(head.next.next); + + // store the new head; + ListNode headNew = head.next; + + // reverse the two nodes. + headNew.next = head; + head.next = next; + + return headNew; + } + + public ListNode swapPairs(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + ListNode dummy = new ListNode(0); + dummy.next = head; + + // the node before the area which want to reverse + ListNode pre = dummy; + + while (pre.next != null && pre.next.next != null) { + // the node after the area which want to reverse + ListNode next = pre.next.next.next; + + // reserve the new tail. + ListNode tmp = pre.next; + + // link pre to the new head; + pre.next = pre.next.next; + + // link the next node. + pre.next.next = tmp; + + // linke the area to the next area. + tmp.next = next; + + // move forward the pre node. + pre = tmp; + } + + return dummy.next; + } +} diff --git a/list/SwapPairs3.java b/list/SwapPairs3.java new file mode 100644 index 0000000..7dd2eb9 --- /dev/null +++ b/list/SwapPairs3.java @@ -0,0 +1,105 @@ +package Algorithms.list; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class SwapPairs3 { + // Solution 1: the recursion version. + public ListNode swapPairs1(ListNode head) { + if (head == null) { + return null; + } + + return rec(head); + } + + public ListNode rec(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + ListNode next = head.next.next; + + // 翻转后面的链表 + next = rec(next); + + // store the new head. + ListNode tmp = head.next; + + // reverse the two nodes. + head.next = next; + tmp.next = head; + + return tmp; + } + + // Solution 2: the iteration version. + public ListNode swapPairs(ListNode head) { + // 如果小于2个元素,不需要任何操作 + if (head == null || head.next == null) { + return head; + } + + ListNode dummy = new ListNode(0); + dummy.next = head; + + // The node before the reverse area; + ListNode pre = dummy; + + while (pre.next != null && pre.next.next != null) { + // The last node of the reverse area; + ListNode tail = pre.next.next; + + ListNode tmp = pre.next; + pre.next = tail; + + ListNode next = tail.next; + tail.next = tmp; + tmp.next = next; + + // move forward the pre node. + pre = tmp; + } + + return dummy.next; + } + + // Solution 3: the iteration version. + public ListNode swapPairs3(ListNode head) { + // 如果小于2个元素,不需要任何操作 + if (head == null || head.next == null) { + return head; + } + + ListNode dummy = new ListNode(0); + dummy.next = head; + + // The node before the reverse area; + ListNode pre = dummy; + + while (pre.next != null && pre.next.next != null) { + ListNode next = pre.next.next.next; + + ListNode tmp = pre.next; + pre.next = pre.next.next; + pre.next.next = tmp; + + tmp.next = next; + + // move forward the pre node. + pre = tmp; + } + + return dummy.next; + } +} \ No newline at end of file diff --git a/math/Reverse.java b/math/Reverse.java new file mode 100644 index 0000000..221dbac --- /dev/null +++ b/math/Reverse.java @@ -0,0 +1,18 @@ +package Algorithms.math; + +public class Reverse { + public int reverse(int x) { + long ret = 0; + + while (x != 0) { + ret = ret * 10 + x % 10; + x /= 10; + } + + if (ret > Integer.MAX_VALUE || ret < Integer.MIN_VALUE) { + return 0; + } + + return (int)ret; + } +} \ No newline at end of file diff --git a/new/FindSubstring.java b/new/FindSubstring.java new file mode 100644 index 0000000..696a7c2 --- /dev/null +++ b/new/FindSubstring.java @@ -0,0 +1,71 @@ +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + + +public class FindSubstring { + public static void main(String[] strs) { + String S = "barfoothefoobarman"; + String[] L = {"foo","bar"}; + + System.out.print(findSubstring(S, L)); + } + + public static List findSubstring(String S, String[] L) { + ArrayList ret = new ArrayList(); + if (S == null || L == null || L.length == 0) { + return ret; + } + + HashMap map = new HashMap(); + HashMap des = new HashMap(); + + for (String s: L) { + if (map.containsKey(s)) { + map.put(s, map.get(s) + 1); + } else { + // bug 1: should be , not . + map.put(s, 1); + } + } + + int wordLen = L[0].length(); + + int size = L.length; + int cnt = 0; + + int len = S.length(); + for (int i = 0; i < len; i++) { + map.clear(); + cnt = 0; + + // pay attention: should use j <= len. + for (int j = i; j <= len - wordLen; j += wordLen) { + String sub = S.substring(j, j + wordLen); + + if (!map.containsKey(sub)) { + break; + } + + if (des.containsKey(sub)) { + des.put(sub, 1 + des.get(sub)); + } else { + des.put(sub, 1); + } + + if (des.get(sub) > map.get(sub)) { + break; + } + + cnt++; + + if (cnt == size) { + ret.add(i); + break; + } + } + } + + return ret; + } +} \ No newline at end of file diff --git a/new/IsPalindrome.java b/new/IsPalindrome.java new file mode 100644 index 0000000..82108e4 --- /dev/null +++ b/new/IsPalindrome.java @@ -0,0 +1,25 @@ + +public class IsPalindrome { + public static void main(String[] strs) { + System.out.print(isPalindrome(12344321)); + } + + public static boolean isPalindrome(int x) { + long y = 0; + + if (x < 0) { + return false; + } + + int tmp = x; + while (tmp > 0) { + int a = tmp % 10; + tmp /= 10; + + y *= 10; + y += a; + } + + return y == x; + } +} \ No newline at end of file diff --git a/new/LRUCache.java b/new/LRUCache.java new file mode 100644 index 0000000..e61f344 --- /dev/null +++ b/new/LRUCache.java @@ -0,0 +1,97 @@ +import java.util.HashMap; + + +public class LRUCache { + public static void main(String[] strs) { + LRUCache cache = new LRUCache(1); + + cache.set(2, 1); + cache.get(2); + cache.set(3, 2); + cache.get(2); + + } + + HashMap map; + int capacity; + + ListNode head; + ListNode tail; + + public class ListNode { + int key; + int val; + ListNode pre; + ListNode next; + + public ListNode (int key, int val) { + this.key = key; + this.val = val; + this.pre = null; + this.next = null; + } + } + + public LRUCache(int capacity) { + this.capacity = capacity; + map = new HashMap(); + + head = new ListNode(-1, -1); + tail = new ListNode(-1, -1); + + head.next = tail; + tail.pre = head; + } + + public void moveToTail(ListNode node) { + // connect the node into the list. + node.pre = tail.pre; + node.next = tail; + + tail.pre.next = node; + tail.pre = node; + } + + public void removeNode(ListNode node) { + node.pre.next = node.next; + node.next.pre = node.pre; + } + + public int get(int key) { + if (map.get(key) == null) { + return -1; + } else { + // move the node to the tail. + ListNode node = map.get(key); + removeNode(node); + moveToTail(node); + + return node.val; + } + } + + public void set(int key, int value) { + ListNode node = map.get(key); + if (node == null) { + node = new ListNode(key, value); + + // but 2: forget to add the node into the map. + map.put(key, node); + } else { + // set the value. + node.val = value; + + removeNode(node); + } + + moveToTail(node); + + // the map is full, remove the head node. + // bug 1: use map.size() instead of map.size. + if (map.size() > capacity) { + map.remove(head.next.key); + + removeNode(head.next); + } + } +} \ No newline at end of file diff --git a/new/LengthOfLastWord.java b/new/LengthOfLastWord.java new file mode 100644 index 0000000..0ea8ae4 --- /dev/null +++ b/new/LengthOfLastWord.java @@ -0,0 +1,25 @@ +public class LengthOfLastWord { + public static void main(String[] strs) { + System.out.println(lengthOfLastWord(" a")); + } + + public static int lengthOfLastWord(String s) { + if (s == null || s.length() == 0) { + return 0; + } + + String strNew = s.trim(); + + int len = strNew.length(); + + int start = 0; + for (int i = len - 1; i >= 0; i--) { + if (s.charAt(i) == ' ') { + start = i + 1; + break; + } + } + + return (len - start); + } +} \ No newline at end of file diff --git a/new/MinWindow.java b/new/MinWindow.java new file mode 100644 index 0000000..2a19ed8 --- /dev/null +++ b/new/MinWindow.java @@ -0,0 +1,163 @@ +import java.util.HashMap; + + +public class MinWindow { + + public static void main(String[] args) { + // TODO Auto-generated method stub + System.out.println(minWindow("ab", "b")); + } + + public static String minWindow1(String S, String T) { + int lenS = S.length(); + int lenT = T.length(); + + if (lenT > lenS) { + // No such window + return ""; + } + + HashMap map = new HashMap(); + for (int i = 0; i < lenT; i++) { + char c = T.charAt(i); + if (map.containsKey(c)) { + map.put(c, map.get(c) + 1); + } else { + map.put(c, 1); + } + } + + int cnt = 0; + int size = map.size(); + + int left = -1; + + String sub = ""; + int minLen = Integer.MAX_VALUE; + + // bug 1: should use ';' instead of ',' + for (int right = 0; right < lenS; right++) { + // bug 2: write i instead of right. + char c = S.charAt(right); + + // bug 5: should add this statement to skip the invalid characters. + if (!map.containsKey(c)) { + continue; + } + + map.put(c, map.get(c) - 1); + + if (map.get(c) == 0) { + cnt++; + } + + //compress the left side. + if (cnt == size) { + while (left < lenS - 1) { + left++; + + char cLeft = S.charAt(left); + if (!map.containsKey(cLeft)) { + // bug 6. + // skip the invalid characters. + continue; + } + + map.put(cLeft, map.get(cLeft) + 1); + + // bug: should use > 0, because it means that the characters is not enought + // if the number of characters reduce to below level, we should break; + if (map.get(cLeft) > 0) { + cnt--; + // Bug 7: + if (minLen > right - left + 1) { + minLen = right - left + 1; + sub = S.substring(left, right + 1); + } + + break; + } + + + + } + } + } + + return sub; + } + + public static String minWindow(String S, String T) { + int lenS = S.length(); + int lenT = T.length(); + + String sub = ""; + + if (lenT > lenS) { + // No such window + return sub; + } + + // ʽʼĬ0 + // http://developer.51cto.com/art/200906/128274.htm + + // store the number of the characters. + int[] src = new int[128]; + int[] des = new int[128]; + + int size = 0, cnt = 0; + + for (int i = 0; i < lenT; i++) { + int num = T.charAt(i); + src[num]++; + + if (src[num] == 1) { + size++; + } + } + + int minLen = Integer.MAX_VALUE; + + int left = -1; + + for (int right = 0; right < lenS; right++) { + char c = S.charAt(right); + if (src[c] != 0) { + des[c]++; + + // bug 1: the statement should be in the 'src[c] != 0' + if (des[c] == src[c]) { + cnt++; + } + } + + if (cnt == size) { + while (left < lenS - 1) { + left++; + + char cLeft = S.charAt(left); + + // skip the invalid character. + if (src[cLeft] == 0) { + continue; + } + + des[cLeft]--; + if (src[cLeft] > des[cLeft]) { + cnt--; // the count reduce to the lower bound. + + // put the statement here. + int len = right - left + 1; + if (len < minLen) { + minLen = len; + sub = S.substring(left, right + 1); + } + break; + } + } + } + } + + return sub; + } +} diff --git a/new/ThreeSum.java b/new/ThreeSum.java new file mode 100644 index 0000000..995d245 --- /dev/null +++ b/new/ThreeSum.java @@ -0,0 +1,61 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + +public class ThreeSum { + public static void main(String[] str) { + int[] num = {0,0,0,0}; + System.out.println(threeSum(num)); + } + + public static List> threeSum(int[] num) { + ArrayList> ret = new ArrayList>(); + if (num == null || num.length == 0) { + return ret; + } + + int len = num.length; + + // sort the array to get unique solutions. + Arrays.sort(num); + for (int i = 0; i < len - 2; i++) { + // skip the duplicate numbers. + while (i != 0 && num[i] == num[i - 1]) { + continue; + } + + int n2 = i + 1; + int n3 = len - 1; + + while (n2 < n3) { + int sum = num[i] + num[n2] + num[n3]; + if (sum == 0) { + ArrayList list = new ArrayList(); + list.add(i); + list.add(n2); + list.add(n3); + ret.add(list); + + n2++; + n3--; + + // skip the duplication. + while (n2 < len - 1 && num[n2] == num[n2 - 1]) { + n2++; + } + + while (n3 > i && num[n3] == num[n3 + 1]) { + n3--; + } + } else if (sum > 0) { + n3--; + } else { + n2++; + } + } + } + + return ret; + } +} \ No newline at end of file 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/permutation/Permutation.java b/permutation/Permutation.java new file mode 100644 index 0000000..be7cc87 --- /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 HASHMAP: " + + timer1.elapsedTime() + " millisec."); + + System.out.printf("Test size:%d \n", num.length); + + Stopwatch timer2 = new Stopwatch(); + + permute2(num); + System.out + .println("Computing time with list: " + + 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/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)); + } + +} diff --git a/permutation/PermuteUnique.java b/permutation/PermuteUnique.java new file mode 100644 index 0000000..4d91540 --- /dev/null +++ b/permutation/PermuteUnique.java @@ -0,0 +1,78 @@ +package Algorithms.permutation; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class PermuteUnique { + public static void main(String[] strs) { + int[] num = {1, 1, 1, 3}; + List> ret = permuteUnique(num); + System.out.println(ret.toString()); + } + + public static List> permuteUnique(int[] num) { + List> ret = new ArrayList>(); + if (num == null || num.length == 0) { + return ret; + } + + // For deal with the duplicate solution, we should sort it. + Arrays.sort(num); + boolean[] visit = new boolean[num.length]; + + dfs1(num, new ArrayList(), ret, visit); + + return ret; + } + + public static void dfs1(int[] num, ArrayList path, List> ret, boolean[] visit) { + int len = num.length; + if (path.size() == len) { + ret.add(new ArrayList(path)); + return; + } + + for (int i = 0; i < len; i++) { + // 只能连续地选,这样就可以避免生成重复的solution. + // 例子:1 2 3 4 4 4 5 6 7 8 + // 444这个的选法只能:4, 44, 444连续这三种选法 + if (visit[i] || (i != 0 && !visit[i - 1] && num[i] == num[i - 1])) { + continue; + } + + // 递归以及回溯 + visit[i] = true; + path.add(num[i]); + dfs1(num, path, ret, visit); + path.remove(path.size() - 1); + visit[i] = false; + } + } + + // SOLUTION 2: + // 使用一个pre来记录。只取第一个可以取的位置 + public void dfs(int[] num, ArrayList path, List> ret, boolean[] visit) { + int len = num.length; + if (path.size() == len) { + ret.add(new ArrayList(path)); + return; + } + + long pre = Long.MIN_VALUE; + for (int i = 0; i < len; i++) { + int n = num[i]; + // 只取第一个可取的位置,因为别的位置取到的也没有区别 + if (visit[i] || pre == n) { + continue; + } + pre = n; + + // 递归以及回溯 + visit[i] = true; + path.add(n); + dfs(num, path, ret, visit); + path.remove(path.size() - 1); + visit[i] = false; + } + } +} \ No newline at end of file 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/recursion/Factorial.java b/recursion/Factorial.java new file mode 100644 index 0000000..39603ef --- /dev/null +++ b/recursion/Factorial.java @@ -0,0 +1,41 @@ +package Algorithms.recursion; + +import java.util.Stack; + +public class Factorial { + public static void main(String[] strs) { + System.out.println(factorial(10)); + System.out.println(factorialIterator(10)); + } + + public static int factorialIterator(Integer n) { + int ret = 1; + for (int i = n; i >= 1; i--) { + ret *= i; + } + + return ret; + } + + + public static int factorial(Integer n) { + Stack s = new Stack(); + + s.push(n); + + int ret = 1; + + while (!s.isEmpty()) { + int cur = s.pop(); + + if (cur == 1) { + break; + } + + ret *= cur; + s.push(cur - 1); + } + + return ret; + } +} diff --git a/recursion/GrayCode.java b/recursion/GrayCode.java new file mode 100644 index 0000000..d766135 --- /dev/null +++ b/recursion/GrayCode.java @@ -0,0 +1,24 @@ +package Algorithms.recursion; + +import java.util.ArrayList; +import java.util.List; + +public class GrayCode { + public List grayCode(int n) { + List ret = new ArrayList(); + if (n == 0) { + ret.add(0); + return ret; + } + + ret = grayCode(n - 1); + + for (int i = ret.size() - 1; i >= 0; i--) { + int num = ret.get(i); + num += 1 << (n - 1); + ret.add(num); + } + + return ret; + } +} \ No newline at end of file diff --git a/sequence/FourSum.java b/sequence/FourSum.java new file mode 100644 index 0000000..e937910 --- /dev/null +++ b/sequence/FourSum.java @@ -0,0 +1,61 @@ +package Algorithms.sequence; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class FourSum { + public List> fourSum(int[] num, int target) { + List> ret = new ArrayList>(); + if (num == null) { + return ret; + } + + Arrays.sort(num); + + int len = num.length; + for (int i = 0; i < len; i++) { + if (i > 0 && num[i] == num[i - 1]) { + // skip duplicate. + continue; + } + + for (int j = i + 1; j < len; j++) { + if (j > i + 1 && num[j] == num[j - 1]) { + // skip duplicate. + continue; + } + + int l = j + 1; + int r = len - 1; + + while (l < r) { + int sum = num[i] + num[j] + num[l] + num[r]; + if (sum == target) { + ArrayList list = new ArrayList(); + list.add(num[i]); + list.add(num[j]); + list.add(num[l]); + list.add(num[r]); + + ret.add(list); + + do { + l++; + } while (l < r && num[l] == num[l - 1]); + + do { + r--; + } while (l < r && num[r] == num[r + 1]); + } else if (sum < target) { + l++; + } else { + r--; + } + } + } + } + + return ret; + } +} diff --git a/sequence/Reverse.java b/sequence/Reverse.java new file mode 100644 index 0000000..7892811 --- /dev/null +++ b/sequence/Reverse.java @@ -0,0 +1,21 @@ +package Algorithms.sequence; +public class Reverse { + public static void main(String[] args) { + System.out.println(reverse(-1234)); + System.out.println(reverse(100)); + } + + public static int reverse(int x) { + long n = x; + + long ret = 0; + while (n != 0) { + long left = n % 10; + ret *= 10; + ret += left; + n /= 10; + } + + return (int)ret; + } +} \ No newline at end of file diff --git a/sequence/ThreeSum.java b/sequence/ThreeSum.java new file mode 100644 index 0000000..7d316c0 --- /dev/null +++ b/sequence/ThreeSum.java @@ -0,0 +1,53 @@ +package Algorithms.sequence; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ThreeSum { + public List> threeSum(int[] num) { + List> ret = new ArrayList>(); + if (num == null) { + return ret; + } + + Arrays.sort(num); + + int len = num.length; + for (int i = 0; i < len; i++) { + // 跳过重复的元素,首个数字不需要选择重复的. + if (i > 0 && num[i] == num[i - 1]) { + continue; + } + + // 创建二个指针,分别从2头查找,查目标值,它们2个加起来要等于0-num1 + int l = i + 1; + int r = len - 1; + while (l < r) { + int sum = num[i] + num[l] + num[r]; + if (sum == 0) { + ArrayList list = new ArrayList(); + list.add(num[i]); + list.add(num[l]); + list.add(num[r]); + ret.add(list); + + // 跳过重复元素 + do { + l++; + } while (l < r && num[l] == num[l - 1]); + + do { + r--; + } while (l < r && num[r] == num[r + 1]); + } else if (sum < 0) { + l++; + } else { + r--; + } + } + } + + return ret; + } +} \ No newline at end of file diff --git a/sequence/ThreeSumClosest.java b/sequence/ThreeSumClosest.java new file mode 100644 index 0000000..960f24c --- /dev/null +++ b/sequence/ThreeSumClosest.java @@ -0,0 +1,42 @@ +package Algorithms.sequence; + +public class ThreeSumClosest { + public int threeSumClosest(int[] num, int target) { + if (num == null) { + return 0; + } + + int len = num.length; + + int diffMin = Integer.MAX_VALUE; + + int ret = 0; + for (int i = 0; i < len; i++) { + + int l = i + 1; + int r = len - 1; + + while (l < r) { + int diff = target - (num[i] + num[l] + num[r]); + + if (Math.abs(diff) < diffMin) { + diffMin = Math.abs(diff); + ret = num[i] + num[l] + num[r]; + } + + if (diff > 0) { + // move right; + l++; + } else if (diff < 0) { + // move left; + r--; + } else { + // We get the 0 now. There is no way that it would be less than 0. + return ret; + } + } + } + + return ret; + } +} \ No newline at end of file diff --git a/sequence/TwoSum.java b/sequence/TwoSum.java new file mode 100644 index 0000000..a4481a2 --- /dev/null +++ b/sequence/TwoSum.java @@ -0,0 +1,35 @@ +package Algorithms.sequence; + +import java.util.HashMap; + +/* + * Two Sum Total Accepted: 36938 Total Submissions: 200732 My Submissions Question Solution +Given an array of integers, find two numbers such that they add up to a specific target number. + +The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based. + +You may assume that each input would have exactly one solution. + +Input: numbers={2, 7, 11, 15}, target=9 +Output: index1=1, index2=2 + * */ + +public class TwoSum { + public int[] twoSum(int[] numbers, int target) { + HashMap map = new HashMap(); + int[] ret = new int[2]; + + for (int i = 0; i < numbers.length; i++) { + if (map.containsKey(target - numbers[i])) { + + // As the index is not ZERO based, we should add one to the result. + ret[0] = map.get(target - numbers[i]) + 1; + ret[1] = i + 1; + return ret; + } + map.put(numbers[i], i); + } + + return ret; + } +} diff --git a/sort/BucketSorter.java b/sort/BucketSorter.java new file mode 100644 index 0000000..f473fd1 --- /dev/null +++ b/sort/BucketSorter.java @@ -0,0 +1,50 @@ +package Algorithms.sort; + + +/** + * @author yovn + * + */ +public class BucketSorter { + public void sort(int[] keys,int from,int len,int max) + { + int[] count = new int[max]; + int[] tmp = new int[len]; + + // count the keys. + for (int i = 0; i < len; i++) { + count[keys[from + i]]++; + } + + // calculate the position. + // BUG 1: i go from 1 not 0. + for (int i = 1; i < max; i++) { + count[i] = count[i] + count[i - 1]; + } + + // back the array. + System.arraycopy(keys, from, tmp, 0, len); + + // Place the objects into the right position. + for (int i = len - 1; i >= 0; i--) { + keys[--count[tmp[i]]] = tmp[i]; + } + } + /** + * @param args + */ + public static void main(String[] args) { + + int[] a={1,4,8,3,2,9,5,0,7,6,9,10,9,13,14,15,11,12,17,16}; + BucketSorter sorter=new BucketSorter(); + sorter.sort(a,0,a.length,20);//actually is 18, but 20 will also work + + + for(int i=0;i= left.length) { + while (rightPoint < right.length) { + ret[cur++] = right[rightPoint++]; + } + } else { + while (leftPoint < left.length) { + ret[cur++] = left[leftPoint++]; + } + } + + return ret; + } + + 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 diff --git a/sort/MergeSort_LinkedList.java b/sort/MergeSort_LinkedList.java new file mode 100644 index 0000000..401a734 --- /dev/null +++ b/sort/MergeSort_LinkedList.java @@ -0,0 +1,99 @@ +package Algorithms.sort; + +import java.util.LinkedList; + +import Algorithms.algorithm.others.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; + } +} diff --git a/sort/QuickSort.java b/sort/QuickSort.java new file mode 100644 index 0000000..dcf224c --- /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 = 10000; + 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(); + array[i] = i; + + //int[] array = {3, 4, 6, 1, 7, 8, 6}; + + // 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) { + // set the pivot. + int l = left - 1 ; + int r = right; + + /* + example: + let 6 to be the pivot. + + (1) At the beginning: + 3 4 6 1 7 8 6 + l r + + + (2) After the first while loop: + 3 4 6 1 7 8 6 + l r + + (3) swap them, then continue to move i and j: + 3 4 1 6 7 8 6 + l r + + (3) swap them, then continue to move i and j: + 3 4 1 6 7 8 6 + l pivot + r + (4) swap the left and the pivot. + 3 4 1 6 7 8 6 + l pivot + + */ + + while (true) { + // Find the first element which does not fulfill the rule + // It will not move out of range because the right node is pivot. + // 使用< 很重要,这样可以避免l跑到pivot的位置,就是right的位置 + //while (l < r && arr[++l] <= pivot); + while (arr[++l] < pivot); + + // Find the first element which does not fulfill the rule + // Don't need to move r to be left of LEFT. + while (r > l && arr[--r] > pivot); + + // 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 pivot. + // So we can put the pivot just here. Because put a big or equal 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/sort/SortColors.java b/sort/SortColors.java new file mode 100644 index 0000000..265b052 --- /dev/null +++ b/sort/SortColors.java @@ -0,0 +1,111 @@ +package Algorithms.sort; + +public class SortColors { + public void sortColors(int[] A) { + if (A == null || A.length == 0) { + return; + } + + int len = A.length; + + int red = 0; + int white = 0; + + for (int i = 0; i < len; i++) { + if (A[i] == 0) { + red++; + } else if (A[i] == 1) { + white++; + } + } + + for (int i = 0; i < len; i++) { + if (red > 0) { + A[i] = 0; + red--; + } else if (white > 0) { + A[i] = 1; + white--; + } else { + A[i] = 2; + } + } + } + + public void sortColors2(int[] A) { + if (A == null || A.length == 0) { + return; + } + + int len = A.length - 1; + int left = 0; + int right = len; + + int cur = 0; + while (cur <= right) { + if (A[cur] == 2) { + // 换到右边,换过来的有可能是0,也有可能是1,所以cur要停留 + + swap(A, cur, right); + right--; + } else if (A[cur] == 0) { + // 从左边换过来的只可能是1,所以可以直接cur++ + // 因为所有的2全部换到右边去了。 + + swap(A, cur, left); + left++; + cur++; + } else { + cur++; + } + } + } + + // Solution 3: use switch + public void sortColors3(int[] A) { + if (A == null || A.length == 0) { + return; + } + + int left = 0; + + // Bug 1: right is wrong. + int right = A.length - 1; + + int cur = 0; + + // left: the first one which is not 0 + // right: the first one which is not 2 + // So we should use <= because right may be not dealed with. + while (cur <= right) { + switch (A[cur]) { + case 0: + // Bug 0: Forget to add A. + swap(A, left, cur); + left++; + cur++; + break; + case 1: + cur++; + break; + case 2: + swap(A, cur, right); + right--; + // 这里不cur++的原因是,有可能从右边换过来有0,1还要继续处理 + break; + + default: + cur++; + break; + } + } + } + + public void swap(int[] A, int n1, int n2) { + int tmp = A[n1]; + A[n1] = A[n2]; + A[n2] = tmp; + } + + +} \ No newline at end of file diff --git a/sort/SortList.java b/sort/SortList.java new file mode 100644 index 0000000..4243acd --- /dev/null +++ b/sort/SortList.java @@ -0,0 +1,255 @@ +package Algorithms.sort; + +import Algorithms.algorithm.others.ListNode; + +/** + * Definition for singly-linked list. + * class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class SortList { + public static void main(String[] strs) { + ListNode n1 = new ListNode(2); + ListNode n2 = new ListNode(18); + ListNode n3 = new ListNode(3); + ListNode n4 = new ListNode(54); + ListNode n5 = new ListNode(6); + ListNode n6 = new ListNode(90); + ListNode n7 = new ListNode(2); + ListNode n8 = new ListNode(1); + ListNode n9 = new ListNode(19); + ListNode n10 = new ListNode(30); + + + n1.next = n2; + n2.next = n3; + n3.next = n4; + n4.next = n5; + n5.next = n6; + n6.next = n7; + n7.next = n8; + n8.next = n9; + n9.next = n10; + n10.next = null; + + ListNode ret = sortList(n1); + System.out.println(ret.toString()); + } + + public static ListNode sortList1(ListNode head) { + // Nodes should be more than 2. + if (head == null || head.next == null) { + return head; + } + + // get the mid node. + ListNode midPre = getMidPre(head); + + // Cut the two list. + ListNode right = midPre.next; + midPre.next = null; + + // Sort the left side and the right side. + ListNode left = sortList(head); + right = sortList(right); + + // Merge the two sides together. + return merge(left, right); + } + + // get the pre node before mid. + public static ListNode getMidPre1(ListNode head) { + ListNode slow = head; + ListNode fast = head; + + while (fast != null && fast.next != null && fast.next.next != null) { + slow = slow.next; + fast = fast.next.next; + } + + return slow; + } + + // get the pre node before mid. + public static ListNode getMidPre(ListNode head) { + ListNode slow = head; + + // fast提前一点儿。这样就可以得到前一个节点喽。 + ListNode fast = head.next; + + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + } + + return slow; + } + + public static ListNode merge(ListNode head1, ListNode head2) { + ListNode dummy = new ListNode(0); + ListNode cur = dummy; + + while (head1 != null && head2 != null) { + if (head1.val < head2.val) { + cur.next = head1; + head1 = head1.next; + } else { + cur.next = head2; + head2 = head2.next; + } + + cur = cur.next; + } + + if (head1 != null) { + cur.next = head1; + } else { + cur.next = head2; + } + + return dummy.next; + } + + /* + The Solution 2: + Quick Sort. + */ + public static ListNode sortList(ListNode head) { + if (head == null) { + return null; + } + + // Sort the list from 0 to len - 1 + return quickSort(head); + } + + // The quick sort algorithm + + // All the elements are the same! + public static boolean isDuplicate(ListNode head) { + while (head != null) { + if (head.next != null && head.next.val != head.val) { + return false; + } + + head = head.next; + } + + return true; + } + + public static ListNode quickSort(ListNode head) { + if (head == null) { + return null; + } + + // 如果整个链是重复的,直接跳过。 + if (isDuplicate(head)) { + return head; + } + + // Use the head node to be the pivot. + ListNode headNew = partition(head, head.val); + + // Find the pre position of the pivoit. + ListNode cur = headNew; + + ListNode dummy = new ListNode(0); + dummy.next = headNew; + + ListNode pre = dummy; + + // Find the pre node and the position of the piviot. + while (cur != null) { + if (cur.val == head.val) { + break; + } + + // move forward. + cur = cur.next; + pre = pre.next; + } + + // Cut the link to be three parts. + pre.next = null; + + // Get the left link; + ListNode left = dummy.next; + + // Get the right link. + ListNode right = cur.next; + cur.next = null; + + // Recurtion to call quick sort to sort left and right link. + left = quickSort(left); + right = quickSort(right); + + // Link the three part together. + + // Link the first part and the 2nd part. + if (left != null) { + dummy.next = left; + + // Find the tail of the left link. + while (left.next != null) { + left = left.next; + } + left.next = cur; + } else { + dummy.next = cur; + } + + cur.next = right; + + // The new head; + return dummy.next; + } + + // Return the new head; + public static ListNode partition(ListNode head, int x) { + if (head == null) { + return null; + } + + ListNode dummy = new ListNode(0); + dummy.next = head; + + ListNode pre = dummy; + ListNode cur = head; + + // Record the big list. + ListNode bigDummy = new ListNode(0); + ListNode bigTail = bigDummy; + + while (cur != null) { + if (cur.val >= x) { + // Unlink the cur; + pre.next = cur.next; + + // Add the cur to the tail of the new link. + bigTail.next = cur; + cur.next = null; + + // Refresh the bigTail. + bigTail = cur; + + // 移除了一个元素的时候,pre不需要修改,因为cur已经移动到下一个位置了。 + } else { + pre = pre.next; + } + + cur = pre.next; + } + + // Link the Big linklist to the smaller one. + pre.next = bigDummy.next; + + return dummy.next; + } +} \ No newline at end of file diff --git a/sort/SortList_leetCode.java b/sort/SortList_leetCode.java new file mode 100644 index 0000000..d4eeeda --- /dev/null +++ b/sort/SortList_leetCode.java @@ -0,0 +1,79 @@ +package Algorithms.sort; + +import Algorithms.algorithm.others.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 diff --git a/stack/EvalRPN.java b/stack/EvalRPN.java new file mode 100644 index 0000000..099f961 --- /dev/null +++ b/stack/EvalRPN.java @@ -0,0 +1,40 @@ +package Algorithms.stack; + +import java.util.Stack; + +public class EvalRPN { + public int evalRPN(String[] tokens) { + if (tokens == null) { + return 0; + } + + int len = tokens.length; + Stack s = new Stack(); + + for (int i = 0; i < len; i++) { + String str = tokens[i]; + if (str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/")) { + // get out the two operation number. + int n2 = s.pop(); + int n1 = s.pop(); + if (str.equals("+")) { + s.push(n1 + n2); + } else if (str.equals("-")) { + s.push(n1 - n2); + } else if (str.equals("*")) { + s.push(n1 * n2); + } else if (str.equals("/")) { + s.push(n1 / n2); + } + } else { + s.push(Integer.parseInt(str)); + } + } + + if (s.isEmpty()) { + return 0; + } + + return s.pop(); + } +} \ No newline at end of file diff --git a/stack/IsValid.java b/stack/IsValid.java new file mode 100644 index 0000000..a1a77cc --- /dev/null +++ b/stack/IsValid.java @@ -0,0 +1,81 @@ +package Algorithms.stack; + +import java.util.Stack; + +public class IsValid { + public boolean isValid1(String s) { + if (s == null || s.length() == 0) { + return true; + } + + Stack stack = new Stack(); + int len = s.length(); + for (int i = 0; i < len; i++) { + char c = s.charAt(i); + if (stack.isEmpty()) { + if (c == ']' || c == ')' || c == '}') { + return false; + } + stack.push(c); + continue; + } + + if (c == ')' && stack.peek() == '(' + || c == ']' && stack.peek() == '[' + || c == '}' && stack.peek() == '{' + ) { + stack.pop(); + } else if (c == '(' || c == '[' || c == '{') { + stack.push(c); + } else { + return false; + } + } + + return stack.isEmpty(); + } + public boolean isValid(String s) { + if (s == null) { + return false; + } + + int len = s.length(); + + // bug 1: don't use s as the name of the stack. + Stack stk = new Stack(); + + for (int i = 0; i < len; i++) { + char c = s.charAt(i); + switch(c) { + case '(': + case '[': + case '{': + stk.push(c); + break; + case ')': + if (!stk.isEmpty() && stk.peek() == '(') { + stk.pop(); + } else { + return false; + } + break; + case '}': + if (!stk.isEmpty() && stk.peek() == '{') { + stk.pop(); + } else { + return false; + } + break; + case ']': + if (!stk.isEmpty() && stk.peek() == '[') { + stk.pop(); + } else { + return false; + } + break; + } + } + + return stk.isEmpty(); + } +} \ No newline at end of file diff --git a/stack/MinStack.java b/stack/MinStack.java new file mode 100644 index 0000000..ceb9077 --- /dev/null +++ b/stack/MinStack.java @@ -0,0 +1,51 @@ +package Algorithms.stack; + +import java.util.Stack; + +class MinStack { + public static void main(String[] strs) { + MinStack sta = new MinStack(); + + //push(512),push(-1024),push(-1024),push(512),pop,getminStack,pop,getminStack,pop,getminStack + sta.push(512); + sta.push(-1024); + sta.push(-1024); + sta.push(512); + + sta.pop(); + sta.getminStack(); + sta.pop(); + sta.getminStack(); + sta.pop(); + sta.getminStack(); + } + + Stack elements = new Stack(); + Stack minStack = new Stack(); + + public void push(int x) { + elements.push(x); + if (minStack.isEmpty() || x <= minStack.peek()) { + minStack.push(x); + } + } + + public void pop() { + if (elements.isEmpty()) { + return; + } + + if (elements.peek().equals(minStack.peek())) { + minStack.pop(); + } + elements.pop(); + } + + public int top() { + return elements.peek(); + } + + public int getminStack() { + return minStack.peek(); + } +} diff --git a/string/AddBinary.java b/string/AddBinary.java new file mode 100644 index 0000000..692e7d5 --- /dev/null +++ b/string/AddBinary.java @@ -0,0 +1,51 @@ +package Algorithms.string; + +public class AddBinary { + public String addBinary(String a, String b) { + if (a == null || b == null) { + return null; + } + + if (a.length() == 0) { + return b; + } + + if (b.length() == 0) { + return a; + } + + StringBuilder sb = new StringBuilder(); + + int p1 = a.length() - 1; + int p2 = b.length() - 1; + + int carry = 0; + while (p1 >= 0 || p2 >= 0) { + int sum = carry; + if (p1 >= 0) { + sum += (a.charAt(p1) - '0'); + } + + if (p2 >= 0) { + sum += (b.charAt(p2) - '0'); + } + + char c = sum % 2 == 1 ? '1': '0'; + sb.insert(0, c); + carry = sum / 2; + + p1--; + p2--; + } + + if (carry == 1) { + sb.insert(0, '1'); + } + + return sb.toString(); + } +} + + + + \ No newline at end of file diff --git a/string/Atoi.java b/string/Atoi.java new file mode 100644 index 0000000..af0714d --- /dev/null +++ b/string/Atoi.java @@ -0,0 +1,86 @@ +package Algorithms.string; + +public class Atoi { + public int atoi(String str) { + if (str == null) { + return 0; + } + + // remove the spaces in the beginning and the end. + String s = str.trim(); + + boolean minus = false; + long num = 0; + for (int i = 0; i < s.length(); i++) { + /* + takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value. + */ + if (i == 0 && s.charAt(i) == '+') { + continue; + } else if (i == 0 && s.charAt(i) == '-'){ + // get the + minus = true; + continue; + } + + int c = s.charAt(i) - '0'; + if (c > 9 || c < 0) { + // invalid character. + break; + } + + num = num * 10 + c; + } + + // If the correct value is out of the range of representable values, INT_MAX (2147483647) or INT_MIN (-2147483648) is // returned. + if (minus) { + num = -num; + num = Math.max(num, Integer.MIN_VALUE); + } else { + num = Math.min(num, Integer.MAX_VALUE); + } + + return (int)num; + } + + // SOLUTION 2: the Leetcode test case is improved. + public int atoi2(String str) { + long ret = 0; + + // ___+1234__ + // Delete the leading and tailing spaces. + String sNew = str.trim(); + + if (sNew.length() == 0) { + return 0; + } + + boolean positive = true; + for (int i = 0; i < sNew.length(); i++) { + char c = sNew.charAt(i); + if (i == 0 && c == '+') { + continue; + } else if (i == 0 && c == '-') { + positive = false; + continue; + } + + if (!(c <= '9' && c >= '0')) { + break; + } + + int dig = positive ? c - '0': '0' - c; + + ret = ret * 10 + dig; + + // bug 2: should consider the out of range. + if (ret > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } else if (ret < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + } + + return (int)ret; + } +} \ No newline at end of file diff --git a/string/Convert.java b/string/Convert.java new file mode 100644 index 0000000..13e9bdf --- /dev/null +++ b/string/Convert.java @@ -0,0 +1,40 @@ +package Algorithms.string; + +public class Convert { + public static void main(String[] strs) { + System.out.println(convert("A", 1)); + } + + public static String convert(String s, int nRows) { + if (s == null) { + return null; + } + + // 第一个小部分的大小 + int size = 2 * nRows - 2; + + // 当行数为1的时候,不需要折叠。 + if (nRows <= 1) { + return s; + } + + StringBuilder ret = new StringBuilder(); + + int len = s.length(); + for (int i = 0; i < nRows; i++) { + // j代表第几个BLOCK + for (int j = i; j < len; j += size) { + ret.append(s.charAt(j)); + + // 即不是第一行,也不是最后一行,还需要加上中间的节点 + int mid = j + size - i * 2; + if (i != 0 && i != nRows - 1 && mid < len) { + char c = s.charAt(mid); + ret.append(c); + } + } + } + + return ret.toString(); + } +} diff --git a/string/CountAndSay.java b/string/CountAndSay.java new file mode 100644 index 0000000..9e567ad --- /dev/null +++ b/string/CountAndSay.java @@ -0,0 +1,30 @@ +package Algorithms.string; + +public class CountAndSay { + public String countAndSay(int n) { + if (n == 0) { + return null; + } + + if (n == 1) { + return "1"; + } + + String s = countAndSay(n - 1); + StringBuilder sb = new StringBuilder(); + + int len = s.length(); + int cnt = 0; + for (int i = 0; i < len; i++) { + cnt++; + + if (i == len - 1 || (i < len - 1 && s.charAt(i) != s.charAt(i + 1))) { + sb.append(cnt); + sb.append(s.charAt(i)); + cnt = 0; + } + } + + return sb.toString(); + } +} \ No newline at end of file diff --git a/string/FindLadders.java b/string/FindLadders.java new file mode 100644 index 0000000..c35c946 --- /dev/null +++ b/string/FindLadders.java @@ -0,0 +1,111 @@ +package Algorithms.string; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; + +public class FindLadders { + public static void main(String[] strs) { + Set dict = new HashSet(); + dict.add("hot"); + dict.add("dot"); + dict.add("dog"); + dict.add("lot"); + dict.add("log"); + dict.add("cog"); + + System.out.println(findLadders("hit", "cob", dict)); + } + + public static List> findLadders(String start, String end, Set dict) { + if (start == null || end == null) { + return null; + } + + Queue q = new LinkedList(); + + // 存储每一个单词对应的路径 + HashMap>> map = new HashMap>>(); + + // 标记在某一层找到解 + boolean find = false; + + // store the length of the start string. + int lenStr = start.length(); + + List> list = new ArrayList>(); + + // 唯一的路径 + List path = new ArrayList(); + path.add(start); + list.add(path); + + // 将头节点放入 + map.put(start, list); + q.offer(start); + + while (!q.isEmpty()) { + int size = q.size(); + + HashMap>> mapTmp = new HashMap>>(); + for (int i = 0; i < size; i++) { + // get the current word. + String str = q.poll(); + for (int j = 0; j < lenStr; j++) { + StringBuilder sb = new StringBuilder(str); + for (char c = 'a'; c <= 'z'; c++) { + sb.setCharAt(j, c); + String tmp = sb.toString(); + + // 1. 重复的单词,不需要计算。因为之前一层出现过,再出现只会更长 + // 2. 必须要在字典中出现 + if (map.containsKey(tmp) || (!dict.contains(tmp) && !tmp.equals(end))) { + continue; + } + + // 将前节点的路径提取出来 + List> pre = map.get(str); + + // 从mapTmp中取出节点,或者是新建一个节点 + List> curList = mapTmp.get(tmp); + if (curList == null) { + // Create a new list and add to the end word. + curList = new ArrayList>(); + mapTmp.put(tmp, curList); + + // 将生成的单词放入队列,以便下一次继续变换 + // 放在这里可以避免Q重复加入 + q.offer(tmp); + } + + // 将PRE的path 取出,加上当前节点,并放入curList中 + for(List pathPre: pre) { + List pathNew = new ArrayList(pathPre); + pathNew.add(tmp); + curList.add(pathNew); + } + + if (tmp.equals(end)) { + find = true; + } + } + } + } + + if (find) { + return mapTmp.get(end); + } + + // 把当前层找到的解放在MAP中。 + // 使用2个map的原因是:在当前层中,我们需要把同一个单词的所有的解全部找出来. + map.putAll(mapTmp); + } + + // 返回一个空的结果 + return new ArrayList>(); + } +} \ No newline at end of file diff --git a/string/FindLadders_1218_2014.java b/string/FindLadders_1218_2014.java new file mode 100644 index 0000000..3d968b0 --- /dev/null +++ b/string/FindLadders_1218_2014.java @@ -0,0 +1,95 @@ +package Algorithms.string; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; + +public class FindLadders_1218_2014 { + public static List> findLadders(String start, String end, Set dict) { + List> ret = new ArrayList>(); + if (start == null || end == null || dict == null) { + return ret; + } + + HashMap>> map = new HashMap>>(); + + // Store the map of the current level. + HashMap>> mapTmp = new HashMap>>(); + + Queue q = new LinkedList(); + q.offer(start); + + List> listStart = new ArrayList>(); + + // 唯一的路径 + List path = new ArrayList(); + path.add(start); + listStart.add(path); + + // 将头节点放入 + map.put(start, listStart); + + while (!q.isEmpty()) { + int size = q.size(); + + for (int i = 0; i < size; i++) { + String s = q.poll(); + + int len = s.length(); + for (int j = 0; j < len; j++) { + StringBuilder sb = new StringBuilder(s); + for (char c = 'a'; c <= 'z'; c++) { + // Bug 2: should seperate the setCharAt(j, c) function and the sb.toString() function. + sb.setCharAt(j, c); + String tmp = sb.toString(); + + // 1. 不在字典中,并且不是end. + // 2. 前面的map中已经出现过 + + // Bug 1: map should use containsKey; + if ((!dict.contains(tmp) && !tmp.equals(end)) || map.containsKey(tmp)) { + continue; + } + + // Try to get the pre list. + List> pre = map.get(s); + + // 从mapTmp中取出节点,或者是新建一个节点 + List> curList = mapTmp.get(tmp); + if (curList == null) { + curList = new ArrayList>(); + + // Only offer new string to the queue. + // 将生成的单词放入队列,以便下一次继续变换 + // 放在这里可以避免Q重复加入 + q.offer(tmp); + + // create a new map. + mapTmp.put(tmp, curList); + } + + // 将PRE的path 取出,加上当前节点,并放入curList中 + for (List strList: pre) { + // Should create a new list. + List strListNew = new ArrayList(strList); + strListNew.add(tmp); + curList.add(strListNew); + } + } + } + } + + if (mapTmp.containsKey(end)) { + return mapTmp.get(end); + } + + // add the tmp map into the map. + map.putAll(mapTmp); + } + + return ret; + } +} \ No newline at end of file diff --git a/string/FindSubstring.java b/string/FindSubstring.java new file mode 100644 index 0000000..40641af --- /dev/null +++ b/string/FindSubstring.java @@ -0,0 +1,133 @@ +package Algorithms.string; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class FindSubstring { + public static void main(String[] strs) { + String[] L = {"fooo","barr","wing","ding","wing"}; + + System.out.println(findSubstring("lingmindraboofooowingdingbarrwingmonkeypoundcake", L)); + } + + public static List findSubstring1(String S, String[] L) { + HashMap map = new HashMap(); + HashMap found = new HashMap(); + List ret = new ArrayList(); + + if (S == null || L == null || L.length == 0) { + return ret; + } + + int cntL = 0; + + // put all the strings into the map. + for (String s: L) { + if (map.containsKey(s)) { + map.put(s, map.get(s) + 1); + } else { + map.put(s, 1); + cntL++; + } + } + + int lenL = L[0].length(); + + int cntFound = 0; + + // 注意这里的条件:i < S.length() - lenL * L.length + // 这里很关键,如果长度不够了,不需要再继续查找 + for (int i = 0; i <= S.length() - lenL * L.length; i++) { + // clear the found hashmap. + found.clear(); + cntFound = 0; + + // 一次前进一个L的length. + // 注意j <= S.length() - lenL; 防止越界 + for (int j = i; j <= S.length() - lenL; j += lenL) { + String sub = S.substring(j, j + lenL); + if (map.containsKey(sub)) { + if (found.containsKey(sub)) { + if (found.get(sub) == map.get(sub)) { + // 超过了限制数目 + break; + } + + found.put(sub, found.get(sub) + 1); + } else { + found.put(sub, 1); + } + + if (found.get(sub) == map.get(sub)) { + cntFound++; + } + + // L中所有的字符串都已经找到了。 + if (cntFound == cntL) { + ret.add(i); + } + } else { + // 不符合条件,可以break,i前进到下一个匹配位置 + break; + } + } + } + + return ret; + } + + // SOLUTION 2: + public static List findSubstring(String S, String[] L) { + HashMap map = new HashMap(); + HashMap found; + List ret = new ArrayList(); + + if (S == null || L == null || L.length == 0) { + return ret; + } + + // put all the strings into the map. + for (String s: L) { + if (map.containsKey(s)) { + map.put(s, map.get(s) + 1); + } else { + map.put(s, 1); + } + } + + int lenL = L[0].length(); + + // 注意这里的条件:i < S.length() - lenL * L.length + // 这里很关键,如果长度不够了,不需要再继续查找 + for (int i = 0; i <= S.length() - lenL * L.length; i++) { + // 每一次,都复制之前的hashMap. + found = new HashMap(map); + + // 一次前进一个L的length. + // 注意j <= S.length() - lenL; 防止越界 + for (int j = i; j <= S.length() - lenL; j += lenL) { + String sub = S.substring(j, j + lenL); + if (found.containsKey(sub)) { + // 将找到字符串的计数器减1. + found.put(sub, found.get(sub) - 1); + + // 减到0即可将其移出。否则会产生重复运算,以及我们用MAP为空来判断是否找到所有的单词。 + if (found.get(sub) == 0) { + found.remove(sub); + } + } else { + // 不符合条件,可以break,i前进到下一个匹配位置 + break; + } + + // L中所有的字符串都已经找到了。 + if (found.isEmpty()) { + ret.add(i); + } + } + } + + return ret; + } +} \ No newline at end of file diff --git a/string/FullJustify.java b/string/FullJustify.java new file mode 100644 index 0000000..56d8aa5 --- /dev/null +++ b/string/FullJustify.java @@ -0,0 +1,264 @@ +package Algorithms.string; + +import java.util.ArrayList; +import java.util.List; + +public class FullJustify { + public static void main(String[] strs) { + String[] words = {"Listen","to","many,","speak","to","a","few."}; + int L = 6; + fullJustify(words, L); + } + + // SOLUTION 1: recursion. + public List fullJustify1(String[] words, int L) { + List ret = new ArrayList(); + + if (words == null) { + return ret; + } + + rec(words, L, 0, ret); + return ret; + } + + public static void rec(String[] words, int L, int index, List list) { + int len = words.length; + if (index >= len) { + return; + } + + int LenTmp = L; + + int end = index; + for (int i = index; i < len && words[i].length() <= L; i++) { + L -= words[i].length(); + + // the space follow the word. + L--; + end = i; + } + + // 最后一个空格收回 + L++; + + // Count how many words do we have. + int num = end - index + 1; + + int extraSpace = 0; + int firstExtra = 0; + + // 单词数大于1,才需要分配,否则所有的空格加到最后即可 + if (num > 1) { + extraSpace = L / (num - 1); + // 首单词后多跟的空格 + firstExtra = L % (num - 1); + } + + StringBuilder sb = new StringBuilder(); + for (int i = index; i <= end; i++) { + sb.append(words[i]); + + // The space following every word. + if (i != end) { + sb.append(' '); + } + + // 不是最后一行 + if (end != len - 1) { + // The first words. + if (firstExtra > 0) { + sb.append(' '); + firstExtra--; + } + + // 最后一个单词后面不需要再加空格 + if (i == end) { + break; + } + + // 每个单词后的额外空格 + int cnt = extraSpace; + while (cnt > 0) { + sb.append(' '); + cnt--; + } + } + } + + // 最后一行的尾部的空格 + int tailLen = LenTmp - sb.length(); + while (tailLen > 0) { + sb.append(' '); + tailLen--; + } + + list.add(sb.toString()); + rec(words, LenTmp, end + 1, list); + } + + // SOLUTION 2: iteration. + public List fullJustify2(String[] words, int L) { + List ret = new ArrayList(); + if (words == null) { + return ret; + } + + int len = words.length; + int index = 0; + + while (index < len) { + int LenTmp = L; + + int end = index; + for (int i = index; i < len && words[i].length() <= LenTmp; i++) { + LenTmp -= words[i].length(); + + // the space follow the word. + LenTmp--; + end = i; + } + + // 最后一个空格收回 + LenTmp++; + + // Count how many words do we have. + int num = end - index + 1; + + int extraSpace = 0; + int firstExtra = 0; + + // 单词数大于1,才需要分配,否则所有的空格加到最后即可 + if (num > 1) { + extraSpace = LenTmp / (num - 1); + // 首单词后多跟的空格 + firstExtra = LenTmp % (num - 1); + } + + StringBuilder sb = new StringBuilder(); + for (int i = index; i <= end; i++) { + sb.append(words[i]); + + // The space following every word. + if (i != end) { + sb.append(' '); + } + + // 不是最后一行 + if (end != len - 1) { + // The first words. + if (firstExtra > 0) { + sb.append(' '); + firstExtra--; + } + + // 最后一个单词后面不需要再加空格 + if (i == end) { + break; + } + + // 每个单词后的额外空格 + int cnt = extraSpace; + while (cnt > 0) { + sb.append(' '); + cnt--; + } + } + } + + // 最后一行的尾部的空格 + int tailLen = L - sb.length(); + while (tailLen > 0) { + sb.append(' '); + tailLen--; + } + + ret.add(sb.toString()); + index = end + 1; + } + + return ret; + } + + // SOLUTION 3: iteration2 + public static List fullJustify(String[] words, int L) { + List ret = new ArrayList(); + if (words == null) { + return ret; + } + + int len = words.length; + int index = 0; + + while (index < len) { + int LenTmp = L; + + int end = index; + for (int i = index; i < len && words[i].length() <= LenTmp; i++) { + LenTmp -= words[i].length(); + + // the space follow the word. + LenTmp--; + end = i; + } + + // 最后一个空格收回 + LenTmp++; + + // Count how many words do we have. + int num = end - index + 1; + + int extraSpace = 0; + int firstExtra = 0; + + // 单词数大于1,才需要分配,否则所有的空格加到最后即可 + if (num > 1) { + extraSpace = LenTmp / (num - 1); + // 首单词后多跟的空格 + firstExtra = LenTmp % (num - 1); + } + + StringBuilder sb = new StringBuilder(); + for (int i = index; i <= end; i++) { + sb.append(words[i]); + + int cnt = 0; + + if (i == end) { + break; + } + + // 不是最后一行 + if (end != len - 1) { + // The first words. + if (firstExtra > 0) { + cnt++; + firstExtra--; + } + + // 最后一个单词后面不需要再加空格 + // 每个单词后的额外空格 + cnt += extraSpace; + } + + // 1: 每个单词后本来要加的空格 + appendSpace(sb, cnt + 1); + } + + // 最后一行的尾部的空格,或者是只有一个单词的情况 + appendSpace(sb, L - sb.length()); + + ret.add(sb.toString()); + index = end + 1; + } + + return ret; + } + + public static void appendSpace(StringBuilder sb, int cnt) { + while (cnt > 0) { + sb.append(' '); + cnt--; + } + } +} \ No newline at end of file diff --git a/string/GenerateParenthesis.java b/string/GenerateParenthesis.java new file mode 100644 index 0000000..260a28d --- /dev/null +++ b/string/GenerateParenthesis.java @@ -0,0 +1,38 @@ +package Algorithms.string; + +import java.util.ArrayList; +import java.util.List; + +public class GenerateParenthesis { + public List generateParenthesis(int n) { + List ret = new ArrayList(); + + if (n == 0) { + return ret; + } + + dfs(n, n, new StringBuilder(), ret); + + return ret; + } + + // left : the left Parentheses + // right : the right Parentheses + public void dfs(int left, int right, StringBuilder sb, List ret) { + if (left == 0 && right == 0) { + ret.add(sb.toString()); + return; + } + + // left < right means that we have more ( then we can add ). + if (left < 0 || right < 0 || left > right) { + return; + } + + dfs(left - 1, right, sb.append('('), ret); + sb.deleteCharAt(sb.length() - 1); + + dfs(left, right - 1, sb.append(')'), ret); + sb.deleteCharAt(sb.length() - 1); + } +} \ No newline at end of file diff --git a/string/IntToRoman.java b/string/IntToRoman.java new file mode 100644 index 0000000..f950ac5 --- /dev/null +++ b/string/IntToRoman.java @@ -0,0 +1,23 @@ +package Algorithms.string; + +public class IntToRoman { + public String intToRoman(int num) { + int nums[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; + String[] romans = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; + + StringBuilder sb = new StringBuilder(); + + int i = 0; + // 使用贪心法。尽量拆分数字 + while (i < nums.length) { + if (num >= nums[i]) { + sb.append(romans[i]); + num -= nums[i]; + } else { + i++; + } + } + + return sb.toString(); + } +} \ No newline at end of file diff --git a/string/IsNumber.java b/string/IsNumber.java new file mode 100644 index 0000000..b8c1989 --- /dev/null +++ b/string/IsNumber.java @@ -0,0 +1,54 @@ +package Algorithms.string; + +public class IsNumber { + public boolean isNumber(String s) { + if (s == null) { + return false; + } + + // cut the leading spaces and tail spaces. + String sCut = s.trim(); + + /* + Some examples: + "0" => true + " 0.1 " => true + "abc" => false + "1 a" => false + "2e10" => true + */ + + int len = sCut.length(); + + boolean num = false; + boolean exp = false; + boolean dot = false; + + for (int i = 0; i < len; i++) { + char c = sCut.charAt(i); + if (c == 'e') { + if (!num || exp) { + return false; + } + exp = true; + num = false; // Should be: 2e2 , so there should be number follow "e" + } else if (c <= '9' && c >= '0') { + num = true; + } else if (c == '.') { + if (exp || dot) { // can't be: e0.2 can't be: .. + return false; + } + dot = true; + } else if (c == '+' || c == '-') { + if (i != 0 && sCut.charAt(i - 1) != 'e') { // filter : " 005047e+6", this is true. + return false; + } + } else { + // invalid character. + return false; + } + } + + return num; + } +} \ No newline at end of file diff --git a/string/IsPalindrome.java b/string/IsPalindrome.java new file mode 100644 index 0000000..7ac6cc6 --- /dev/null +++ b/string/IsPalindrome.java @@ -0,0 +1,41 @@ +package Algorithms.string; + +public class IsPalindrome { + public boolean isPalindrome(String s) { + // http://blog.csdn.net/fightforyourdream/article/details/12860445 + if (s == null) { + return false; + } + + int len = s.length(); + + s = s.toLowerCase(); + + int l = 0; + int r = len - 1; + while (l < r) { + if (!isValid(s.charAt(l))) { + l++; + } else if (!isValid(s.charAt(r))) { + r--; + } else if (s.charAt(l) != s.charAt(r)) { + return false; + } else { + l++; + r--; + } + } + + return true; + } + + public boolean isValid(char c) { + return Character.isLetterOrDigit(c); + // if (c <= 'z' && c >= 'a' || c <= 'Z' && c >= 'A' + // || c <= '9' && c >= '0') { + // return true; + // } + + // return false; + } +} diff --git a/string/IsPalindrome_2014_1229.java b/string/IsPalindrome_2014_1229.java new file mode 100644 index 0000000..6222930 --- /dev/null +++ b/string/IsPalindrome_2014_1229.java @@ -0,0 +1,80 @@ +package Algorithms.string; + +public class IsPalindrome_2014_1229 { + /* + SOLUTION 1: Iterator. + */ + public boolean isPalindrome1(String s) { + if (s == null) { + return false; + } + + int len = s.length(); + + int left = 0; + int right = len - 1; + + String sNew = s.toLowerCase(); + + while (left < right) { + // bug 1: forget a ) + while (left < right && !isNumChar(sNew.charAt(left))) { + left++; + } + + while (left < right && !isNumChar(sNew.charAt(right))) { + right--; + } + + if (sNew.charAt(left) != sNew.charAt(right)) { + return false; + } + + left++; + right--; + } + + return true; + } + + public boolean isNumChar(char c) { + if (c <= '9' && c >= '0' || c <= 'z' && c >= 'a' || c <= 'Z' && c >= 'A') { + return true; + } + + return false; + } + + /* + SOLUTION 2: Iterator2. + */ + public boolean isPalindrome(String s) { + if (s == null) { + return false; + } + + int len = s.length(); + + int left = 0; + int right = len - 1; + + String sNew = s.toLowerCase(); + + while (left < right) { + // bug 1: forget a ) + if (!Character.isLetterOrDigit(sNew.charAt(left))) { + left++; + // bug 2: Line 67: error: cannot find symbol: method isLetterOrDigital(char) + } else if (!Character.isLetterOrDigit(sNew.charAt(right))) { + right--; + } else if (sNew.charAt(left) != sNew.charAt(right)) { + return false; + } else { + left++; + right--; + } + } + + return true; + } +} \ No newline at end of file diff --git a/string/LengthOfLastWord.java b/string/LengthOfLastWord.java new file mode 100644 index 0000000..43bc650 --- /dev/null +++ b/string/LengthOfLastWord.java @@ -0,0 +1,51 @@ +package Algorithms.string; + +public class LengthOfLastWord { + public static void main(String[] strs) { + String s = " the book "; + System.out.println(lengthOfLastWord1(s)); + } + + // solution 1 + public static int lengthOfLastWord1(String s) { + if (s == null || s.length() == 0) { + return 0; + } + + /* + 这里有个规则,它乍看之下很古怪,但很少造成问题:Split会保留开头处的空字段,却舍去结尾处的空字段。例如: + + my @fields = split /:/, “:::a:b:c:::”; #得到(“”,“”,“”,“a”,“b”,“c”) + */ + String[] strs = s.split("\\s+"); + + int size = strs.length; + if (size == 0) { + return 0; + } + int len = strs[size - 1].length(); + return len; + } + + // solution 2 + public int lengthOfLastWord(String s) { + if (s == null || s.length() == 0) { + return 0; + } + + // remove the spaces at the end. + String strs = s.trim(); + + int len = strs.length(); + + int ret = 0; + for (int i = len - 1; i >= 0; i--) { + if (strs.charAt(i) == ' ') { + return ret; + } + ret++; + } + + return len; + } +} diff --git a/string/LengthOfLongestSubstring.java b/string/LengthOfLongestSubstring.java new file mode 100644 index 0000000..ae8f44f --- /dev/null +++ b/string/LengthOfLongestSubstring.java @@ -0,0 +1,95 @@ +package Algorithms.string; + +import java.util.HashMap; + +public class LengthOfLongestSubstring { + public int lengthOfLongestSubstring(String s) { + if (s == null) { + return 0; + } + + int len = s.length(); + + // The start of the window. + int start = 0; + int max = 0; + + HashMap map = new HashMap(); + + for (int end = 0; end < len; end++) { + char c = s.charAt(end); + if (map.containsKey(c)) { + if (map.get(c) >= start) { + start = map.get(c) + 1; + } + } + + map.put(c, end); + + int subLen = end - start + 1; + max = Math.max(max, subLen); + } + + return max; + } + + public int lengthOfLongestSubstring1(String s) { + if (s == null) { + return 0; + } + + int max = 0; + HashMap map = new HashMap(); + + int len = s.length(); + int l = 0; + for (int r = 0; r < len; r++) { + char c = s.charAt(r); + + if (map.containsKey(c) && map.get(c) >= l) { + l = map.get(c) + 1; + } + + // replace the last index of the character c. + map.put(c, r); + + // replace the max value. + max = Math.max(max, r - l + 1); + } + + return max; + } + + // SOLUTION 2: use the array. + public int lengthOfLongestSubstring2(String s) { + if (s == null) { + return 0; + } + + int max = 0; + + // suppose there are only ASCII code. + int[] lastIndex = new int[128]; + for (int i = 0; i < 128; i++) { + lastIndex[i] = -1; + } + + int len = s.length(); + int l = 0; + for (int r = 0; r < len; r++) { + char c = s.charAt(r); + + if (lastIndex[c] >= l) { + l = lastIndex[c] + 1; + } + + // replace the last index of the character c. + lastIndex[c] = r; + + // replace the max value. + max = Math.max(max, r - l + 1); + } + + return max; + } +} \ No newline at end of file diff --git a/string/LongestCommonPrefix.java b/string/LongestCommonPrefix.java new file mode 100644 index 0000000..73e0ba1 --- /dev/null +++ b/string/LongestCommonPrefix.java @@ -0,0 +1,31 @@ +package Algorithms.string; + +public class LongestCommonPrefix { + //http://blog.csdn.net/fightforyourdream/article/details/14642079 + public String longestCommonPrefix(String[] strs) { + if (strs == null) { + return null; + } + + if (strs.length == 0) { + return ""; + } + + String s = strs[0]; + int len = s.length(); + + for (int i = 0; i < len; i++) { + char c = s.charAt(i); + + for (int j = 1; j < strs.length; j++) { + if (strs[j].length() <= i || c != strs[j].charAt(i)) { + // The char i is invalid. 因为读到i时退出,所以不应包含i本身。 + return s.substring(0, i); + } + } + } + + // Didn't break, the whole String is valid. + return s; + } +} diff --git a/string/LongestCommonPrefix_1221_2014.java b/string/LongestCommonPrefix_1221_2014.java new file mode 100644 index 0000000..d59c344 --- /dev/null +++ b/string/LongestCommonPrefix_1221_2014.java @@ -0,0 +1,35 @@ +package Algorithms.string; + +public class LongestCommonPrefix_1221_2014 { + //http://blog.csdn.net/fightforyourdream/article/details/14642079 + public String longestCommonPrefix(String[] strs) { + if (strs == null || strs.length == 0) { + // bug 2: should not return null. + return ""; + } + + // Find out the shortest length. + String s0 = strs[0]; + int len = s0.length(); + for (String s: strs) { + len = Math.min(len, s.length()); + } + + // The index of the character which is examing. + // Bug 3: 当不会break的时候,结果是错的 + // Bug 4: forget to add int i = 0; + for (int i = 0; i < len; i++) { + // Bug 1: forget to write charAt(i); + char c = s0.charAt(i); + for (int j = 0; j < strs.length; j++) { + if (strs[j].charAt(i) != c) { + // Bug 5: write substring to substring + return s0.substring(0, i); + } + } + } + + // Never break, means strs[0].0-len is the solution. + return s0.substring(0, len); + } +} \ No newline at end of file diff --git a/string/LongestValidParentheses.java b/string/LongestValidParentheses.java new file mode 100644 index 0000000..8b83fa5 --- /dev/null +++ b/string/LongestValidParentheses.java @@ -0,0 +1,87 @@ +package Algorithms.string; + +import java.util.Stack; + +public class LongestValidParentheses { + public static void main(String[] strs) { + System.out.println(longestValidParentheses("(()()())")); + } + + public static int longestValidParentheses(String s) { + if (s == null) { + return 0; + } + + Stack stk = new Stack(); + int sum = 0; + int tmp = 0; + + int max = 0; + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + if (c == '(') { + stk.push(i); + } else { + if (stk.isEmpty()) { + // 栈中没有'(',出现')', 则必须重置计算 + sum = 0; + continue; + } + + // count the temporary lenght: + // like: (()()() + // tmp = 2. + tmp = i - stk.pop() + 1; + if (stk.isEmpty()) { + // 有一套完整的括号集,可以加到前面的一整套括号集上 + // () (()()) + // 1 2 第二套括号集可以加过来 + sum += tmp; + max = Math.max(sum, max); + } else { + // 也可能是一个未完成的括号集,比如: + // () (()() 在这里 ()() 是一个未完成的括号集,可以独立出来计算,作为 + // 阶段性的结果 + tmp = i - stk.peek(); + max = Math.max(tmp, max); + } + } + } + + return max; + } + public int longestValidParentheses2(String s) { + if (s == null) { + return 0; + } + + int len = s.length(); + Stack stk = new Stack(); + + int sum = 0; + int max = 0; + for (int i = 0; i < len; i++) { + char c = s.charAt(i); + if (c == '(') { + stk.push(i); + } else { + if (stk.isEmpty()) { + // The sequence is cut off. + sum = 0; + } else { + int tmp = i - stk.pop() + 1; + if (stk.isEmpty()) { + sum += tmp; + max = Math.max(max, sum); + } else { + max = Math.max(max, i - stk.peek()); + } + } + } + } + + return max; + } +} \ No newline at end of file diff --git a/string/MinWindow.java b/string/MinWindow.java new file mode 100644 index 0000000..f7741a9 --- /dev/null +++ b/string/MinWindow.java @@ -0,0 +1,146 @@ +package Algorithms.string; + +import java.util.HashMap; + +public class MinWindow { + public static void main(String[] strs) { + System.out.println(minWindow("aa", "aab")); + System.out.println(minWindow1("aa", "aab")); + + int a [] = new int [5] ; + System.out.println("" + a[0]) ; + } + /* + * Use Hashmap to do it. + * */ + public static String minWindow1(String S, String T) { + if (S == null || T == null) { + return null; + } + + // Create a map to record the characters exit time. + HashMap map = new HashMap(); + + int lenS = S.length(); + int lenT = T.length(); + for (int i = 0; i < lenT; i++) { + Integer times = map.get(T.charAt(i)); + if (times == null) { + map.put(T.charAt(i), 1); + } else { + map.put(T.charAt(i), times + 1); + } + } + + int left = 0; + int right = 0; + + int size = 0; + + String ret = ""; + + int minLen = Integer.MAX_VALUE; + + // 注意:这里right 要++ + for (right = 0 ; right < lenS; right++) { + char cRight = S.charAt(right); + if (map.containsKey(cRight)) { + map.put(cRight, map.get(cRight) - 1); + if (map.get(cRight) == 0) { + // 表示某一个字符全部出现了. + size++; + } + } + + // shift the left point to right, until all the dupilcate characters gone. + while (left < lenS) { + char c = S.charAt(left); + // 如果这字符出现的次数刚好,或是不够,是不可以移动Left的 + if (map.get(c) != null && map.get(c) >= 0) { + break; + } + + // 可以删除无关的字符,以及重复的字符 + if (map.get(c) != null) { + map.put(c, map.get(c) + 1); + } + + left++; + } + + int len = right - left + 1; + // 字符都出现了 + if (size == map.size() && len < minLen) { + ret = S.substring(left, right + 1); + minLen = len; + } + } + + return ret; + } + + /* + * Try to do it with Arrays. + * */ + public static String minWindow(String S, String T) { + if (S == null || T == null) { + return null; + } + + // 隐式初始化后,它们默认是0 + // http://developer.51cto.com/art/200906/128274.htm + int[] cntS = new int[128]; + int[] cntT = new int[128]; + + int lenS = S.length(); + int lenT = T.length(); + + // count all the characters in T. + int cntCharT = 0; + for (int i = 0; i < lenT; i++) { + cntT[T.charAt(i)]++; + if (cntT[T.charAt(i)] == 1) { + // 计算T中不同字母的个数 + cntCharT++; + } + } + + // 从左至右扫描 S + int left = 0; // LEFT set to the left and move right. + int cnt = 0; + int minLen = Integer.MAX_VALUE; + + String ret = ""; + for (int i = 0; i < lenS; i++) { + char c = S.charAt(i); + if (cntT[c] != 0) { + cntS[c]++; + //c字母全部出现了 + if (cntS[c] == cntT[c]) { + cnt++; + } + } + + while (cnt == cntCharT) { + // 更新最小长度 + if (i - left + 1 < minLen) { + minLen = i - left + 1; + ret = S.substring(left, i + 1); + } + + // 从左边移除一个字符 + if (cntT[c] != 0) { + cntS[c]--; + } + + // 如果某个字符被减到小于预定值,cnt要减少。 + if (cntS[c] < cntT[c]) { + cnt--; + } + left++; + } + } + + return ret; + } +} \ No newline at end of file diff --git a/string/Multiply.java b/string/Multiply.java new file mode 100644 index 0000000..f973607 --- /dev/null +++ b/string/Multiply.java @@ -0,0 +1,41 @@ +package Algorithms.string; + +public class Multiply { + public static void main(String[] strs) { + multiply("9", "9"); + } + + public static String multiply(String num1, String num2) { + if (num1 == null || num2 == null) { + return null; + } + + int len1 = num1.length(); + int len2 = num2.length(); + + int[] product = new int[len1 + len2]; + + // 计算相应位置的product. + for (int i = 0; i < len1; i++) { + for (int j = 0; j < len2; j++) { + product[i + j] = (num1.charAt(len1 - 1 - i) - '0') * (num2.charAt(len2 - 1 - j) - '0'); + } + } + + StringBuilder ret = new StringBuilder(); + + int carry = 0; + for (int i = 0; i < len1 + len2; i++) { + product[i] = product[i] + carry; + int digit = product[i] % 10; + carry = digit / 10; + ret.insert(0, digit); + } + + while (ret.length() > 1 && ret.charAt(0) == '0') { + ret.deleteCharAt(0); + } + + return ret.toString(); + } +} diff --git a/string/RestoreIpAddresses.java b/string/RestoreIpAddresses.java new file mode 100644 index 0000000..8c144f9 --- /dev/null +++ b/string/RestoreIpAddresses.java @@ -0,0 +1,109 @@ +package Algorithms.string; + +import java.util.ArrayList; +import java.util.List; + +public class RestoreIpAddresses { + public List restoreIpAddresses(String s) { + if (s == null) { + return null; + } + + ArrayList ret = new ArrayList(); + ArrayList path = new ArrayList(); + + dfs(s, 0, path, ret); + + return ret; + } + + public void dfs(String s, int index, ArrayList path, ArrayList ret) { + if (path.size() == 4) { + if (index == s.length()) { + StringBuilder sb = new StringBuilder(); + for (String str: path) { + sb.append(str); + sb.append('.'); + } + + sb.deleteCharAt(sb.length() - 1); + ret.add(sb.toString()); + } + + return; + } + + int len = s.length(); + for (int i = index; i < index + 3 && i < len; i++) { + if (s.charAt(index) == '0' && i > index) { + break; + } + + String pre = s.substring(index, i + 1); + int num = Integer.parseInt(pre); + if (num > 255) { + continue; + } + + path.add(pre); + dfs(s, i + 1, path, ret); + path.remove(path.size() - 1); + } + } + + // 2015.1.1 Redo: + public List restoreIpAddresses2(String s) { + List ret = new ArrayList(); + // Bug 1: not length, but length(). + if (s == null || s.length() < 4 || s.length() > 12) { + return ret; + } + + dfs(s, new ArrayList(), ret, 0); + return ret; + } + + public void dfs(String s, List path, List ret, int index) { + // THE BASE CASE: + int len = s.length(); + if (path.size() == 4) { + // Create a solution. + if (index == len) { + StringBuilder sb = new StringBuilder(); + for (String str: path) { + sb.append(str); + sb.append("."); + } + sb.deleteCharAt(sb.length() - 1); + + // bug 3: forget this statement. + ret.add(sb.toString()); + } + + return; + } + + // 2/ 25 / 255 + // bug 2: i should < len. + for (int i = index; i < index + 3 && i < len; i++) { + String sub = s.substring(index, i + 1); + if (s.charAt(index) == '0' && i != index) { + // only allow 0, not 02, 022 + break; + } + + if (!isValid(sub)) { + continue; + } + + path.add(sub); + dfs(s, path, ret, i + 1); + path.remove(path.size() - 1); + } + } + + public boolean isValid(String s) { + int num = Integer.parseInt(s); + return num >= 0 && num <= 255; + } +} \ No newline at end of file diff --git a/string/ReverseWords.java b/string/ReverseWords.java new file mode 100644 index 0000000..dbbfe6e --- /dev/null +++ b/string/ReverseWords.java @@ -0,0 +1,63 @@ +package Algorithms.string; + +public class ReverseWords { + public static void main(String[] strs) { + reverseWords(" I love cmu "); + } + + /** + * @param s : A string + * @return : A string + */ + public static String reverseWords(String s) { + // write your code + if (s == null) { + return null; + } + + StringBuilder sb = new StringBuilder(); + + // remove the leading and the tail space. + //String sTrim = s.trim(); + String[] strs = s.split("\\s+"); + for (int i = strs.length - 1; i >= 0; i--) { + System.out.println("word:" + strs[i]); + if (strs[i].equals("")) { + continue; + } + + sb.append(strs[i]); + if (i != 0) { + sb.append(" "); + } + } + + return sb.toString(); + } + + /** + * @param s : A string + * @return : A string + */ + public String reverseWords1(String s) { + // write your code + if (s == null) { + return null; + } + + StringBuilder sb = new StringBuilder(); + + // remove the leading and the tail space. + String sTrim = s.trim(); + String strs[] = sTrim.split("\\s+"); + for (int i = strs.length - 1; i >= 0; i--) { + sb.append(strs[i]); + if (i != 0) { + sb.append(" "); + } + } + + return sb.toString(); + } +} + diff --git a/string/RomanToInt.java b/string/RomanToInt.java new file mode 100644 index 0000000..b9190d4 --- /dev/null +++ b/string/RomanToInt.java @@ -0,0 +1,64 @@ +package Algorithms.string; + +public class RomanToInt { + public int romanToInt(String s) { + if (s == null) { + return 0; + } + + int len = s.length(); + int sum = 0; + int pre = 0; + + for (int i = len - 1; i >= 0; i--) { + int cur = romanTable(s.charAt(i)); + + if (i == len - 1) { + // 如果是在尾部,直接加上当前值 + sum += cur; + } else { + // 判定当前值是不是比前一个值要小,如果小,则需要减去它 + if (cur < pre) { + sum -= cur; + } else { + sum += cur; + } + } + pre = cur; + } + + return sum; + } + + public int romanTable(char c) { + int num = 0; + switch(c) { + case 'I': + num = 1; + break; + case 'V': + num = 5; + break; + case 'X': + num = 10; + break; + case 'L': + num = 50; + break; + case 'C': + num = 100; + break; + case 'D': + num = 500; + break; + case 'M': + num = 1000; + break; + default: + num = 0; + break; + } + + return num; + } +} \ No newline at end of file diff --git a/string/SimplifyPath.java b/string/SimplifyPath.java new file mode 100644 index 0000000..61e5862 --- /dev/null +++ b/string/SimplifyPath.java @@ -0,0 +1,49 @@ +package Algorithms.string; + +import java.util.Stack; + +public class SimplifyPath { + public static void main(String[] strs) { + System.out.println(simplifyPath("//home")); + } + + public static String simplifyPath(String path) { + if (path == null || path.length() == 0) { + return null; + } + + /* + path = "/home/", => "/home" --> Split to : 空格 home + path = "/a/./b/../../c/", => "/c" --> splite to: 空格 a . b .. .. c + */ + // 注意 split的输入是一个字符串 + String[] strs = path.split("/"); + + Stack s = new Stack(); + + for (String str: strs) { + if (str.equals("..")) { + // we should pop out a element. + if (!s.isEmpty()) { + s.pop(); + } + // should skip the space and the '.' + } else if (!str.equals(".") && !str.equals("")) { + s.push(str); + } + } + + StringBuilder sb = new StringBuilder(); + while (!s.isEmpty()) { + sb.insert(0, s.pop()); + sb.insert(0, '/'); + } + + // if we get a empty string, should return / + if (sb.length() ==0) { + sb.append('/'); + } + + return sb.toString(); + } +} diff --git a/string/StrStr.java b/string/StrStr.java new file mode 100644 index 0000000..8a12942 --- /dev/null +++ b/string/StrStr.java @@ -0,0 +1,69 @@ +package Algorithms.string; + +import java.util.ArrayList; + +public class StrStr { + public static void main(String[] strs) { + System.out.println(strStr("ppa","pa")); + System.out.println(findPattern("ppa","pax")); + + //System.out.println(findAllStrings("xxisxhis")); + + } + + public static 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; + } + + public static int findPattern(String base, String pattern) { + if (base == null || pattern == null) { + return -1; + } + + int len1 = base.length(); + int len2 = pattern.length(); + + for (int i = 0; i <= len1 - len2; i++) { + int j = 0; + for (; j < len2; j++) { + if (base.charAt(i + j) != pattern.charAt(j)) { + break; + } + + if (j == len2 - 1) { + return i; + } + } + + } + + // did not find pattern. + return -1; + } +} \ No newline at end of file diff --git a/string/isMatch.java b/string/isMatch.java new file mode 100644 index 0000000..0da97fe --- /dev/null +++ b/string/isMatch.java @@ -0,0 +1,62 @@ +package Algorithms.string; + +public class isMatch { + public boolean isMatch(String s, String p) { + if (s == null || p == null) { + return false; + } + + return isMatchRec(s, p, 0, 0); + } + + public boolean isMatchRec(String s, String p, int indexS, int indexP) { + int lenS = s.length(); + int lenP = p.length(); + + // we get to the end of the string. + if (indexP == lenP) { + return indexS == lenS; + } + + // At lease 2 match character left + if (indexP < lenP - 1 && p.charAt(indexP + 1) == '*') { + // match 0; + if (isMatchRec(s, p, indexS, indexP + 2)) { + return true; + } + + // we can match 0 or more. + for (int i = indexS; i < lenS; i++) { + // match once or more. + if (!isMatchChar(s.charAt(i), p.charAt(indexP))) { + return false; + } + + if (isMatchRec(s, p, i + 1, indexP + 2)) { + return true; + } + } + + // if any of them does not match, just return false. + return false; + } + + // match current character and the left string. + return indexS < lenS + && isMatchChar(s.charAt(indexS), p.charAt(indexP)) + && isMatchRec(s, p, indexS + 1, indexP + 1); + } + + public boolean isMatchChar(char s, char p) { + if (p == '*') { + return false; + } + + if (s == p || p == '.') { + return true; + } + + return false; + } + +} \ No newline at end of file diff --git a/string/isMatch_2014_1228.java b/string/isMatch_2014_1228.java new file mode 100644 index 0000000..098d6ae --- /dev/null +++ b/string/isMatch_2014_1228.java @@ -0,0 +1,182 @@ +package Algorithms.string; + +public class isMatch_2014_1228 { + public boolean isMatch1(String s, String p) { + if (s == null || p == null) { + return false; + } + + return dfs(s, p, 0, 0); + } + + public boolean dfs(String s, String p, int indexS, int indexP) { + int lenS = s.length(); + int lenP = p.length(); + + // THE BASE CASE: + if (indexP >= lenP) { + // indexP is out of range. Then the s should also be empty. + return indexS >= lenS; + } + + // The first Case: next node is * + if (indexP != lenP - 1 && p.charAt(indexP + 1) == '*') { + // p can skip 2 node, and the S can skip 0 or more characters. + if (dfs(s, p, indexS, indexP + 2)) { + return true; + } + + for (int i = indexS; i < lenS; i++) { + // the char is not equal. + // bug 2: Line 31: java.lang.StringIndexOutOfBoundsException: String index out of range: -1 + if (!isSame(s.charAt(i), p.charAt(indexP))) { + return false; + } + + if (dfs(s, p, i + 1, indexP + 2)) { + return true; + } + } + + // Not any of them can match. + return false; + } else { + // S should have at least one character left. + if (indexS >= lenS) { + return false; + } + + if (!isSame(s.charAt(indexS), p.charAt(indexP))) { + return false; + } + + // bug 1: forget ';' + return dfs(s, p, indexS + 1, indexP + 1); + } + } + + public boolean isSame(char c, char p) { + return p == '.' || c == p; + } + + // solution2: dfs + memory + public boolean isMatch2(String s, String p) { + if (s == null || p == null) { + return false; + } + + int[][] mem = new int[s.length() + 1][p.length() + 1]; + + // BUG 1: forget to init the memory array. + // BUG 2: the corner is <= + for (int i = 0; i <= s.length(); i++) { + for (int j = 0; j <= p.length(); j++) { + mem[i][j] = -1; + } + } + + return dfsMem(s, p, 0, 0, mem); + } + + public boolean dfsMem(String s, String p, int indexS, int indexP, int[][] mem) { + int lenS = s.length(); + int lenP = p.length(); + + if (mem[indexS][indexP] != -1) { + return mem[indexS][indexP] == 1; + } + + // THE BASE CASE: + if (indexP >= lenP) { + // indexP is out of range. Then the s should also be empty. + mem[indexS][indexP] = indexS >= lenS ? 1: 0; + return indexS >= lenS; + } + + // The first Case: next node is * + if (indexP != lenP - 1 && p.charAt(indexP + 1) == '*') { + // p can skip 2 node, and the S can skip 0 or more characters. + if (dfsMem(s, p, indexS, indexP + 2, mem)) { + mem[indexS][indexP] = 1; + return true; + } + + for (int i = indexS; i < lenS; i++) { + // the char is not equal. + // bug 2: Line 31: java.lang.StringIndexOutOfBoundsException: String index out of range: -1 + if (!isSame(s.charAt(i), p.charAt(indexP))) { + mem[indexS][indexP] = 0; + return false; + } + + if (dfsMem(s, p, i + 1, indexP + 2, mem)) { + mem[indexS][indexP] = 1; + return true; + } + } + + // Not any of them can match. + mem[indexS][indexP] = 0; + return false; + } else { + // S should have at least one character left. + boolean ret = indexS < lenS + && isSame(s.charAt(indexS), p.charAt(indexP)) + && dfsMem(s, p, indexS + 1, indexP + 1, mem); + + mem[indexS][indexP] = ret ? 1: 0; + return ret; + } + } + + // solution4: DP + public boolean isMatch(String s, String p) { + if (s == null || p == null) { + return false; + } + + // bug 2: should use boolean instead of int. + boolean[][] D = new boolean[s.length() + 1][p.length() + 1]; + + // D[i][j]: i, j, the length of String s and String p. + for (int i = 0; i <= s.length(); i++) { + for (int j = 0; j <= p.length(); j++) { + if (j == 0) { + // when p is empth, the s should be empty. + D[i][j] = i == 0; + } else if (p.charAt(j - 1) == '*') { + /* + P has at least one node. + */ + + // The last node in p is '*' + if (j < 2) { + // a error: there should be a character before *. + //return false; + } + + // we can match 0 characters or match more characters. + for (int k = 0; k <= i; k++) { + // BUG 3: severe! Forget to deal with the empty string!! + if (k != 0 && !isSame(s.charAt(i - k), p.charAt(j - 2))) { + D[i][j] = false; + break; + } + + if (D[i - k][j - 2]) { + D[i][j] = true; + break; + } + } + } else { + D[i][j] = i >= 1 + && isSame(s.charAt(i - 1), p.charAt(j - 1)) + && D[i - 1][j - 1]; + } + } + } + + return D[s.length()][p.length()]; + } + +} \ No newline at end of file diff --git a/tree/BuildTree.java b/tree/BuildTree.java new file mode 100644 index 0000000..51fe4a1 --- /dev/null +++ b/tree/BuildTree.java @@ -0,0 +1,60 @@ +package Algorithms.tree; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class BuildTree { + public static void main(String[] strs) { + int[] pre = {1, 2}; + int[] in = {2, 1}; + + buildTree(pre, in); + } + + public static TreeNode buildTree(int[] preorder, int[] inorder) { + // bug 3: consider when length is 0. + if (preorder == null || inorder == null || preorder.length == 0 || preorder.length != inorder.length) { + return null; + } + + // bug 4: end index is length - 1. + return buildTree(preorder, inorder, 0, preorder.length - 1, 0, preorder.length - 1); + } + + public static TreeNode buildTree(int[] preorder, int[] inorder, int preStart, int preEnd, int inStart, int inEnd) { + // base case; + if (preStart > preEnd) { + return null; + } + + int rootVal = preorder[preStart]; + TreeNode root = new TreeNode(rootVal); + + int pos = findTarget(inorder, rootVal, inStart, inEnd); + + // bug 5: left number is pos - instart can't add 1 + int leftNum = pos - inStart; + + root.left = buildTree(preorder, inorder, preStart + 1, preStart + leftNum, inStart, pos - 1); + root.right = buildTree(preorder, inorder, preStart + leftNum + 1, preEnd, pos + 1, inEnd); + + return root; + } + + // bug 1: return type required. + public static int findTarget(int[] A, int target, int start, int end) { + for (int i = start; i <= end; i++) { + if (target == A[i]) { + return i; + } + } + + return -1; + } +} \ No newline at end of file diff --git a/tree/BuildTree2.java b/tree/BuildTree2.java new file mode 100644 index 0000000..4abf538 --- /dev/null +++ b/tree/BuildTree2.java @@ -0,0 +1,44 @@ +package Algorithms.tree; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class BuildTree2 { + public TreeNode buildTree(int[] inorder, int[] postorder) { + if (inorder == null || postorder == null) { + return null; + } + + return dfs(inorder, postorder, 0, inorder.length - 1, 0, postorder.length - 1); + } + + public TreeNode dfs(int[] inorder, int[] postorder, int inL, int inR, int postL, int postR) { + if (inL > inR) { + return null; + } + + // create the root node. + TreeNode root = new TreeNode(postorder[postR]); + + // find the position of the root node in the inorder traversal. + int pos = 0; + for (; pos <= inR; pos++) { + if (inorder[pos] == postorder[postR]) { + break; + } + } + + int leftNum = pos - inL; + + root.left = dfs(inorder, postorder, inL, pos - 1, postL, postL + leftNum - 1); + root.right = dfs(inorder, postorder, pos + 1, inR, postL + leftNum, postR - 1); + + return root; + } +} \ No newline at end of file diff --git a/tree/Connect.java b/tree/Connect.java new file mode 100644 index 0000000..be1b8b5 --- /dev/null +++ b/tree/Connect.java @@ -0,0 +1,78 @@ +package Algorithms.tree; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * Definition for binary tree with next pointer. + * public class TreeLinkNode { + * int val; + * TreeLinkNode left, right, next; + * TreeLinkNode(int x) { val = x; } + * } + */ +public class Connect { + /* + * 使用level traversal来做。 + * */ + public void connect1(TreeLinkNode root) { + if (root == null) { + return; + } + + TreeLinkNode dummy = new TreeLinkNode(0); + Queue q = new LinkedList(); + q.offer(root); + q.offer(dummy); + + while (!q.isEmpty()) { + TreeLinkNode cur = q.poll(); + if (cur == dummy) { + if (!q.isEmpty()) { + q.offer(dummy); + } + continue; + } + + if (q.peek() == dummy) { + cur.next = null; + } else { + cur.next = q.peek(); + } + + if (cur.left != null) { + q.offer(cur.left); + } + + if (cur.right != null) { + q.offer(cur.right); + } + } + } + + /* 试一下 recursion */ + public void connect(TreeLinkNode root) { + if (root == null) { + return; + } + + rec(root); + } + + public void rec(TreeLinkNode root) { + if (root == null) { + return; + } + + if (root.left != null) { + root.left.next = root.right; + } + + if (root.right != null) { + root.right.next = root.next.left; + } + + rec(root.left); + rec(root.right); + } +} diff --git a/tree/Connect2.java b/tree/Connect2.java new file mode 100644 index 0000000..fbc4f93 --- /dev/null +++ b/tree/Connect2.java @@ -0,0 +1,149 @@ +package Algorithms.tree; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * Definition for binary tree with next pointer. + * public class TreeLinkNode { + * int val; + * TreeLinkNode left, right, next; + * TreeLinkNode(int x) { val = x; } + * } + */ +public class Connect2 { + /* + Solution 1: space: O(N), the nodes of the last level. + */ + public void connect1(TreeLinkNode root) { + if (root == null) { + return; + } + + TreeLinkNode dummy = new TreeLinkNode(0); + Queue q = new LinkedList(); + + q.offer(root); + q.offer(dummy); + + while(!q.isEmpty()) { + TreeLinkNode cur = q.poll(); + if (cur == dummy) { + if (!q.isEmpty()) { + q.offer(dummy); + } + continue; + } + + if (q.peek() == dummy) { + cur.next = null; + } else { + cur.next = q.peek(); + } + + if (cur.left != null) { + q.offer(cur.left); + } + + if (cur.right != null) { + q.offer(cur.right); + } + } + } + + /* + Solution 2: recursion with O(h) space. H: the height of the tree. + */ + public void connect2(TreeLinkNode root) { + if (root == null) { + return; + } + + TreeLinkNode cur = root.next; + TreeLinkNode next = null; + // this is very important. should exit after found the next. + while (cur != null && next == null) { + if (cur.left != null) { + next = cur.left; + } else if (cur.right != null) { + next = cur.right; + } else { + cur = cur.next; + } + } + + if (root.right != null) { + root.right.next = next; + next = root.right; + } + + if (root.left != null) { + root.left.next = next; + } + + // The order is very important. We should deal with right first! + connect2(root.right); + connect2(root.left); + } + + /* + Solution 3: iterator with O(1) space. + */ + public void connect(TreeLinkNode root) { + if (root == null) { + return; + } + + connIterator(root); + } + + /* + This is a iterator version. + */ + public void connIterator(TreeLinkNode root) { + TreeLinkNode leftEnd = root; + while (leftEnd != null) { + TreeLinkNode p = leftEnd; + + // Connect all the nodes in the next level together. + while (p != null) { + + // find the + TreeLinkNode next = findLeftEnd(p.next); + + if (p.right != null) { + p.right.next = next; + next = p.right; + } + + if (p.left != null) { + p.left.next = next; + } + + // continue to deal with the next point. + p = p.next; + } + + // Find the left end of the NEXT LEVEL. + leftEnd = findLeftEnd(leftEnd); + } + + } + + // Find out the left end of the next level of Root TreeNode. + public TreeLinkNode findLeftEnd(TreeLinkNode root) { + while (root != null) { + if (root.left != null) { + return root.left; + } + + if (root.right != null) { + return root.right; + } + + root = root.next; + } + + return null; + } +} diff --git a/tree/Connect2_2014_1229.java b/tree/Connect2_2014_1229.java new file mode 100644 index 0000000..24207c1 --- /dev/null +++ b/tree/Connect2_2014_1229.java @@ -0,0 +1,92 @@ +package Algorithms.tree; + +/** + * Definition for binary tree with next pointer. + * public class TreeLinkNode { + * int val; + * TreeLinkNode left, right, next; + * TreeLinkNode(int x) { val = x; } + * } + */ +public class Connect2_2014_1229 { + // SOLUTION 1: Iteration + public void connect1(TreeLinkNode root) { + if (root == null) { + return; + } + + TreeLinkNode leftEnd = root; + + // Bug 1: don't need " && leftEnd.left != null" + while (leftEnd != null) { + TreeLinkNode cur = leftEnd; + + TreeLinkNode dummy = new TreeLinkNode(0); + TreeLinkNode pre = dummy; + while (cur != null) { + if (cur.left != null) { + pre.next = cur.left; + pre = cur.left; + } + + if (cur.right != null) { + pre.next = cur.right; + pre = cur.right; + } + + cur = cur.next; + } + leftEnd = dummy.next; + } + } + + // SOLUTION 2: REC + public void connect(TreeLinkNode root) { + if (root == null) { + return; + } + + TreeLinkNode dummy = new TreeLinkNode(0); + TreeLinkNode pre = dummy; + + if (root.left != null) { + pre.next = root.left; + pre = root.left; + } + + if (root.right != null) { + pre.right = root.right; + pre = root.right; + } + + if (root.left == null && root.right == null) { + return; + } + + // Try to find the next node; + TreeLinkNode cur = root.next; + TreeLinkNode next = null; + while (cur != null) { + if (cur.left != null) { + next = cur.left; + break; + } else if (cur.right != null) { + next = cur.right; + break; + } else { + cur = cur.next; + } + } + + pre.next = next; + + if (root.right != null && (root.right.left != null || root.right.right != null)) { + connect(root.right); + } + + if (root.left != null && (root.left.left != null || root.left.right != null)) { + connect(root.left); + } + + } +} \ No newline at end of file diff --git a/tree/Connect_2014_1229.java b/tree/Connect_2014_1229.java new file mode 100644 index 0000000..ef1e75e --- /dev/null +++ b/tree/Connect_2014_1229.java @@ -0,0 +1,110 @@ +package Algorithms.tree; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * Definition for binary tree with next pointer. + * public class TreeLinkNode { + * int val; + * TreeLinkNode left, right, next; + * TreeLinkNode(int x) { val = x; } + * } + */ +public class Connect_2014_1229 { + /* + 1. Iterator. + */ + public void connect1(TreeLinkNode root) { + if (root == null) { + return; + } + + Queue q = new LinkedList(); + q.offer(root); + + while (!q.isEmpty()) { + int size = q.size(); + + for (int i = 0; i < size; i++) { + TreeLinkNode cur = q.poll(); + + // ERROR 2: forget to determine if root don't have left and right. + if (cur.left == null) { + return; + } + + cur.left.next = cur.right; + cur.right.next = cur.next == null ? null : cur.next.left; + // bug 1: should put the offer inside the for loop + q.offer(cur.left); + q.offer(cur.right); + } + } + } + + /* + 2. Iterator. More simple version. + */ + public void connect2(TreeLinkNode root) { + if (root == null) { + return; + } + + Queue q = new LinkedList(); + q.offer(root); + + while (!q.isEmpty()) { + int size = q.size(); + + for (int i = 0; i < size; i++) { + TreeLinkNode cur = q.poll(); + + // bug 1: should judge the size! + cur.next = (i == size - 1) ? null: q.peek(); + + if (cur.left != null) { + q.offer(cur.left); + q.offer(cur.right); + } + } + } + } + + /* + 3. A recursion version. + */ + public void connect3(TreeLinkNode root) { + if (root == null || root.left == null) { + return; + } + + root.left.next = root.right; + root.right.next = root.next == null ? null: root.next.left; + + connect(root.left); + connect(root.right); + } + + /* + 4. Another constant iterator version. + */ + public void connect(TreeLinkNode root) { + if (root == null) { + return; + } + + TreeLinkNode leftEnd = root; + while (leftEnd != null && leftEnd.left != null) { + TreeLinkNode cur = leftEnd; + while (cur != null) { + cur.left.next = cur.right; + cur.right.next = cur.next == null ? null: cur.next.left; + + cur = cur.next; + } + + leftEnd = leftEnd.left; + } + } +} \ No newline at end of file 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; + } +} 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; + } + } +} diff --git a/tree/IsBalanced.java b/tree/IsBalanced.java new file mode 100644 index 0000000..8fe4ec5 --- /dev/null +++ b/tree/IsBalanced.java @@ -0,0 +1,66 @@ +package Algorithms.tree; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class IsBalanced { + // Solution 1: + public boolean isBalanced1(TreeNode root) { + return dfs(root).isBalanced; + } + + // bug 1: inner class is like: "public class ReturnType {", no () + public class ReturnType { + boolean isBalanced; + int depth; + + ReturnType(int depth, boolean isBalanced) { + this.depth = depth; + this.isBalanced = isBalanced; + } + } + + public ReturnType dfs(TreeNode root) { + ReturnType ret = new ReturnType(0, true); + + if (root == null) { + return ret; + } + + ReturnType left = dfs(root.left); + ReturnType right = dfs(root.right); + + ret.isBalanced = left.isBalanced + && right.isBalanced + && Math.abs(left.depth - right.depth) <= 1; + + // bug 2: remember to add 1( the root depth ) + ret.depth = Math.max(left.depth, right.depth) + 1; + + return ret; + } + + // Solution 2: + public boolean isBalanced(TreeNode root) { + if (root == null) { + return true; + } + + return isBalanced(root.left) && isBalanced(root.right) + && Math.abs(getDepth(root.left) - getDepth(root.right)) <= 1; + } + + public int getDepth(TreeNode root) { + if (root == null) { + return 0; + } + + return Math.max(getDepth(root.left), getDepth(root.right)) + 1; + } +} \ No newline at end of file diff --git a/tree/IsSameTree1.java b/tree/IsSameTree1.java new file mode 100644 index 0000000..7aad317 --- /dev/null +++ b/tree/IsSameTree1.java @@ -0,0 +1,74 @@ +package Algorithms.tree; + +import java.util.Stack; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class IsSameTree1 { + // solution 1: + public boolean isSameTree1(TreeNode p, TreeNode q) { + if (p == null && q == null) { + return true; + } + + if (p == null || q == null) { + return false; + } + + return p.val == q.val && + isSameTree(p.left, q.left) && + isSameTree(p.right, q.right); + } + + // Solution 2: + public boolean isSameTree(TreeNode p, TreeNode q) { + if (p == null && q == null) { + return true; + } + + if (p == null || q == null) { + return false; + } + + Stack s1 = new Stack(); + Stack s2 = new Stack(); + + s1.push(p); + s2.push(q); + + while (!s1.isEmpty() && !s2.isEmpty()) { + TreeNode cur1 = s1.pop(); + TreeNode cur2 = s2.pop(); + + // 弹出的节点的值必须相等 + if (cur1.val != cur2.val) { + return false; + } + + // tree1的right节点,tree2的right节点,可以同时不为空,也可以同时为空,否则返回false. + if (cur1.left != null && cur2.left != null) { + s1.push(cur1.left); + s2.push(cur2.left); + } else if (!(cur1.left == null && cur2.left == null)) { + return false; + } + + // tree1的左节点,tree2的left节点,可以同时不为空,也可以同时为空,否则返回false. + if (cur1.right != null && cur2.right != null) { + s1.push(cur1.right); + s2.push(cur2.right); + } else if (!(cur1.right == null && cur2.right == null)) { + return false; + } + } + + return true; + } +} \ No newline at end of file diff --git a/tree/IsSymmetric.java b/tree/IsSymmetric.java new file mode 100644 index 0000000..c9413dc --- /dev/null +++ b/tree/IsSymmetric.java @@ -0,0 +1,80 @@ +package Algorithms.tree; + +import java.util.Stack; + +public class IsSymmetric { + /** + * Definition for binary tree public class TreeNode { int val; TreeNode + * left; TreeNode right; TreeNode(int x) { val = x; } } + */ + // solution 1: + public boolean isSymmetric(TreeNode root) { + if (root == null) { + return true; + } + + return isSymmetricTree(root.left, root.right); + } + + /* + * 判断两个树是否互相镜像 (1) 根必须同时为空,或是同时不为空 + * + * 如果根不为空: (1).根的值一样 (2).r1的左树是r2的右树的镜像 (3).r1的右树是r2的左树的镜像 + */ + public boolean isSymmetricTree1(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) { + return true; + } + + if (root1 == null || root2 == null) { + return false; + } + + return root1.val == root2.val + && isSymmetricTree(root1.left, root2.right) + && isSymmetricTree(root1.right, root2.left); + } + + // solution 2: + public boolean isSymmetricTree(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) { + return true; + } + + if (root1 == null || root2 == null) { + return false; + } + + Stack s1 = new Stack(); + Stack s2 = new Stack(); + + // 一定记得初始化 + s1.push(root1); + s2.push(root2); + + while (!s1.isEmpty() && !s2.isEmpty()) { + TreeNode cur1 = s1.pop(); + TreeNode cur2 = s2.pop(); + + if (cur1.val != cur2.val) { + return 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; + } + + 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; + } +} \ No newline at end of file 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/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 diff --git a/tree/IsValidBST_1221_2014.java b/tree/IsValidBST_1221_2014.java new file mode 100644 index 0000000..b9678d7 --- /dev/null +++ b/tree/IsValidBST_1221_2014.java @@ -0,0 +1,178 @@ +package Algorithms.tree; + +import java.util.Stack; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class IsValidBST_1221_2014 { + public boolean isValidBST1(TreeNode root) { + // Just use the inOrder traversal to solve the problem. + if (root == null) { + return true; + } + + Stack s = new Stack(); + TreeNode cur = root; + + TreeNode pre = null; + + while(true) { + // Push all the left node into the stack. + while (cur != null) { + s.push(cur); + cur = cur.left; + } + + if (s.isEmpty()) { + break; + } + + // No left node, just deal with the current node. + cur = s.pop(); + + if (pre != null && pre.val >= cur.val) { + return false; + } + + pre = cur; + + // Go to the right node. + cur = cur.right; + } + + return true; + } + + /* + SOLUTION 2: Use the recursive version. + REF: http://blog.csdn.net/fightforyourdream/article/details/14444883 + */ + public boolean isValidBST2(TreeNode root) { + // Just use the inOrder traversal to solve the problem. + if (root == null) { + return true; + } + + return dfs(root, Long.MIN_VALUE, Long.MAX_VALUE); + } + + public boolean dfs(TreeNode root, long low, long up) { + if (root == null) { + return true; + } + + if (root.val >= up || root.val <= low) { + return false; + } + + return dfs(root.left, low, root.val) + && dfs(root.right, root.val, up); + } + + /* + SOLUTION 3: Use the recursive version2. + */ + public boolean isValidBST3(TreeNode root) { + // Just use the inOrder traversal to solve the problem. + if (root == null) { + return true; + } + + return dfs(root, Long.MIN_VALUE, Long.MAX_VALUE); + } + + public class ReturnType { + int min; + int max; + boolean isBST; + public ReturnType (int min, int max, boolean isBST) { + this.min = min; + this.max = max; + this.isBST = isBST; + } + } + + // BST: + // 1. Left tree is BST; + // 2. Right tree is BST; + // 3. root value is bigger than the max value of left tree and + // smaller than the min value of the right tree. + public ReturnType dfs(TreeNode root) { + ReturnType ret = new ReturnType(Integer.MAX_VALUE, Integer.MIN_VALUE, true); + if (root == null) { + return ret; + } + + ReturnType left = dfs(root.left); + ReturnType right = dfs(root.right); + + // determine the left tree and the right tree; + if (!left.isBST || !right.isBST) { + ret.isBST = false; + return ret; + } + + // 判断Root.left != null是有必要的,如果root.val是MAX 或是MIN value,判断会失误 + if (root.left != null && root.val <= left.max) { + ret.isBST = false; + return ret; + } + + if (root.right != null && root.val >= right.min) { + ret.isBST = false; + return ret; + } + + return new ReturnType(Math.min(root.val, left.min), Math.max(root.val, right.max), true); + } + + /* + SOLUTION 4: Use the recursive version3. + */ + TreeNode pre = null; + + public boolean isValidBST(TreeNode root) { + // Just use the inOrder traversal to solve the problem. + return dfs4(root); + } + + public boolean dfs4(TreeNode root) { + if (root == null) { + return true; + } + + // Judge the left tree. + if (!dfs4(root.left)) { + return false; + } + + // judge the sequence. + if (pre != null && root.val <= pre.val) { + return false; + } + pre = root; + + // Judge the right tree. + if (!dfs4(root.right)) { + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/LCA.java b/tree/LCA.java similarity index 99% rename from LCA.java rename to tree/LCA.java index 199a7eb..9119361 100644 --- a/LCA.java +++ b/tree/LCA.java @@ -1,4 +1,5 @@ -package Algorithms; +package Algorithms.tree; + /** @@ -87,7 +88,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/tree/LCA_Demo.java b/tree/LCA_Demo.java new file mode 100644 index 0000000..cb802e8 --- /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. 求二叉树中两个节点的最低公共祖先节点: + * (1) LAC 求解最小公共祖先, 使用list来存储path. + * 算法复杂度是:O(n), 这里遍历2次,加一次对最高为H的list的遍历. 并且有O(h)的空间复杂度。 + * (2) LCARec 递归算法 . + * 算法复杂度是:O(n) + * (3) LCABstRec 递归求解BST树. + * 算法复杂度: O(logN). + */ + +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 diff --git a/tree/LargestCommonSubtrees.java b/tree/LargestCommonSubtrees.java new file mode 100644 index 0000000..2011e94 --- /dev/null +++ b/tree/LargestCommonSubtrees.java @@ -0,0 +1,171 @@ +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; + } + + // 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) { + maxNum = num; + 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 diff --git a/tree/LevelOrder.java b/tree/LevelOrder.java new file mode 100644 index 0000000..cd17a8a --- /dev/null +++ b/tree/LevelOrder.java @@ -0,0 +1,48 @@ +package Algorithms.tree; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class LevelOrder { + public List> levelOrder(TreeNode root) { + List> ret = new ArrayList>(); + if (root == null) { + return ret; + } + + Queue q = new LinkedList(); + q.offer(root); + + while (!q.isEmpty()) { + int size = q.size(); + List list = new ArrayList(); + for (int i = 0; i < size; i++) { + TreeNode cur = q.poll(); + list.add(cur.val); + + if (cur.left != null) { + q.offer(cur.left); + } + + if (cur.right != null) { + q.offer(cur.right); + } + } + + ret.add(list); + } + + return ret; + } +} \ No newline at end of file diff --git a/Level_Order.java b/tree/Level_Order.java similarity index 98% rename from Level_Order.java rename to tree/Level_Order.java index 1ea79b4..b73e3e9 100644 --- a/Level_Order.java +++ b/tree/Level_Order.java @@ -1,4 +1,4 @@ -package Algorithms; +package Algorithms.tree; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Queue; diff --git a/tree/MaxPathSum.java b/tree/MaxPathSum.java new file mode 100644 index 0000000..a9711ee --- /dev/null +++ b/tree/MaxPathSum.java @@ -0,0 +1,61 @@ +package Algorithms.tree; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class MaxPathSum { + public static void main(String[] strs) { + TreeNode root = new TreeNode(2); + TreeNode left = new TreeNode(-1); + + root.left = left; + + System.out.println(maxPathSum(root)); + } + + public static class ReturnType { + int maxSingle; + int max; + ReturnType (int maxSingle, int max) { + this.max = max; + this.maxSingle = maxSingle; + } + } + + public static int maxPathSum(TreeNode root) { + return dfs(root).max; + } + + public static ReturnType dfs(TreeNode root) { + ReturnType ret = new ReturnType(Integer.MIN_VALUE, Integer.MIN_VALUE); + if (root == null) { + return ret; + } + + ReturnType left = dfs(root.left); + ReturnType right = dfs(root.right); + + int cross = root.val; + + // if any of the path of left and right is below 0, don't add it. + cross += Math.max(0, left.maxSingle); + cross += Math.max(0, right.maxSingle); + + int maxSingle = root.val + Math.max(left.maxSingle, right.maxSingle); + + // may left.maxSingle and right.maxSingle are below 0 + maxSingle = Math.max(maxSingle, root.val); + + ret.maxSingle = maxSingle; + ret.max = Math.max(right.max, left.max); + ret.max = Math.max(ret.max, cross); + + return ret; + } +} \ No newline at end of file diff --git a/tree/MinDepth.java b/tree/MinDepth.java new file mode 100644 index 0000000..ad0afbc --- /dev/null +++ b/tree/MinDepth.java @@ -0,0 +1,112 @@ +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; + } + + // 如果root是叶子节点,直接就可以退出咯。 + if (root.left == null && root.right == null) { + return 1; + } + + // root不是叶子节点,输出左右子树的最小值,再加上root本身 + return 1 + Math.min(minDepthHelp(root.left), minDepthHelp(root.right)); + } + + /* + * 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 diff --git a/tree/MinDepth_1218_2014.java b/tree/MinDepth_1218_2014.java new file mode 100644 index 0000000..7ab0cfa --- /dev/null +++ b/tree/MinDepth_1218_2014.java @@ -0,0 +1,88 @@ +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_1218_2014 { + // SOLUTION 1: + public int minDepth1(TreeNode root) { + /* + 主页君认为,在这应该是属于未定义行为,这里我们定义为MAX会比较好,因为 + null就是取不到任何节点,没有path,不应该将最小值定为0. + */ + if (root == null) { + return 0; + } + + return dfs(root); + } + + /* + * The Recursion Version: + * 这种递归解法更简单。因为在本层递归中不需要考虑左右子树是否为NULL的情况。因为我们直接 + 把 null 设置为返回一个最大值,这样的话,如果出现空子树,它不会影响最小值。但是如果左 + 右均为空,则应返回1(即是仅仅为根节点) + + 而且这种做法更加合理。 因为如果是空树,应该是无法到达才是。这时就应该将值设置为最大。 + * */ + public int dfs(TreeNode root) { + if (root == null) { + return Integer.MAX_VALUE; + } + + // The base case: the root is a leaf. + if (root.left == null && root.right == null) { + return 1; + } + + return Math.min(dfs(root.left), dfs(root.right)) + 1; + } + + // SOLUTION 2: + // Level Traversal: + public int minDepth(TreeNode root) { + /* + 主页君认为,在这应该是属于未定义行为,这里我们定义为MAX会比较好,因为 + null就是取不到任何节点,没有path,不应该将最小值定为0. + */ + if (root == null) { + return 0; + } + + int level = 0; + + Queue q = new LinkedList(); + q.offer(root); + + while (!q.isEmpty()) { + int size = q.size(); + level++; + for (int i = 0; i < size; i++) { + TreeNode cur = q.poll(); + + if (cur.left == null && cur.right == null) { + return level; + } + + if (cur.left != null) { + q.offer(cur.left); + } + + if (cur.right != null) { + q.offer(cur.right); + } + } + } + + return 0; + } +} \ No newline at end of file diff --git a/tree/NumTrees.java b/tree/NumTrees.java new file mode 100644 index 0000000..4f45028 --- /dev/null +++ b/tree/NumTrees.java @@ -0,0 +1,44 @@ +package Algorithms.tree; + +public class NumTrees { + 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: + // 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]; + } + + 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 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 diff --git a/tree/PostorderTraversal.java b/tree/PostorderTraversal.java new file mode 100644 index 0000000..f1a9d09 --- /dev/null +++ b/tree/PostorderTraversal.java @@ -0,0 +1,65 @@ +package Algorithms.tree; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class PostorderTraversal { + public List postorderTraversal1(TreeNode root) { + List ret = new ArrayList(); + dfs(root, ret); + return ret; + } + + // Solution 1: rec + public void dfs(TreeNode root, List ret) { + if (root == null) { + return; + } + + dfs(root.left, ret); + dfs(root.right, ret); + ret.add(root.val); + } + + // Solution 2: iterator + public List postorderTraversal(TreeNode root) { + List ret = new ArrayList(); + if (root == null) { + return ret; + } + + Stack s = new Stack(); + Stack out = new Stack(); + + s.push(root); + + while (!s.isEmpty()) { + TreeNode cur = s.pop(); + out.push(cur.val); + + if (cur.left != null) { + s.push(cur.left); + } + + if (cur.right != null) { + s.push(cur.right); + } + } + + while (!out.isEmpty()) { + ret.add(out.pop()); + } + + return ret; + } +} \ No newline at end of file diff --git a/tree/PreorderTraversal.java b/tree/PreorderTraversal.java new file mode 100644 index 0000000..9dabc72 --- /dev/null +++ b/tree/PreorderTraversal.java @@ -0,0 +1,60 @@ +package Algorithms.tree; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class PreorderTraversal { + // sol1: + public List preorderTraversal1(TreeNode root) { + List ret = new ArrayList(); + + rec(root, ret); + return ret; + } + + public void rec(TreeNode root, List ret) { + if (root == null) { + return; + } + + ret.add(root.val); + rec(root.left, ret); + rec(root.right, ret); + } + + public List preorderTraversal(TreeNode root) { + List ret = new ArrayList(); + + if (root == null) { + return ret; + } + + Stack s = new Stack(); + s.push(root); + + while (!s.isEmpty()) { + TreeNode cur = s.pop(); + ret.add(cur.val); + + if (cur.right != null) { + s.push(cur.right); + } + + if (cur.left != null) { + s.push(cur.left); + } + } + + return ret; + } +} \ No newline at end of file diff --git a/tree/RecoverTree.java b/tree/RecoverTree.java new file mode 100644 index 0000000..ebe39a7 --- /dev/null +++ b/tree/RecoverTree.java @@ -0,0 +1,140 @@ +package Algorithms.tree; + +import java.util.ArrayList; +import java.util.Stack; + +/** + * 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 static class Function { + int reference; + + Function () { + super(); + } + } + + public static void main(String[] strs) { + ArrayList list = new ArrayList(); + + list.add("string"); + list.add(1); + + Function fuc = new Function(); + + + } + + 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); + } + + public void recoverTree1(TreeNode root) { + if (root == null) { + return; + } + + TreeNode node1 = null; + TreeNode node2 = null; + + TreeNode pre = null; + + Stack s = new Stack(); + TreeNode cur = root; + + while (true) { + while (cur != null) { + s.push(cur); + cur = cur.left; + } + + if (s.isEmpty()) { + break; + } + + TreeNode node = s.pop(); + + if (pre != null) { + // invalid order + if (pre.val > node.val) { + if (node1 == null) { + node1 = pre; + node2 = node; + } else { + node2 = node; + } + } + } + + pre = node; + + cur = node.right; + } + + int tmp = node1.val; + node1.val = node2.val; + node2.val = tmp; + + return; + } +} diff --git a/tree/SortedArrayToBST.java b/tree/SortedArrayToBST.java new file mode 100644 index 0000000..4f1c1de --- /dev/null +++ b/tree/SortedArrayToBST.java @@ -0,0 +1,38 @@ +package Algorithms.tree; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class SortedArrayToBST { + public TreeNode sortedArrayToBST(int[] num) { + if (num == null || num.length == 0) { + return null; + } + + return sortedArrayToBST(num, 0, num.length - 1); + } + + public TreeNode sortedArrayToBST(int[] num, int left, int right) { + // The base case: + if (left > right) { + return null; + } + + int mid = left + (right - left) / 2; + TreeNode root = new TreeNode(num[mid]); + + TreeNode leftNode = sortedArrayToBST(num, left, mid - 1); + TreeNode rightNode = sortedArrayToBST(num, mid + 1, right); + + root.left = leftNode; + root.right = rightNode; + + return root; + } +} \ No newline at end of file diff --git a/tree/SumNumbers.java b/tree/SumNumbers.java new file mode 100644 index 0000000..66b20de --- /dev/null +++ b/tree/SumNumbers.java @@ -0,0 +1,67 @@ +package Algorithms.tree; + +import java.util.ArrayList; + +/* + * + * Sum Root to Leaf Numbers Total Accepted: 23940 Total Submissions: 80436 My Submissions +Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number. + +An example is the root-to-leaf path 1->2->3 which represents the number 123. + +Find the total sum of all root-to-leaf numbers. + +For example, + + 1 + / \ + 2 3 +The root-to-leaf path 1->2 represents the number 12. +The root-to-leaf path 1->3 represents the number 13. + +Return the sum = 12 + 13 = 25. + * */ + +public class SumNumbers { + public int sumNumbers(TreeNode root) { + if (root == null) { + return 0; + } + + ArrayList ret = new ArrayList(); + + // 存储从根节点到当前节点的路径上的数字 + ArrayList path = new ArrayList(); + + dfs(root, path, ret); + int sum = 0; + for (int n: ret) { + sum += n; + } + + return sum; + } + + public void dfs(TreeNode root, ArrayList path, ArrayList ret) { + if (root == null) { + return; + } + + path.add(root.val); + + if (root.left == null && root.right == null) { + int num = 0; + for (int n: path) { + num = num * 10 + n; + } + ret.add(num); + } else { + // 向左右子树递归 + dfs(root.left, path, ret); + dfs(root.right, path, ret); + } + + // 一定要记得回溯,也就是说递归不能修改Path本身,否则以上向左右子树分别递归时 path就会被改。 + path.remove(path.size() - 1); + } +} diff --git a/tree/SumNumbers_1208_2014.java b/tree/SumNumbers_1208_2014.java new file mode 100644 index 0000000..08a1038 --- /dev/null +++ b/tree/SumNumbers_1208_2014.java @@ -0,0 +1,29 @@ +package Algorithms.tree; + +/** + * Definition for binary tree + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class SumNumbers_1208_2014 { + public int sumNumbers(TreeNode root) { + return dfs(root, 0); + } + + public int dfs(TreeNode root, int pre) { + if (root == null) { + return 0; + } + + int cur = pre * 10 + root.val; + if (root.left == null && root.right == null) { + return cur; + } + + return dfs(root.left, cur) + dfs(root.right, cur); + } +} \ No newline at end of file diff --git a/tree/TreeDemo.java b/tree/TreeDemo.java new file mode 100644 index 0000000..8931467 --- /dev/null +++ b/tree/TreeDemo.java @@ -0,0 +1,1560 @@ +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; + + +/** + * 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(递归解法) + * 5. 将二叉查找树变为有序的双向链表: convertBST2DLLRec, convertBST2DLL + * 6. 求二叉树第K层的节点个数:getNodeNumKthLevelRec, getNodeNumKthLevel + * 7. 求二叉树中叶子节点的个数:getNodeNumLeafRec, getNodeNumLeaf + * 8. 判断两棵二叉树是否相同的树:isSameRec, isSame + * 9. 判断二叉树是不是平衡二叉树:isAVLRec + * 10. 求二叉树的镜像(破坏和不破坏原来的树两种情况): + * mirrorRec, mirrorCopyRec + * mirror, mirrorCopy + * 10.1 判断两个树是否互相镜像:isMirrorRec isMirror + * 11. 求二叉树中两个节点的最低公共祖先节点: + * LAC 求解最小公共祖先, 使用list来存储path. + * LCABstRec 递归求解BST树. + * LCARec 递归算法 . + * 12. 求二叉树中节点的最大距离:getMaxDistanceRec + * 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec + * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec + * 15. 找出二叉树中最长连续子串(即全部往左的连续节点,或是全部往右的连续节点)findLongest + */ + +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 + / + 0 +*/ + /* + 1 + / \ + 2 3 + / \ \ + 4 5 6 +*/ +// 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; + + 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); + + 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; + t2.right = t5; + t3.left = t6; + t3.right = t7; + + t4.left = t8; + //t4.right = t9; + t5.right = t9; + + + // test distance +// t5.right = t8; +// t8.right = t9; +// t9.right = t10; +// t10.right = t11; + + /* + 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(getMaxDistanceRec(t1)); + + //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(null)); +// 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)); + + // test the rebuildBinaryTreeRec. + //test_rebuildBinaryTreeRec(); + + System.out.println(isCompleteBinaryTreeRec(t1)); + System.out.println(isCompleteBinaryTree(t1)); + } + + 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{ + 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 -1; + } + + 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 = -1; + 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; + } + +/* + * * 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); + } + + /* + * 7. getNodeNumLeafRec 把左子树和右子树的叶子节点加在一起即可 + * */ + 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); + } + + /* 7. getNodeNumLeaf + * 随便使用一种遍历方法都可以,比如,中序遍历。 + * inorderTraversal,判断是不是叶子节点。 + * */ + public static int getNodeNumLeaf(TreeNode root) { + if (root == null) { + return 0; + } + + 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 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. 求二叉树中两个节点的最低公共祖先节点: + * 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; + } + + /* + * * 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 + * 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; + } + + // 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. + // So we just create the root node here. + TreeNode root = new TreeNode(preOrder.get(0)); + + 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 + * 进行level traversal, 一旦遇到一个节点的左节点为空,后面的节点的子节点都必须为空。而且不应该有下一行,其实就是队列中所有的 + * 元素都不应该再有子元素。 + * */ + + public static boolean isCompleteBinaryTree(TreeNode root) { + if (root == null) { + return false; + } + + TreeNode dummyNode = new TreeNode(0); + Queue 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; + } + + /* + * 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; + } + + /* + * 15. findLongest + * 第一种解法: + * 返回左边最长,右边最长,及左子树最长,右子树最长。 + * */ + 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 diff --git a/tree/TreeDemo2.java b/tree/TreeDemo2.java new file mode 100644 index 0000000..954bdaa --- /dev/null +++ b/tree/TreeDemo2.java @@ -0,0 +1,1560 @@ +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; + + +/** + * 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(递归解法) + * 5. 将二叉查找树变为有序的双向链表: convertBST2DLLRec, convertBST2DLL + * 6. 求二叉树第K层的节点个数:getNodeNumKthLevelRec, getNodeNumKthLevel + * 7. 求二叉树中叶子节点的个数:getNodeNumLeafRec, getNodeNumLeaf + * 8. 判断两棵二叉树是否相同的树:isSameRec, isSame + * 9. 判断二叉树是不是平衡二叉树:isAVLRec + * 10. 求二叉树的镜像(破坏和不破坏原来的树两种情况): + * mirrorRec, mirrorCopyRec + * mirror, mirrorCopy + * 10.1 判断两个树是否互相镜像:isMirrorRec isMirror + * 11. 求二叉树中两个节点的最低公共祖先节点: + * LAC 求解最小公共祖先, 使用list来存储path. + * LCABstRec 递归求解BST树. + * LCARec 递归算法 . + * 12. 求二叉树中节点的最大距离:getMaxDistanceRec + * 13. 由前序遍历序列和中序遍历序列重建二叉树:rebuildBinaryTreeRec + * 14. 判断二叉树是不是完全二叉树:isCompleteBinaryTree, isCompleteBinaryTreeRec + * 15. 找出二叉树中最长连续子串(即全部往左的连续节点,或是全部往右的连续节点)findLongest + */ + +public class TreeDemo2 { + /* + 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 + / + 0 +*/ + /* + 1 + / \ + 2 3 + / \ \ + 4 5 6 +*/ +// 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; + + 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); + + 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; + t2.right = t5; + t3.left = t6; + t3.right = t7; + + t4.left = t8; + //t4.right = t9; + t5.right = t9; + + + // test distance +// t5.right = t8; +// t8.right = t9; +// t9.right = t10; +// t10.right = t11; + + /* + 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(getMaxDistanceRec(t1)); + + //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(null)); +// 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)); + + // test the rebuildBinaryTreeRec. + //test_rebuildBinaryTreeRec(); + + System.out.println(isCompleteBinaryTreeRec(t1)); + System.out.println(isCompleteBinaryTree(t1)); + } + + 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{ + 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 -1; + } + + 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 = -1; + 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; + } + +/* + * * 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); + } + + /* + * 7. getNodeNumLeafRec 把左子树和右子树的叶子节点加在一起即可 + * */ + 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); + } + + /* 7. getNodeNumLeaf + * 随便使用一种遍历方法都可以,比如,中序遍历。 + * inorderTraversal,判断是不是叶子节点。 + * */ + public static int getNodeNumLeaf(TreeNode root) { + if (root == null) { + return 0; + } + + 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 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. 求二叉树中两个节点的最低公共祖先节点: + * 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; + } + + /* + * * 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 + * 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; + } + + // 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. + // So we just create the root node here. + TreeNode root = new TreeNode(preOrder.get(0)); + + 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 + * 进行level traversal, 一旦遇到一个节点的左节点为空,后面的节点的子节点都必须为空。而且不应该有下一行,其实就是队列中所有的 + * 元素都不应该再有子元素。 + * */ + + public static boolean isCompleteBinaryTree(TreeNode root) { + if (root == null) { + return false; + } + + TreeNode dummyNode = new TreeNode(0); + Queue 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; + } + + /* + * 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; + } + + /* + * 15. findLongest + * 第一种解法: + * 返回左边最长,右边最长,及左子树最长,右子树最长。 + * */ + 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 diff --git a/tree/TreeLinkNode.java b/tree/TreeLinkNode.java new file mode 100644 index 0000000..ab63f36 --- /dev/null +++ b/tree/TreeLinkNode.java @@ -0,0 +1,8 @@ +package Algorithms.tree; +public class TreeLinkNode { + int val; + public TreeLinkNode left; + public TreeLinkNode right; + public TreeLinkNode next; + public TreeLinkNode(int x) { val = x; } +} \ No newline at end of file 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; diff --git a/tree/hasPathSum.java b/tree/hasPathSum.java new file mode 100644 index 0000000..b722c4a --- /dev/null +++ b/tree/hasPathSum.java @@ -0,0 +1,35 @@ +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); + } + + // Solution 2 + public boolean hasPathSum2(TreeNode root, int sum) { + if (root == null) { + return false; + } + + if (root.left == null && root.right == null && root.val == sum) { + return true; + } + + sum -= root.val; + + return hasPathSum2(root.left, sum) || hasPathSum2(root.right, sum); + } +} diff --git a/tree/readme.md b/tree/readme.md new file mode 100644 index 0000000..b9bbb9f --- /dev/null +++ b/tree/readme.md @@ -0,0 +1,29 @@ +Tree +================== + +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.[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 diff --git a/tree/sortedListToBST.java b/tree/sortedListToBST.java new file mode 100644 index 0000000..35eea52 --- /dev/null +++ b/tree/sortedListToBST.java @@ -0,0 +1,106 @@ +package Algorithms.tree; + +import Algorithms.algorithm.others.ListNode; + +/** + * 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 sortedListToBST { + 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; + } +} diff --git a/twoPoints/MaxArea.java b/twoPoints/MaxArea.java new file mode 100644 index 0000000..96d9a27 --- /dev/null +++ b/twoPoints/MaxArea.java @@ -0,0 +1,29 @@ +package Algorithms.twoPoints; + +public class MaxArea { + public int maxArea(int[] height) { + if (height == null) { + return 0; + } + + int left = 0; + int right = height.length - 1; + int maxArea = 0; + + while (left < right) { + int h = Math.min(height[left], height[right]); + int area = h * (right - left); + maxArea = Math.max(maxArea, area); + + if (height[left] < height[right]) { + // 如果左边界比较低,尝试向右寻找更高的边界 + left++; + } else { + // 如果右边界比较低,尝试向左寻找更高的边界 + right--; + } + } + + return maxArea; + } +} \ No newline at end of file