104. Maximum Depth of Binary Treenode
找到二叉樹的最大深度。git
public class Solution {
public int maxDepth(TreeNode root) { if (root == null) { return 0; } int l = maxDepth(root.left) + 1; int r = maxDepth(root.right) + 1; return l > r ? l : r; } }
111. Minimum Depth of Binary Tree數組
找到二叉樹的最小深度ide
思路:與最大深度不一樣的地方在於,若一個節點只有左節點或者右節點的其中之一的節點,則該節點並不爲完整路徑的葉節點,必定要找到葉節點才能判斷最小路徑函數
public class Solution {
public int minDepth(TreeNode root) { if (root == null) { return 0; } if (root.left == null) { return minDepth(root.right) + 1; } if (root.right == null) { return minDepth(root.left) + 1; } return Math.min(minDepth(root.left), minDepth(root.right)) + 1; } }
112. Path Sumpost
給定一個樹和一個整數,決定是否該樹有從跟節點到葉節點的一條路徑上的值的和等於給定的這個整數ui
思路:前序遍歷,若沒有左右子節點的話,判斷當前根節點是否等於sum,若不等於,sum減去當前根節點的值,繼續向下遍歷。this
public class Solution {
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)); } }
113. Path Sum IIspa
給定一個樹和一個整數,找到全部從根節點到葉節點的路徑上的值的和等於給的這個整數,要返回下面這種。指針
[ [5,4,11,2], [5,8,4,5] ]
思路:與上一題不一樣之處在於,上一題是判斷存不存在,該題要找到全部符合的路徑,兩個list是必不可少。內層list來存儲符合的路徑。而後遍歷到葉節點符合條件,就將對應的一條路徑添加到外層list中,這裏有兩個關鍵點,前序遍歷是必不可少,問題是遍歷的過程當中若是訪問到某一葉節點,但這條路徑不符合。那麼內層list須要一個一個remove掉當前元素,即便該路徑符合,爲了尋找新的符合條件路徑,也須要remove掉當前的值。因此在遍歷的最後要remove掉當前節點的值。
易錯的地方:由於innerlist是處於一直增刪的狀態。因此肯定了某一完整的符合條件的路徑後,應新建一個temp的list來存儲對應的innerlist,但不能直接把引用=innerlist,這樣二者的地址會同樣。因此方法是將innerlist的值複製到temp中,因此應該用 addAll方法來處理。
public class Solution {
List<List<Integer>> list = new ArrayList<>(); List<Integer> innerlist = new ArrayList<>(); public List<List<Integer>> pathSum(TreeNode root, int sum) { if (root == null) { return list; } innerlist.add(root.val); hasPathSum(root, sum - root.val); return list; } public void hasPathSum(TreeNode root, int sum) { if (root.left == null && root.right == null && sum == 0) { List<Integer> temp = new ArrayList<>(); temp.addAll(innerlist); list.add(temp); } if (root.left != null) { innerlist.add(root.left.val); hasPathSum(root.left, sum - root.left.val); innerlist.remove(innerlist.size() - 1); } if (root.right != null) { innerlist.add(root.right.val); hasPathSum(root.right, sum - root.right.val); innerlist.remove(innerlist.size() - 1); } } }
437. Path Sum III
給定一個樹和一個整數,找到全部從任意節點到任意節點的路徑上的值的和等於給的這個整數,但必定是從上到下的邏輯順序。返回共有多少條路徑。
思路:與前兩題不同的地方在於 不是從根節點開始了,而是從任意節點開始到下面節點路徑和爲該值便可。很典型的動態規劃的問題。先考慮跟節點去往下遍歷,記錄從根節點開始的符合狀況,接着從根節點的左右子節點開始遍歷。
public class Solution {
public int pathSum(TreeNode root, int sum) { if (root == null) { return 0; } return dfs(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum); } public int dfs(TreeNode root, int sum) { int res = 0; if (root == null) { return 0; } if (root.val == sum) { ++res; } res += dfs(root.left, sum - root.val); res += dfs(root.right, sum - root.val); return res; } }
102. Binary Tree Level Order Traversal 待修改,減小空間複雜度
給定一個二叉樹,從左到右,一層一層返回遍歷的值。相似下面這種
3 / \ 9 20 / \ 15 7
return its level order traversal as:
[ [3], [9,20], [15,7] ]
思路:利用兩個雙端隊列linkedlist去存儲當前遍歷的層以及下一層要遍歷的元素,經過remove將隊列中的節點一個一個處理。
public class Solution { public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> list = new ArrayList<List<Integer>>(); ArrayList<Integer> nodeValue = new ArrayList<Integer>(); if (root == null){ return list; } LinkedList<TreeNode> current = new LinkedList<TreeNode>(); LinkedList<TreeNode> next = new LinkedList<TreeNode>(); current.add(root); while (!current.isEmpty()) { TreeNode node = current.remove(); if (node.left != null) { next.add(node.left); } if (node.right != null) { next.add(node.right); } nodeValue.add(node.val); if (current.isEmpty()) { current = next; next = new LinkedList<TreeNode>(); list.add(nodeValue); nodeValue = new ArrayList<Integer>(); } } return list; } }
107. Binary Tree Level Order Traversal II 待修改,減小空間複雜度
與上題不一樣之處在於要倒序輸出,返回以下這種
[ [15,7], [9,20], [3] ]
思路:最後對上一題的list進行reverse便可。
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ public class Solution { public List<List<Integer>> levelOrderBottom(TreeNode root) { List<List<Integer>> list = new ArrayList<List<Integer>>(); List<Integer> nodeValue = new ArrayList<Integer>(); if (root == null){ return list; } LinkedList<TreeNode> current = new LinkedList<TreeNode>(); LinkedList<TreeNode> next = new LinkedList<TreeNode>(); current.add(root); while (!current.isEmpty()){ TreeNode node = current.remove(); if (node.left != null){ next.add(node.left); } if (node.right != null){ next.add(node.right); } nodeValue.add(node.val); if (current.isEmpty()){ current = next; next = new LinkedList<TreeNode>(); list.add(nodeValue); nodeValue = new ArrayList<Integer>(); } } Collections.reverse(list);return reverseList; } }
103. Binary Tree Zigzag Level Order Traversal
給定一個二叉樹,返回它的zigzag型的遍歷形式
For example:
Given binary tree [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
return its zigzag level order traversal as:
[
[3],
[20,9],
[15,7]
]
思路:利用linkedlist是一個雙端隊列,也能夠當棧來使用的特性輸出。
public class Zigzag_Traversal { public List<List<Integer>> zigzagLevelOrder(TreeNode root) { List<List<Integer>> list = new ArrayList<>(); List<Integer> nodeValues = new ArrayList<>(); if (root == null){ return list; } int i = 0; LinkedList<TreeNode> current = new LinkedList<>(); LinkedList<TreeNode> next = new LinkedList<>(); current.add(root); while (!current.isEmpty()) { TreeNode node = current.removeLast(); nodeValues.add(node.val); if (i % 2 == 0){ if (node.left != null){ next.add(node.left); } if (node.right != null){ next.add(node.right); } } if (i % 2 == 1){ if (node.right != null){ next.add(node.right); } if (node.left != null){ next.add(node.left); } } if (current.isEmpty()){ i++; list.add(nodeValues); current = next; next = new LinkedList<TreeNode>(); nodeValues = new ArrayList<Integer>(); } } return list; } }
100. Same Tree
給兩個二叉樹,判斷這個兩個二叉樹是否是相同的,若是他們結構一致,且節點值相同,則爲相同
思路:該題不難,遍歷對應的節點值是否相等便可。
public class Solution { public boolean isSameTree(TreeNode p, TreeNode q) { if (p == null && q == null) { return true; } if (p == null || q == null) { return false; } if (p.val != q.val) { return false; } return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); } }
101. Symmetric Tree
給定一個樹,判斷該樹是否是對稱的結構
For example, this binary tree [1,2,2,3,4,4,3]
is symmetric:
1 / \ 2 2 / \ / \ 3 4 4 3
But the following [1,2,2,null,3,null,3]
is not:
1 / \ 2 2 \ \ 3 3
思路:對稱必定是在同一層中,最左邊節點等於最右邊節點,其次第二個值等於倒數第二個值,依次到中間。
易錯點,容易單純判斷某一節點的左右子節點是否相等。這並非對陳數的定義。因此應該判斷左子節點的左子節點與右子節點的右子節點是否相等,以及左子節點的右子節點與右子節點的左子節點是否相等。
public class Solution { public boolean isSymmetric(TreeNode root) { if (root == null) { return true; } return isSymmetric(root, root); } public boolean isSymmetric(TreeNode p, TreeNode q) { if (p == null && q == null) { return true; } if (p == null || q == null) { return false; } if (p.val != q.val) { return false; } return isSymmetric(p.left, q.right) && isSymmetric(p.right, q.left); } }
110. Balanced Binary Tree
給定一個樹,判斷該樹是否高度平衡,高度平衡指的是某節點的兩個子樹高度差不能大於1
思路:遞歸遍歷整個樹,判斷每一個節點的左子節點的高度與右子節點的高度差是否大於1便可。
public class Solution { public boolean isBalanced(TreeNode root) { if (root == null) { return true; } int l = depth(root.left); int r = depth(root.right); if (Math.abs(l - r) > 1) { return false; } return isBalanced(root.left) && isBalanced(root.right); } public int depth(TreeNode root) { if (root == null) { return 0; } int l = depth(root.left) + 1; int r = depth(root.right) + 1; return l > r ? l:r; } }
226. Invert Binary Tree
翻轉一個二叉樹,相似以下這種
4 / \ 2 7 / \ / \ 1 3 6 9
to
4 / \ 7 2 / \ / \ 9 6 3 1
思路:該題不難,能夠先翻轉左右子節點,而後再翻轉每一個子節點的左右子節點。遞歸處理。
public class Solution { public TreeNode invertTree(TreeNode root) { if (root == null) { return null; } TreeNode node = root.left; root.left = root.right; root.right = node; inverTree(root.left); inverTree(root.right); return root; } }
257. Binary Tree Paths
返回他的從根到葉的全部路徑以下:
1
/ \
2 3
\
5
All root-to-leaf paths are:
["1->2->5", "1->3"]
思路:該題不難,遞歸去訪問是否存在子節點便可。
public class Solution { List<String> list = new ArrayList<String>(); public List<String> binaryTreePaths(TreeNode root) { if (root == null) { return list; } path(root, String.valueOf(root.val)); return list; } public void path(TreeNode root, String paths) { if (root.left == null && root.right == null) { list.add(paths); } if (root.left != null) { path(root.left, paths + "->" + root.left.val); } if (root.right != null) { path(root.right, paths + "->" + root.right.val); } } }
235. Lowest Common Ancestor of a Binary Search Tree
給定一個二叉搜索樹,找到在這個樹中任意兩個節點的公共父節點
_______6______
/ \
___2__ ___8__
/ \ / \
0 _4 7 9
/ \
3 5
For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. Another example is LCA of nodes 2 and 4 is 2
思路:鑑於這是一個二叉搜索樹,那麼給定的兩個節點若一個大於根節點,一個小於根節點,那麼根節點即爲她們的公共父節點,若兩個節點都小於根節點,則在左子節點方向遍歷。反之,在右子節點方向遍歷。
若不是二叉搜索樹呢?這個時候就不能單純憑藉以上條件來判斷,咱們分別遍歷樹,記錄找到對應的這兩個節點的路徑,經過比較兩個節點的路徑,最後一個相同的節點路徑即爲公共父節點,
第一種解法(適用於bst)
public class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){ if (root == null || p == null || q == null){ return null; } if (p.val < root.val && q.val < root.val) { return lowestCommonAncestor(root.left, p, q); } if (p.val > root.val && q.val > root.val) { return lowestCommonAncestor(root.right, p, q); } else { return root; } } }
第二種解法(通用)
public class Solution { public TreeNode lowestCommonAncestor(TreeNode root,TreeNode p,TreeNode q){ if (root == null || p == null || q == null){ return null; } List<TreeNode> pathp = new ArrayList<>(); List<TreeNode> pathq = new ArrayList<>(); pathp.add(root); pathq.add(root); getPath(root, p, pathp); getPath(root, q, pathq); TreeNode lca = null; for (int i = 0;i < pathq.size() && i < pathp.size();i++){ if (pathp.get(i) == pathq.get(i)){ lca = pathp.get(i); } } return lca; } public boolean getPath(TreeNode root, TreeNode n, List<TreeNode> path){ if (root == n){ return true; } if (root.left != null){ path.add(root.left); if(getPath(root.left,n,path)) return true; path.remove(path.size() - 1); } if (root.right != null){ path.add(root.right); if (getPath(root.right, n, path)) return true; path.remove(path.size() - 1); } return false; } }
404. Sum of Left Leaves
找到該樹中全部左子樹葉子的和
3
/ \
9 20
/ \
15 7 Return 24.
思路:該題不難就是遍歷尋找,找到左子節點後,判斷左子節點是不是葉節點便可。
public class Solution { int sum=0; public int sumOfLeftLeaves(TreeNode root) { if(root== null) { return 0; } if(root.left!=null) { if(root.left.left==null&&root.left.right==null) { sum+=root.left.val; } } sumOfLeftLeaves(root.left); sumOfLeftLeaves(root.right); return sum; } }
270:Closest Binary Search Tree Value
給定一個非空的二叉搜索樹,和一個目標值(浮點型),找到該樹中最接近該值的那個節點的值。該樹中只有一個知足條件的值。
思路:從根節點遍歷,找到與該目標值的差值保存,若目標值小於當前根節點的值,則向左遍歷,反之向右遍歷
public class Solution { public int closetValue(TreeNode root, double target){ double min = Double.MAX_VALUE; int closet = root.val; while (root != null){ if (Math.abs(root.val - target) < min){ min = Math.abs(root.val - target); closet = root.val; } if (target < root.val){ root = root.left; } if (target > root.val){ root = root.right; } else { return root.val; } } return closet; } }
236. Lowest Common Ancestor of a Binary Tree
給定一個二叉樹,和兩個節點,找到這兩個節點的父節點。
思路:相似235題。不一樣在於這個就不是二叉搜索樹了。因此找路徑便可。(注意兩個地方:不是bst的話 數值有可能會重複。所以判斷的時候要用tree類型判斷,而不能用val判斷,另外搜尋某個node的時候,利用if+遞歸來判斷是否找到)
public class Solution { public TreeNode lowestCommonAncestor(TreeNode root,TreeNode p,TreeNode q){ if (root == null || p == null || q == null){ return null; } List<TreeNode> pathp = new ArrayList<>(); List<TreeNode> pathq = new ArrayList<>(); pathp.add(root); pathq.add(root); getPath(root, p, pathp); getPath(root, q, pathq); TreeNode lca = null; for (int i = 0;i < pathq.size() && i < pathp.size();i++){ if (pathp.get(i) == pathq.get(i)){ lca = pathp.get(i); } } return lca; } public boolean getPath(TreeNode root, TreeNode n, List<TreeNode> path){ if (root == n){ return true; } if (root.left != null){ path.add(root.left); if(getPath(root.left,n,path)) return true; path.remove(path.size() - 1); } if (root.right != null){ path.add(root.right); if (getPath(root.right, n, path)) return true; path.remove(path.size() - 1); } return false; } }
230. Kth Smallest Element in a BST
給定一個二叉搜索樹,找到其中第k個最小的元素。 1<=k<=tree的大小
思路:兩種解法:本質都是中序遍歷,第一種是dfs:
public class Solution { int count = 1; int result = 0; public int kthSmallest(TreeNode root, int k) { if (root == null) { return 0; } dfs(root,k); return result; } public void dfs(TreeNode root, int k) { if (root == null) { return; } dfs(root.left,k); if (count == k) { result = root.val; } count++; dfs(root.right,k); } }
第二種解法:利用棧的中序遍歷。
public class Solution { public int kthSmallest(TreeNode root, int k) { TreeNode n = root; Stack<TreeNode> stack = new Stack<>(); int result = 0; while (n != null || !stack.isEmpty()) { if (n != null){ stack.push(n); n = n.left; } else { TreeNode t = stack.pop(); k--; if (k == 0) { result = t.val; } n = t.right; } } return result; } }
105. Construct Binary Tree from Preorder and Inorder Traversal
給一個先序遍歷和中序遍歷的數組,構建對應的二叉樹。
思路:
假設樹的先序遍歷是12453687,中序遍歷是42516837。
這裏最重要的一點就是先序遍歷能夠提供根的所在,而根據中序遍歷的性質知道根的所在就能夠將序列分爲左右子樹。
好比上述例子,咱們知道1是根,因此根據中序遍歷的結果425是左子樹,而6837就是右子樹。
接下來根據切出來的左右子樹的長度又能夠在先序便利中肯定左右子樹對應的子序列(先序遍歷也是先左子樹後右子樹)。
根據這個流程,左子樹的先序遍歷和中序遍歷分別是245和425,右子樹的先序遍歷和中序遍歷則是3687和6837,咱們重複以上方法,能夠繼續找到根和左右子樹,直到剩下一個元素。
能夠看出這是一個比較明顯的遞歸過程,對於尋找根所對應的下標,咱們能夠先創建一個HashMap,以避免後面須要進行線行搜索,這樣每次遞歸中就只須要常量操做就能夠完成對根的肯定和左右子樹的分割。
public class Solution { public TreeNode buildTree(int[] preorder, int[] inorder) { if (preorder == null || inorder == null) { return null; } HashMap<Integer, Integer> map = new HashMap<>(); for (int i = 0; i < inorder.length; i++) { map.put(inorder[i], i); } return help(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1, map); } public TreeNode help(int[] preorder, int startPre, int endPre, int[] inorder, int startIn, int endIn, HashMap<Integer, Integer> map) { if (startPre > endPre || startIn > endIn) { return null; } TreeNode root = new TreeNode(preorder[startPre]); int index = map.get(root.val); root.left = help(preorder, startPre + 1, startPre + index - startIn, inorder, startIn, index - 1, map); root.right = help(preorder, startPre + index - startIn + 1, endPre, inorder, index + 1, endIn, map); return root; } }
106. Construct Binary Tree from Inorder and Postorder Traversal
思路:此次是提供了中序和後續的遍歷序列,同理,只不過根在最後面。
public class Solution { public TreeNode buildTree(int[] inorder, int[] postorder) { if (postorder == null || inorder == null){ return null; } HashMap<Integer,Integer>map = new HashMap<>(); for (int i = 0; i < inorder.length; i++){ map.put(inorder[i], i); } return help(postorder, 0,postorder.length-1,inorder,0,inorder.length-1,map); } public TreeNode help(int[]postorder,int startPost,int endPost,int[]inorder,int startIn,int endIn,HashMap<Integer,Integer>map){ if(startIn>endIn||startPost>endPost){ return null; } TreeNode root=new TreeNode(postorder[endPost]); int index=map.get(root.val); root.left=help(postorder,startPost,startPost+index-startIn-1,inorder,startIn,index-1,map); root.right=help(postorder,endPost-(endIn-index),endPost-1,inorder,index+1,endIn,map); return root; } }
94/144/145. Binary Tree Preorder/Inorder/Postorder Traversal
若是用迭代解決以下
pre
public List<Integer> preorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); Deque<TreeNode> stack = new ArrayDeque<>(); TreeNode p = root; while(!stack.isEmpty() || p != null) { if(p != null) { stack.push(p); result.add(p.val); // Add before going to children p = p.left; } else { TreeNode node = stack.pop(); p = node.right; } } return result; }
Inorder:
public List<Integer> inorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); Deque<TreeNode> stack = new ArrayDeque<>(); TreeNode p = root; while(!stack.isEmpty() || p != null) { if(p != null) { stack.push(p); p = p.left; } else { TreeNode node = stack.pop(); result.add(node.val); // Add after all left children p = node.right; } } return result; }
Postorder:
public List<Integer> postorderTraversal(TreeNode root) { LinkedList<Integer> result = new LinkedList<>(); Deque<TreeNode> stack = new ArrayDeque<>(); TreeNode p = root; while(!stack.isEmpty() || p != null) { if(p != null) { stack.push(p); result.addFirst(p.val); // Reverse the process of preorder p = p.right; // Reverse the process of preorder } else { TreeNode node = stack.pop(); p = node.left; // Reverse the process of preorder } } return result; }
222. Count Complete Tree Nodes
計算一個徹底樹的全部節點數量。
思路:先計算左右的深度是否相等(注意 這裏有個易錯點,不是判斷左右子樹的最大深度,而是判斷該樹的最左葉節點的深度是否和該樹最右的葉節點是否相等,因此若是用最大深度去求就會出問題,應該用循環分別計算到最左葉節點和最右節點的長度)相等則爲滿二叉樹,滿二叉樹的節點個數爲深度的平方減一,即depth^2-1;
若是不相等,則遞歸以一樣的方式計算左子樹和右子樹,並返回二者個數之和加一。
注意 用pow方法的時候頗有可能超時,要學會利用位運算 <<
public class Solution { public int countNodes(TreeNode root) { if (root == null) { return 0; } int l = leftDepth(root) + 1; int r = rightDepth(root) + 1; if (l == r) { return (1 << l) - 1; } else { return countNodes(root.left) + countNodes(root.right) + 1; } } public int leftDepth(TreeNode root) { int count = 0; while (root.left != null){ root = root.left; count++; } return count; } public int rightDepth(TreeNode root) { int count = 0; while (root.right != null){ root = root.right; count++; } return count; } }
199. Binary Tree Right Side View
給一個二叉樹,返回它從右側看顯示的數值
For example:
Given the following binary tree,
1 <--- / \ 2 3 <--- \ \ 5 4 <---
You should return [1, 3, 4]
.
思路:傳統的層次遍歷,返回最右側的值,但此處用個更簡單的方法,由於每層只添加一個元素,那麼二叉樹的深度和list中的元素是對應增加的。先遍歷右子節點,存在,添加進list,再次判斷list的數量和深度的關係,不相等說明已經添加過了該層的元素,繼續向下遍歷。
public class Solution { public List<Integer> rightSideView(TreeNode root) { List<Integer> list = new ArrayList<>(); if (root == null) { return list; } help(root, list, 0); return list; } public void help(TreeNode root, List<Integer> list, int depth) { if (root == null) { return; } if (depth == list.size()) { list.add(root.val); } help(root.right, list, depth + 1); help(root.left, list, depth + 1); } }
173. Binary Search Tree Iterator
Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the root node of a BST.
Calling next()
will return the next smallest number in the BST.
Note: next()
and hasNext()
should run in average O(1) time and uses O(h) memory, where h is the height of the tree.
思路:該題每次調用next要返還下一個最小的值。用棧去處理。中序遍歷。
public class BSTIterator { TreeNode node = null; Stack<TreeNode> stack = new Stack<>(); public BSTIterator(TreeNode root) { node = root; } /** @return whether we have a next smallest number */ public boolean hasNext() { return !(stack.isEmpty() && node == null); } /** @return the next smallest number */ public int next() { TreeNode res = null; if (node == null) { res = stack.pop(); node = res.right; } else { while(node.left != null) { stack.push(node); node = node.left; } res = node; node = node.right; } return res.val; } }
leetcode 156: Binary Tree Upside Down
Given a binary tree where all the right nodes are either leaf nodes with a sibling (a left node that shares the same parent node) or empty, flip it upside down and turn it into a tree where the original right nodes turned into left leaf nodes. Return the new root.
For example:
Given a binary tree {1,2,3,4,5},
1
/ \
2 3
/ \
4 5
return the root of the binary tree [4,5,2,#,#,3,1].
4
/ \
5 2
/ \
3 1
思路:這道題讓咱們把一棵二叉樹上下顛倒一下,並且限制了右節點要麼爲空要麼必定會有對應的左節點。上下顛倒後原來二叉樹的最左子節點變成了根節點,其對應的右節點變成了其左子節點,其父節點變成了其右子節點,至關於順時針旋轉了一下。對於一個根節點來講,咱們的目標是將其左子節點變爲根節點,右子節點變爲左子節點,原根節點變爲右子節點,那麼咱們首先判斷這個根節點是否存在,且其有沒有左子節點,若是不知足這兩個條件的話,直接返回便可,不須要翻轉操做。那麼咱們不停的對左子節點調用遞歸函數,直到到達最左子節點開始翻轉,翻轉好最左子節點後,開始回到上一個左子節點繼續翻轉便可,直至翻轉完整棵樹
public class UpsideDown { public TreeNode UpsideDownBinaryTree(TreeNode root) { if (root == null) { return null; } TreeNode parent = root; TreeNode left = root.left; TreeNode right = root.right; if (left != null) { TreeNode temp = UpsideDownBinaryTree(left); left.left=right; left.right=parent; return temp; } return root; } }
366. Find Leaves of Binary Tree
Given a binary tree, find all leaves and then remove those leaves. Then repeat the previous steps until the tree is empty.
Example:
Given binary tree
1
/ \
2 3
/ \
4 5
Returns [4, 5, 3], [2], [1].
思路:一種比較直接的思路是每次截取葉子結點保存起來, 而後再從根開始遍歷剪去葉子結點. 可是這樣重複遍歷太多, 其時間複雜度最壞能夠達到O(n!)。換個思惟考慮,考慮每一個節點的最大深度,每一個節點的最大深度其實就是內層list的對應位置。所以能夠在遍歷的同時判斷該節點的深度,同時將對應節點的值添加到對應的list位置。
public class Solution { public List<List<Integer>> findLeaves(TreeNode root) { List<List<Integer>> list = new ArrayList<>(); if (root == null) { return list; } for(int i = 0; i < depth(root); i++) { list.add(new ArrayList<>()); } depth(root,list); return list; } public int depth(TreeNode root) { if(root == null) { return 0; } int l=depth(root.left); int r=depth(root.right); return l>r? l+1:r+1; } public int depth(TreeNode root, List<List<Integer>> list) { if(root==null) { return 0; } int depth=1; int left=depth(root.left,list); int right=depth(root.right,list); depth+=Math.max(left,right); list.get(depth-1).add(root.val); return depth; } }
129. Sum Root to Leaf Numbers
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
.
思路:兩種第一種用string存儲完整路徑,而後將string轉換爲int。第二種更簡單,每遍歷一次,將對應的sum*10再加上當前的val
public class Solution { public int sumNumbers(TreeNode root) { return help(root, 0); } public int help(TreeNode root, int sum) { if (root == null) { return 0; } if (root.left == null && root.right == null) { return sum * 10 + root.val; } return help(root.left, sum * 10 + root.val) + help(root.right, sum * 10 + root.val); } }
337. House Robber III
小偷偷東西的問題。若是連在一塊兒的房間都偷,則會觸發警報。房間相似二叉樹。求小偷能偷的最大數量
Example 1:
3 / \ 2 3 \ \ 3 1
Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.
Example 2:
3 / \ 4 5 / \ \ 1 3 1
Maximum amount of money the thief can rob = 4 + 5 = 9.
思路:首先分析以前的錯誤解法,以前想的是每隔一層相加一次,但其實也有可能相隔不少層的和大於每隔一層的和,因此該解法錯誤。
說下正確解法,dfs的想法。bottom-up的思想,利用後序遍歷。假設arr[0]表明這個節點咱們能夠搶劫的數量,arr[1]表明若是不搶這個節點咱們能得到的數量。
arr[0]很容易想到,若是搶了該節點,那麼arr[0]的值即爲該節點的數量+不搶它的左子節點能得到的數量+不搶它的右子節點能得到的數量。
公式爲arr[0]=root.val+left[1]+right[1].接下來考慮不搶該節點的狀況,若是不搶該節點,那麼對於該節點的左右子節點也分別有兩種狀況,搶或者不搶,
那麼對應就是 arr[1]=Math.max(left[0],left[1]) + Math.max(right[0],right[1]).那麼最大值即爲arr[0]或者arr[1]其中的一個。
public class Solution { public int rob(TreeNode root) { int[] res = help(root); return Math.max(res[0], res[1]); } public int[] help(TreeNode root) { int[] arr = new int[2]; if (root == null) { return arr; } int[] left = help(root.left); int[] right = help(root.right); arr[0] = root.val + left[1] + right[1]; arr[1] = Math.max(left[0], left[1]) + Math.max(right[1], right[0]); return arr; } }
333. Largest BST Subtree
給定一個二叉樹,找到該二叉樹的最大二叉搜索子樹,返回該樹的尺寸。
思路:兩種解法,第一種就是常規的判斷每一個節點爲根時是不是bst,每遍歷一個子樹的跟節點,變會自根節點遍歷至最下面的葉節點。所以時間複雜度爲O(nlogn).
第二種解法:bottom-up,從下而上。Time Complexity: O(n). 每一個點不會訪問超過兩遍. Space: O(logn).
第一種:
public class LargestBSTSubtree { public int largestBSTSubtree(TreeNode root) { if(isBST(root)) { return size(root); } return Math.max(largestBSTSubtree(root.left), largestBSTSubtree(root.right)); } public int size(TreeNode root) { if(root==null) { return 0; } return size(root.left)+size(root.right)+1; } public boolean isBST(TreeNode root) { return isBST(root,Integer.MIN_VALUE,Integer.MAX_VALUE); } public boolean isBST(TreeNode root, int min,int max){ if(root==null){ return true; } if(root.val<min||root.val>max){ return false; } return (isBST(root.left,min,root.val)&&isBST(root.right,root.val,max)); } }
第二種:
public class LargestBSTSubtreeII { public int largestBSTSubtree(TreeNode root) { int[] res={0}; helper(root,res); return res[0]; } public Node helper (TreeNode root,int [] res){ Node cur=new Node(); if(root==null){ cur.isBST=true; return cur; } Node left=helper(root.left,res); Node right=helper(root.right,res); if(left.isBST && root.val>left.max && right.isBST && root.val<right.min){ cur.isBST=true; cur.min=Math.min(root.val,left.min); cur.max=Math.max(root.val, right.max); cur.size=left.size+right.size+1; if(cur.size>res[0]){ res[0]=cur.size; } } return cur; } } class Node { boolean isBST; int max; int min; int size; public Node(){ isBST=false; min=Integer.MAX_VALUE; max=Integer.MIN_VALUE; size=0; } }
114. Flatten Binary Tree to Linked List
Given a binary tree, flatten it to a linked list in-place.
For example,
Given
1 / \ 2 5 / \ \ 3 4 6
The flattened tree should look like:
1 \ 2 \ 3 \ 4 \ 5 \ 6
思路:從根結點(root)找左子樹(l)的最右子結點(cur),將root的右子樹(r)接到cur的右子樹上(cur的右子樹爲空),root的左子樹總體調整爲右子樹,root的左子樹賦空。
public class Solution { public void flatten(TreeNode root) { while(root!=null) { if(root.left!=null) { TreeNode cur=root.left; while(cur.right!=null) { cur=cur.right; } cur.right=root.right; root.right=root.left; root.left=null; } root=root.right; } } }
108. Convert Sorted Array to Binary Search Tree
給定一個排序好的升序數組,構建一個高度平衡的二叉搜樹
思路:高度平衡,因此從中間二分構造。
public class Solution { public TreeNode sortedArrayToBST(int[] nums) { int left=0; int right=nums.length-1; return help(nums,left,right); } public TreeNode help(int[] nums,int left, int right) { if(left>right) { return null; } int mid=left+(right-left)/2; TreeNode root =new TreeNode(nums[mid]); root.left=help(nums,left,mid-1); root.right=help(nums,mid+1,right); return root; } }
116. Populating Next Right Pointers in Each Node
Given a binary tree
struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode *next; }
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL
.
Initially, all next pointers are set to NULL
.
Note:
For example,
Given the following perfect binary tree,
1 / \ 2 3 / \ / \ 4 5 6 7
After calling your function, the tree should look like:
1 -> NULL / \ 2 -> 3 -> NULL / \ / \ 4->5->6->7 -> NULL
思路:將樹的每一層節點用next串起來。這樣每一層也會造成一個單鏈表。而每層的鏈表頭,則是,根的左孩子,左孩子,左孩子。
利用雙循環,外層循環,沿着根的左孩子,一直向下。內層循環,負責將下一層的節點串起來。即,將本身右孩子放到左孩子的next上,
而右孩子,則可經過本身的next指針,找到右鄰居。
public class Solution { public void connect(TreeLinkNode root) { if(root==null) { return; } TreeLinkNode node; while(root!=null&&root.left!=null) { node=root; while(node!=null) { node.left.next=node.right; if(node.next!=null) { node.right.next=node.next.left; } node=node.next; } root=root.left; } } }
117. Populating Next Right Pointers in Each Node II
思路:與116題不一樣之處在於,給定的二叉樹不是徹底二叉樹了,而是任意的二叉樹,所以要判斷左右子節點是否存在的狀況。
/** * Definition for binary tree with next pointer. * public class TreeLinkNode { * int val; * TreeLinkNode left, right, next; * TreeLinkNode(int x) { val = x; } * } */ public class Solution { public void connect(TreeLinkNode root) { if(root==null) { return; } TreeLinkNode parent=root; TreeLinkNode pre=null; TreeLinkNode curHead=null; while(parent!=null) { TreeLinkNode lastCur=parent; while(lastCur!=null) { if(lastCur.left!=null) { if(curHead==null) { curHead=lastCur.left; pre=curHead; }else { pre.next=lastCur.left; pre=pre.next; } } if(lastCur.right!=null) { if(curHead==null) { curHead=lastCur.right; pre=curHead; }else { pre.next=lastCur.right; pre=pre.next; } } lastCur=lastCur.next; } parent=curHead; curHead=null; } } }
298: Binary Tree Longest Consecutive Sequence
Given a binary tree, find the length of the longest consecutive sequence path.
The path refers to any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The longest consecutive path need to be from parent to child (cannot be the reverse).
For example,
1 \ 3 / \ 2 4 \ 5
Longest consecutive sequence path is 3-4-5
, so return 3
.
2 \ 3 / 2 / 1
Longest consecutive sequence path is 2-3
,not3-2-1
, so return 2
.
思路:遞歸,判斷下一個值是否連續,不連續從下個值開始。
public class LongestConsecutiveSequence { int max = 1; public int longestConsecutive(TreeNode root) { if (root == null) return 0; rec(root, 1); return max; } private void rec(TreeNode n, int c) { if (n.left != null) { if (n.val + 1 == n.left.val) { rec(n.left, c + 1); max = Math.max(max, c + 1); } else { rec(n.left, 1); } } if (n.right != null) { if (n.val + 1 == n.right.val) { rec(n.right, c + 1); max = Math.max(max, c + 1); } else { rec(n.right, 1); } } } }
450. Delete Node in a BST
Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST.
Basically, the deletion can be divided into two stages:
Note: Time complexity should be O(height of tree).
思路:三種狀況,待刪的節點沒有左右子節點,待刪的節點有一個子節點,待刪的節點有兩個子節點,其中有兩個最麻煩,須要尋找後繼節點。
public class DeleteNode { private TreeNode getSuccessor(TreeNode delNode) { TreeNode successorParent = delNode; TreeNode successor = delNode; TreeNode current = delNode.right; while (current != null) { successorParent = successor; successor = current; current = current.left; } if (successor != delNode.right) { successorParent.left = successor.right; successor.right = delNode.right; } return successor; } public TreeNode deleteNode(TreeNode root, int key) { if (root == null) { return null; } TreeNode current = root; TreeNode parent = root; boolean isLeftChild = true; while (current.val != key) { parent = current; if (key < current.val) { current = current.left; isLeftChild = true; } else { isLeftChild = false; current = current.right; } if (current == null) { return root; } } if (current.left == null && current.right == null) { if (current == root) { root = null; } else if (isLeftChild) { parent.left = null; } else { parent.right = null; } } else if (current.right == null) { if (current == root) { root = current.left; } else if (isLeftChild) { parent.left = current.left; } else { parent.right = current.left; } } else if (current.left == null) { if (current == root) { root = current.right; } else if (isLeftChild) { parent.left = current.right; } else { parent.right = current.right; } } else { TreeNode successor = getSuccessor(current); if (current == root) { root = successor; } else if (isLeftChild) { parent.left = successor; } else { parent.right = successor; } successor.left = current.left; } return root; } }
285. Inorder Successor in BST
Given a binary search tree and a node in it, find the in-order successor of that node in the BST.
Note: If the given node has no in-order successor in the tree, return null.
思路:其實就是上題的第三種狀況。
public class Inorder_Successor_in_BST { public TreeNode inorderSuccessor(TreeNode root, TreeNode p) { if (root == null || p == null) { return null; } TreeNode successor = null; while (root != null) { if (p.val < root.val) { successor = root; root = root.left; } else { root = root.right; } } return successor; } }
98. Validate Binary Search Tree
給定一個樹,判斷該樹是否是二叉搜索樹
思路:易錯點在於有可能左子樹的一個右節點的值大於了根節點,或者是右子樹的一個左節點的值小於了根節點。因此要有一個最大值和最小值的概念。
兩種解法,第一種遞歸,第二種迭代。
第一種:
public class Solution { public boolean isValidBST(TreeNode root) { return isValid(root,Long.MIN_VALUE,Long.MAX_VALUE); } public boolean isValid(TreeNode root,long min, long max) { if(root==null) { return true; } if (root.val >= max || root.val <= min) { return false; } return isValid(root.left,min,root.val)&&isValid(root.right,root.val,max); } }
第二種:
public class Solution { public boolean isValidBST(TreeNode root) { if(root==null) { return true; } Stack<TreeNode> stack=new Stack<>(); TreeNode pre=null; while(!stack.isEmpty()||root!=null){ while(root!=null) { stack.push(root); root=root.left; } root=stack.pop(); if(pre!=null&&root.val<=pre.val) { return false; } pre=root; root=root.right; } return true; } }
96. Unique Binary Search Trees
Given n, how many structurally unique BST's (binary search trees) that store values 1...n?
For example,
Given n = 3, there are a total of 5 unique BST's.
1 3 3 2 1 \ / / / \ \ 3 2 1 1 3 2 / / \ \ 2 1 2 3
思路:典型的動態規劃。找出0個值,1個值,2個值的狀況,隨便一個值爲根,左子樹*右子樹即爲該節點爲根的數量。
public class Solution { public int numTrees(int n) { int[] dp=new int[n+1]; dp[0]=1; dp[1]=1; for(int i=2;i<=n;i++) { for(int j=1;j<=i;j++) { dp[i]+=dp[i-j]*dp[j-1]; } } return dp[n]; } }
95. Unique Binary Search Trees II
與上題不同的地方在於要返回全部構建的樹,而不是可構建的數量
public class Solution { public ArrayList<TreeNode> generateTrees(int n) { if (n == 0) { return new ArrayList<TreeNode>(); } return helper(1, n); } private ArrayList<TreeNode> helper(int left, int right) { ArrayList<TreeNode> res = new ArrayList<TreeNode>(); if (left > right) { res.add(null); return res; } for (int i = left; i <= right; i++) { ArrayList<TreeNode> leftList = helper(left, i - 1); ArrayList<TreeNode> rightList = helper(i + 1, right); for (int j = 0; j < leftList.size(); j++) { for (int k = 0; k < rightList.size(); k++) { TreeNode root = new TreeNode(i); root.left = leftList.get(j); root.right = rightList.get(k); res.add(root); } } } return res; } }
255. Verify Preorder Sequence in Binary Search Tree
Given an array of numbers, verify whether it is the correct preorder traversal sequence of a binary search tree.You may assume each number in the sequence is unique.
Follow up:
Could you do it using only constant space complexity?
思路:開始我老是想錯,開始想錯的地方在於給的樹不是一個二叉搜索樹,其實給的樹是一個二叉搜索樹,只不過這個數組可能順序不是按這個二叉搜索樹來的,是要判斷這個數組,而不是判斷這個樹。先序的狀況,
對於一個搜索二叉樹的前序序列來講, 若是某段序列爲一個遞減序列, 說明這是一段沿着左子樹的路徑. 直到碰到一個比前一個大的值, 說明此時已經來到某個結點的右子樹上了, 而此時能夠得出一個此後序列的下界值, 也就是此後序列的任意一個值必需要比這個結點的父結點的值大, 由於對於搜索二叉樹來講根節點左邊的都比根節點小, 而根節點右邊的都比根節點大, 因此既然如今已經來到某個結點(設爲A)的右子樹上, 那麼此後任何結點的值必然比A的值大.
那麼當咱們碰到一個比以前結點大的值如何找到他的父結點呢? 能夠藉助一個棧, 即若是當前結點比棧頂元素小, 就入棧, 若是當前值大於棧頂值, 則讓全部比當前結點小的值都出棧, 直到棧頂元素比當前結點大, 則最後一個出棧的比當前結點小的值就是當前結點的父結點, 咱們只要在棧元素出棧的時候更新最小下界再將當前元素入棧便可. 另外這樣的時間和空間複雜度都是O(n)。若是要o(1)的空間,那麼可利用原數組去模擬棧。
思路一(棧):
public class VerifyPreorderinBST { public boolean verifyPreorder(int[] preorder) { Stack<Integer> stack = new Stack<>(); int min = Integer.MIN_VALUE; for (int i : preorder) { if (i < min) { return false; } while (!stack.isEmpty() && i > stack.peek()) { min = stack.pop(); } stack.push(i); } return true; } }
思路二:利用原數組模擬棧
public class Solution { public boolean verifyPreorder(int[] preorder) { int low = Integer.MIN_VALUE, index = -1; for (int i : preorder) { if (i < low) return false; while (index >= 0 && i > preorder[index]) low = preorder[index--]; preorder[++index] = i; } return true; } }