[leetcode刷題]——樹(BST)
此部落格主要記錄BST(Binary Search Tree)
一、修剪二叉查詢樹
669.修建二叉搜尋樹 (medium)2021-07-06
給你二叉搜尋樹的根節點 root ,同時給定最小邊界low 和最大邊界 high。通過修剪二叉搜尋樹,使得所有節點的值在[low, high]中。修剪樹不應該改變保留在樹中的元素的相對結構(即,如果沒有被移除,原有的父代子代關係都應當保留)。 可以證明,存在唯一的答案。
使用遞迴的方法
class Solution { public TreeNode trimBST(TreeNode root, int low, int high) {if(root == null) return null; if(root.val > high) return trimBST(root.left, low, high); if(root.val < low) return trimBST(root.right, low, high); root.left = trimBST(root.left, low, high); root.right = trimBST(root.right, low, high); return root; } }
二、尋找二叉查詢樹的第k小的元素
230.二叉搜尋樹中第k小的元素 (medium)2021-07-07
給定一個二叉搜尋樹的根節點root ,和一個整數k ,請你設計一個演算法查詢其中第k 個最小的元素(從1開始計數)。
class Solution { public int kthSmallest(TreeNode root, int k) { int kthSmall = -1; Stack<TreeNode> stack = new Stack<>(); TreeNode node = root;int count = 0; while(!stack.isEmpty() || node != null){ while(node != null){ stack.push(node); node = node.left; } TreeNode node_out = stack.pop(); count++; if(count == k){ kthSmall = node_out.val; break; } node = node_out.right; } return kthSmall; } }
三、把二叉查詢樹每個節點的值都加上比他大的節點的值
538. 把二叉搜尋樹轉換為累加樹(medium)2021-07-07
給出二叉搜尋樹的根節點,該樹的節點值各不相同,請你將其轉換為累加樹(Greater Sum Tree),使每個節點
node
的新值等於原樹中大於或等於node.val
的值之和。提醒一下,二叉搜尋樹滿足下列約束條件:
-
-
節點的左子樹僅包含鍵小於節點鍵的節點。
-
節點的右子樹僅包含鍵大於節點鍵的節點。
-
左右子樹也必須是二叉搜尋樹。
-
我的做法雖然有用但是很傻,常規解法,首先遍歷得到所有節點的累加和,然後再次遍歷一遍修改各個節點的值。
class Solution { public TreeNode convertBST(TreeNode root) { sum = inOrderSum(root); return inOrder(root); } //對二叉搜尋樹進行求和 int sum = 0; public int inOrderSum(TreeNode root){ if(root == null) return -1; inOrderSum(root.left); sum = sum + root.val; inOrderSum(root.right); return sum; } //對二叉樹進行前序遍歷,然後修改節點的值 int preSum = 0; public TreeNode inOrder(TreeNode root){ if(root == null) return null; inOrder(root.left); int temp = root.val; root.val = sum - preSum; preSum = preSum + temp; inOrder(root.right); return root; } }
在二叉搜尋樹中我一直執著於中序遍歷,但是這個題使用(右子樹 -> 根節點 -> 左子樹) 顯然更方便。一次遍歷就行,時間空間都暴打我的方法。
public TreeNode convertBST(TreeNode root) { traver(root); return root; } private void traver(TreeNode node) { if (node == null) return; traver(node.right); sum += node.val; node.val = sum; traver(node.left); }
四、二叉查詢樹的最近公共祖先
235.二叉搜尋樹的最近公共祖先 (easy)2021-07-07
給定一個二叉搜尋樹, 找到該樹中兩個指定節點的最近公共祖先。
百度百科中最近公共祖先的定義為:“對於有根樹 T 的兩個結點 p、q,最近公共祖先表示為一個結點 x,滿足 x 是 p、q 的祖先且 x 的深度儘可能大(一個節點也可以是它自己的祖先)。”
例如,給定如下二叉搜尋樹: root =[6,2,8,0,4,7,9,null,null,3,5]
這個題我一點頭緒都沒有,答案只需要三行就解決了,破防了。
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if(root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left, p, q); if(root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right, p, q); return root; }
五、二叉樹最近的公共祖先
236. 二叉樹最近的公共祖先 (medium)2021-07-07
給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。
百度百科中最近公共祖先的定義為:“對於有根樹 T 的兩個節點 p、q,最近公共祖先表示為一個節點 x,滿足 x 是 p、q 的祖先且 x 的深度儘可能大(一個節點也可以是它自己的祖先)。”
這個題和上面的題極其相似,難度增加,但是我依然沒有頭緒。
class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if(root == null) return null; if(root == p || root == q) return root; TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); if(left != null && right != null) return root; if(left != null) return left; if(right != null) return right; return null; } }
六、從有序陣列中構造二叉查詢樹
108.將有序陣列轉換成二叉搜尋樹 (easy)2021-07-07
給你一個整數陣列 nums ,其中元素已經按 升序 排列,請你將其轉換為一棵 高度平衡 二叉搜尋樹。
高度平衡 二叉樹是一棵滿足「每個節點的左右兩個子樹的高度差的絕對值不超過 1 」的二叉樹。
class Solution { public TreeNode sortedArrayToBST(int[] nums) { int len = nums.length; return sortedArrayToBST(nums, 0, len - 1); } //這個函式的作用是將從l 到 r 的下標的陣列進行整理 public TreeNode sortedArrayToBST(int[] nums, int l, int r){ if(l > r) return null; int m = l + (r - l) / 2; TreeNode root = new TreeNode(nums[m]); root.left = sortedArrayToBST(nums, l , m - 1); root.right = sortedArrayToBST(nums, m + 1, r); return root; } }
七、根據有序連結串列構造平衡二叉查詢樹
109. 有序連結串列轉換二叉搜尋樹 (medium)2021-07-07
給定一個單鏈表,其中的元素按升序排序,將其轉換為高度平衡的二叉搜尋樹。
本題中,一個高度平衡二叉樹是指一個二叉樹每個節點的左右兩個子樹的高度差的絕對值不超過 1。
我用陣列的思路去解這個題,用時擊敗 5%的使用者。
評論裡說到,思想的懶惰不利於寫出牛逼的程式,我深以為然。
class Solution { public TreeNode sortedListToBST(ListNode head) { ListNode node = head; int count = 0; //連結串列的長度 while(node != null){ count ++; node = node.next; } return toBST(head, 0, count - 1); } public TreeNode toBST(ListNode head, int l, int r){ if(l > r) return null; int m = l + (r - l) / 2; TreeNode root = new TreeNode(searchList(head, m)); root.left = toBST(head, l, m - 1); root.right = toBST(head, m + 1, r); return root; } //尋找連結串列中下標為m 的元素, m小於連結串列的長度 public int searchList(ListNode head, int m){ ListNode node = new ListNode(); node.next = head; for(int i = 0; i <= m; i++){ node = node.next; } return node.val; } }
碰到連結串列找中點的演算法,使用快慢指標,讓快的指標一次移動兩格,慢的一次一格。當快指標到隊尾的時候,慢指標正好是在連結串列中間。
連結串列相對於陣列有自己的優勢,其不需要記錄陣列的下標,只需要將連結串列斷開就行。
轉換思路,用時擊敗 100%
class Solution { public TreeNode sortedListToBST(ListNode head) { if(head == null) return null; if(head.next == null) return new TreeNode(head.val); ListNode fastNode = head; ListNode slowNode = head; ListNode midLeftNode = head; while(fastNode != null && fastNode.next != null){ fastNode = fastNode.next.next; midLeftNode = slowNode; slowNode = slowNode.next; } TreeNode root = new TreeNode(slowNode.val); midLeftNode.next = null; //將中間節點的左邊節點的next指標置為null root.left = sortedListToBST(head); root.right = sortedListToBST(slowNode.next); return root; } }
八、在二叉查詢樹中尋找兩個節點,使它們的和為一個定值
653. 兩數之和IV ( BST) (easy)2021-07-07
給定一個二叉搜尋樹和一個目標結果,如果 BST 中存在兩個元素且它們的和等於給定的目標結果,則返回 true。
思想需要簡單,將二叉查詢樹中序遍歷為有序列表,然後對列表進行查詢。
class Solution { public boolean findTarget(TreeNode root, int k) { List<Integer> l = TreeToList(root); int i = 0; int j = l.size() - 1; while(i < j){ int sum = l.get(i) + l.get(j); if(sum == k) return true; if(sum > k){ j--; }else{ i++; } } return false; } List<Integer> list = new ArrayList<>(); public List<Integer> TreeToList(TreeNode root){ if(root == null) return null; TreeToList(root.left); list.add(root.val); TreeToList(root.right); return list; } }