classSolution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { // if root.val == q.val or p.val then no need to traverse if (root == null || root.val == q.val || root.val == p.val) { return root; }
// if both q's and p's val are less than root.val then search the left side if (root.val > q.val && root.val > p.val) { return lowestCommonAncestor(root.left, p, q); }
// if both q's and p's val are larger than root.val then search the right side if (root.val < q.val && root.val < p.val) { return lowestCommonAncestor(root.right, p, q); }
// else it means that the two nodes are in both sides, no matter q is in left && // p in the right or the reversed situation, just return root return root;
classSolution { public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) { return root; } List<Integer> list = newLinkedList<>();
// if root is the node to delete if (root.val == key) {
// if right branch is null then return left if (root.left != null && root.right == null) { return root.left; }
// if left branch is null then return right if (root.left == null && root.right != null) { return root.right; }
// if no children just return null if (root.left == null && root.right == null) { returnnull; }
// else: it means that both child nodes exist // find the leftmost child of root's right branch TreeNodenode= root.right; while (node.left != null) { node = node.left; } node.left = root.left; return root.right;
}else { if (root.val > key) { // we maintain that deleteNode returns the new node after deletion root.left = deleteNode(root.left, key); }else { root.right = deleteNode(root.right, key); } } return root; } }
publicvoidgetMD(TreeNode root) { if (root == null) { return; }
// left getMD(root.left);
// root if (prev != null) {
// actually, no need to use abs, as this is a BST, // the value of the node behind should be larger than its former element // int gap = Math.abs(root.val - prev.val); // int gap = root.val - prev.val; // if (gap < minGap) { // minGap = gap;; // }
// Step 2: update the ans list if necessary if (tempCount == highestFrequence) { ans.add(cur.val); }elseif (tempCount > highestFrequence) { // note here, if higher frequence exists, then drop all the current cached res highestFrequence = tempCount; ans.clear(); ans.add(cur.val); }
// as a root node of any sub-tree, is my left branch and my right branck both // do not contain the target nodes, then I would definitely not be the LCA if(left == null && right == null) { returnnull; // similarly, if both my sub-tree contain the target, then because we // are backtracking, myself must be the LCA }elseif (left != null && right != null) { return root;
// if left does not contain target nodes, then the ans must be in the rightside }elseif (left == null && right != null) { return right; }else { // the same with the leftside return left; } } }
classSolution { public List<List<Integer>> pathSum(TreeNode root, int targetSum) { List<List<Integer>> ans = newLinkedList<>(); preorder(ans, newLinkedList<>(), root, targetSum); return ans; }
privatevoidpreorder(List<List<Integer>> ans, List<Integer> path, TreeNode node, int targetSum){ // exitrance if (node == null) { return; }
// add the val of the node into path path.add(node.val);
// if this is a leaf node and its val is equals to target, record this path if (node.val == targetSum && node.left == null && node.right == null) { // note here, we cannot directly add path list to the ans, as it is just // a temp container and would be changed during next track List<Integer> validPath = newLinkedList<>(); validPath.addAll(path); ans.add(validPath); }
// if there are children nodes, recursivelly call this func if (node.left != null) { preorder(ans, path, node.left, targetSum - node.val); // backtrack path.remove(path.size() - 1); }
public TreeNode buildmyThree(int[] preorder, int preBeginIndex, int preEndIndex, int[] inorder, int inBeginIndex, int inEndIndex) { // when [preBeginIndex, preEndIndex) has no element, return null; if (preBeginIndex >= preEndIndex) { returnnull; }
// left branch // the key here is how to make sure the next range of preorder array and inorder array // deal with the inorder array first, as we know where to devide it into two partitions intdevideInorderIndex=0; for (inti=0; i < inorder.length; i++) { if (inorder[i] == rootValue) { devideInorderIndex = i; break; } }
// culculate the leftTreeSize to handle the preOrder array starting Index and size intleftTreeSize= devideInorderIndex - inBeginIndex;
private TreeNode buildmyTree(int[] inorder, int inStartIndex, int inEndIndex, int[]postorder, int postStartIndex, int postEndIndex) { // if there is no elements in [inStartIndex, inEndIndex) then return if (inStartIndex >= inEndIndex) { returnnull; }
// the last element in postorder is the root of the whole tree introotValue= postorder[postEndIndex - 1];
TreeNoderoot=newTreeNode(rootValue);
// find the index of rootValue in inorder array to divide the inOrder array into two partitions
introotValueIndexAtInOrder=0; for (inti=0; i < inorder.length; i++) { if (inorder[i] == rootValue) { rootValueIndexAtInOrder = i; break; } }
// the next step is recursively call this function to get the left node and right node root.left = buildmyTree( inorder, inStartIndex, rootValueIndexAtInOrder, postorder, postStartIndex, postStartIndex + leftPostOrderArraySize);
// if there is child node, recursively call this func if (node.left != null) { traversal(node.left, path, ans); // note here, we need to BACKTRACK the path list after we checked this path path.remove(path.size() - 1); }
if (node == null) { return0; } else { // to some extent, this is post-order, LRD traversal return Math.max(postorder(node.left), postorder(node.right)) + 1; }
publicintcountNodes(TreeNode root) { if (root == null) { return0; }
TreeNodeleft= root.left; intleftDepth=0; while (left != null) { left = left.left; leftDepth++; }
TreeNoderight= root.right; intrightDepth=0; while (right != null) { right = right.right; rightDepth++; }
// if it is a full binary tree, easy culculation if (leftDepth == rightDepth) { return (2 << leftDepth) - 1; }else { return countNodes(root.left) + countNodes(root.right) + 1; }
classSolution { public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> ans = newLinkedList();
if (root != null) { recursiveLevelOrder(0, ans, root); }
return ans; } // an int variable 'level' is needed to record which level a node is privatevoidrecursiveLevelOrder(int level, List<List<Integer>> ans, TreeNode node) { if (node == null) { return; }
// if the list which would record this node has not been created, new one and record if (ans.size() <= level) { List<Integer> list = newLinkedList<>(); list.add(node.val); ans.add(list); }else{ ans.get(level).add(node.val); }
// actually, no need to check if left or right is null if (node.left != null) { recursiveLevelOrder(level + 1 , ans, node.left); }
if (node.right != null) { recursiveLevelOrder(level + 1, ans, node.right); }
privatevoidpreorder( List<Integer> ans, TreeNode next) {
// as this is pre-order scan // no matter whether this node has children or not // add its value in the ans first TreeNodenode= next; ans.add(node.val);
// if there is no child, just return if ( node.left == null && node.right == null) { return; // else let's call this method recursively on its children }else{ if(node.left != null) { preorder(ans, node.left); } if(node.right != null) { preorder(ans, node.right); } } } }
// in-order classSolution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> ans = newLinkedList<>();
if (root != null){ inorder(ans, root); }
return ans; }
privatevoidinorder(List<Integer> ans, TreeNode next) { TreeNodenode= next; if (node.left == null){ ans.add(node.val);
// post order left right root, reverse to root, right, left in stack // see what? root, right, left, similar to pre-order but get child nodes swapped // thus, it is easy to think how about let's slightly change the code for pre-order stack.push(node); while (!stack.isEmpty()) { ans.add(node.val);
if (node.left != null) { stack.push(node.left); }
if (node.right != null) { stack.push(node.right); }
node = stack.pop(); }
// now we get the values but in root right left, we need to reverse the ans list for (inti=0, j = ans.size() - 1, temp = 0; i < j; i++, j--) { temp = ans.get(i); ans.set(i, ans.get(j)); ans.set(j, temp); }
// if the slide window rule out our head element // then pop it, else pop nothing, as we do not cache // them actaully publicvoidpoll(int val) { if ( val == deque.peek()) { deque.poll(); } }
// for every new added element, try to add them into the queue // if they are less then any elements, just add it at the last // else delete those less than it, as they are meanningless now
publicvoidadd(int val) { // note here, we need to remain the same large element within the queue // if here we use val >= deque.last, we would rule out the same large element while (!deque.isEmpty() && val > deque.peekLast()) { deque.removeLast(); } deque.addLast(val); }
// since we maintain such a queue that the head element is always our // maximum value in this window publicintpeek() { return deque.peek(); }
classSolution { publicint[] topKFrequent(int[] nums, int k) {
// step 1 : count the frequence of each element Map<Integer, Integer> map = newHashMap<>(); for (inti=0; i < nums.length; i++) { if (map.containsKey(nums[i])){ map.put(nums[i], map.get(nums[i]) + 1); }else { map.put(nums[i], 1); } }
// step 2 : sort the frequences List<Map.Entry<Integer, Integer>> list = newArrayList<>(map.entrySet()); // can use lambda expression to simplify the declaration of the comparator // list.sort((o1,o2)-> (- o1.getValue().compareTo(o2.getValue()))); list.sort(newComparator<Map.Entry<Integer, Integer>>() { @Override publicintcompare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2){ // the defult order is natrual order i.e. increasing order return -o1.getValue().compareTo(o2.getValue()); } });
// steo 3 : output the ans int[] ans = newint[k]; for (inti=0; i < k; i++) { ans[i] = list.get(i).getKey(); }
// step 1 : count the frequence of each element Map<Integer, Integer> map = newHashMap<>(); for (inti=0; i < nums.length; i++) { map.put(nums[i], map.getOrDefault(nums[i], 0) + 1); }
// step 2 : sort the frequences PriorityQueue<int[]> pq = newPriorityQueue<>((pair1,pair2)->pair1[1]-pair2[1]); for (Map.entry<Integer, Integer> entry : map.entrySet()) { if (pq.size() < k) { pq.add(newint[]{entry.getKey(), entry.getValue()}); }else { if (entry.getValue() > pq.peek()[1]){ pq.poll(); pq.add(entry); } } }
// steo 3 : output the ans int[] ans = newint[k]; for (inti= k - 1; i >= 0; i--) { ans[i] = pq.poll()[0]; }
for (inti=0; i < s.length(); i++) { charc1= s.charAt(i); // if this char is left side, push it into stack if (c1 == '(' || c1 == '[' || c1 == '{') { stack.push(c1); }else {
// if stack is empty and a right side char comes // return false if (stack.isEmpty()) { returnfalse; }
// else let's check if there is a pair charc2= stack.pop(); if ( c1 == ')' && c2 == '(' || c1 == ']' && c2 == '[' || c1 == '}' && c2 == '{') { continue; }else { returnfalse; } } } // if after checking, there is no chars left in the stack // it means that they are all pairs return stack.isEmpty();
classSolution { public String removeDuplicates(String s) {
char[] chars = s.toCharArray(); Stack<Character> stack = newStack<>(); // full scan the whole string for (char c : chars) { // if stack is not empty, pop the top element // compare if it is the same with the pointed one // if not push them back if (!stack.empty()) { charc2= stack.pop(); if (c2 != c){ stack.push(c2); stack.push(c); } }else { stack.push(c); } } // pop the left elements if (!stack.isEmpty()){ intsize= stack.size(); char[] ans = newchar[size]; while (size > 0) { ans[--size] = stack.pop(); }