文章目錄
- 一、“樹”基礎(來自LeetCode)
- 二、“樹”題目--遞歸
- 1.二叉樹的最大深度(題號:104,Easy) 第2次
- 2.平衡二叉樹
- 3.二叉樹的直徑
- 4.路徑總和
- 5.合併二叉樹
- 6.翻轉二叉樹 第2次
- 7.統計路徑和等於一個數的路徑數量
- 8.另一個樹的子樹(題號:572)
- 9.對稱二叉樹(題號:101)
- 10.二叉樹的最小深度(題號:111) 第2次
- 11.左葉子之和(題號:404) 第1次
- 12.最長節點值相同的路徑(題號:687) 有待進一步理解???
- 13.打家劫舍 III,間隔遍歷(題號:337) 第二遍
- 14.二叉樹中第二小的節點(題號:671) 第一遍
- 15.相同的樹(題號:100) 第1次
- 16.求根到葉子節點數字之和(題號:129) 第1次
- 17.二叉樹的所有路徑(題號:257) 第1次
- 三、“樹”題目--遍歷
- 1.二叉樹的層平均值(題號:637) 第一次
- 2.找樹左下角的值(題號:513) 第一次
- 3.非遞歸實現二叉樹的前序遍歷(題號:144) 第一次
- 4.非遞歸實現二叉樹的後序遍歷(題號:145) 第一次
- 5.非遞歸實現二叉樹的中序遍歷(題號:94) 第0次
- 四、“樹”題目--二叉查找樹
一、“樹”基礎(來自LeetCode)
樹的深度:某節點的深度是指從根節點到該節點的最長簡單路徑邊的條數,從根節點往下數邊數。
樹的高度:某節點的高度指從該節點到葉子節點的最長簡單路徑邊的條數,從葉子節點往上數。
二、“樹”題目–遞歸
1.二叉樹的最大深度(題號:104,Easy) 第2次
題目描述:
給定一個二叉樹,找出其最大深度,二叉樹的深度爲根節點到最遠葉子節點的最長路徑上的節點數。
說明: 葉子節點是指沒有子節點的節點。
解題思路:利用遞歸的思想,三部曲:第一步,找到遞歸出口,當root爲0時,返回0,即爲遞歸出口;第二步,找返回值,返回值爲int型,爲本子樹的深度;第三步:遞歸主體是左右子樹的深度,並進行比較。可參考:https://blog.csdn.net/weixin_43502661/article/details/90743053
代碼:
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 Math.max(l,r);
}
}
2.平衡二叉樹
題目描述:給定一個二叉樹,判斷它是否是高度平衡的二叉樹。本題中,一棵高度平衡二叉樹定義爲:
一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過1。
解題思路:利用遞歸的思路,只不過要用兩個函數,同樣遵循遞歸三部曲,只不過這裏的第三步遞歸函數的主體增加了判斷該級樹是否爲平衡二叉樹的步驟。
啓發:遞歸函數並不一定是要用一個函數完成(尤其是對於返回boolean類型值的函數),也可以使用返回值爲其他類型(比如int型)來進行遞歸。
代碼:
class Solution {
private boolean result = true;
public boolean isBalanced(TreeNode root) {
MaxDepth(root);
return result;
}
public int MaxDepth(TreeNode root){
if(root == null){
return 0;
}
int l = MaxDepth(root.left);
int r = MaxDepth(root.right);
if(Math.abs(l-r) > 1) this.result = false;
return Math.max(l+1,r+1);
}
}
3.二叉樹的直徑
題目描述:給定一棵二叉樹,你需要計算它的直徑長度。一棵二叉樹的直徑長度是任意兩個結點路徑長度中的最大值。這條路徑可能穿過根結點。
解題思路:根據二叉樹最大深度的代碼可以得到每一個子樹的左右深度(分別用l和r表示),將某由於深度指的是根節點到葉子節點的節點的數目,這裏需要統計的是邊數,所以對於某一個子樹,它的直徑爲左右最大深度對應的邊數之和,即(l-1+r-1),定義一個成員變量len初始化爲0,然後在不斷遞歸的過程中進行比較,得到其最大值。
代碼:
class Solution {
public int len = 0;
public int diameterOfBinaryTree(TreeNode root) {
maxDepth(root);
return len;
}
public int maxDepth(TreeNode root){
if(root == null){
return 0;
}
int l = maxDepth(root.left) + 1;
int r = maxDepth(root.right) + 1;
len = (len < (l+r-2)) ? (l+r-2) : len;
return Math.max(l,r);
}
}
4.路徑總和
題目描述:給定一個二叉樹和一個目標和,判斷該樹中是否存在根節點到葉子節點的路徑,這條路徑上所有節點值相加等於目標和。
解題思路:採用遞歸的思路,將這顆樹看成一個只包含:左、右、根節點,可以看成從根節點開始遍歷,每過一個根節點,則sum減去根節點的值,最後到葉子節點時判斷sum是否爲0,也即找到遞歸的出口(遍歷到葉子節點即爲遞歸出口,這裏有兩個出口,出口值分別爲false和true)。
代碼:
參考代碼:優秀
public boolean hasPathSum(TreeNode root, int sum) {
if (root == null) return false;
if (root.left == null && root.right == null && root.val == sum) return true;
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
我的代碼:垃圾
class Solution {
private boolean result=false;
public boolean hasPathSum(TreeNode root, int sum) {
if(root == null){
return false;
}
path(root,sum);
return result;
}
public void path(TreeNode root,int sum){
if(root.left == null && root.right == null){
sum = sum - root.val;
if(sum == 0){
result = true;
}
}
if(root.left != null){
path(root.left,sum - root.val);
}
if(root.right != null){
path(root.right,sum - root.val);
}
}
}
5.合併二叉樹
題目描述:(題號:617)給定兩個二叉樹,想象當你將它們中的一個覆蓋到另一個上時,兩個二叉樹的一些節點便會重疊。你需要將他們合併爲一個新的二叉樹。合併的規則是如果兩個節點重疊,那麼將他們的值相加作爲節點合併後的新值,否則不爲 NULL 的節點將直接作爲新二叉樹的節點。
解題思路:利用迭代的思想,三部曲,第一步:迭代出口,三種情況(t1和t2同時爲空,t1爲空、t2爲空)。第二步:返回值爲result。第三步:遞歸主體,
result.val = t1.val + t2.val;
result.left = mergeTrees(t1.left,t2.left);
result.right = mergeTrees(t1.right,t2.right);
代碼:
class Solution {
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
if(t1 == null && t2 == null){
return null;
}
if(t1 == null){
return t2;
}
if(t2 == null){
return t1;
}
TreeNode result = t1;
result.val = t1.val + t2.val;
result.left = mergeTrees(t1.left,t2.left);
result.right = mergeTrees(t1.right,t2.right);
return result;
}
}
6.翻轉二叉樹 第2次
題目描述:翻轉一棵二叉樹。
解題思路:利用遞歸的思想,三部曲,第一步:遞歸出口,當傳入的節點爲null時,返回null;第二步:返回值,返回傳入的root節點,第三步:遞歸方法主體,將root的左子樹先暫存下來,然後讓root的左子樹等於其右子樹,再讓右子樹等於暫存的左子樹;
代碼:
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null){
return null;
}
TreeNode left = root.left;
root.left = invertTree(root.right);
root.right = invertTree(left);
return root;
}
}
7.統計路徑和等於一個數的路徑數量
題目描述:給定一個二叉樹,它的每個結點都存放着一個整數值。找出路徑和等於給定數值的路徑總數。路徑不需要從根節點開始,也不需要在葉子節點結束,但是路徑方向必須是向下的(只能從父節點到子節點)。
二叉樹不超過1000個節點,且節點數值範圍是 [-1000000,1000000] 的整數。
解題思路:由於這道題沒有限制從頭節點開始到哦葉子節點終止,解決辦法是:將一顆包含(root,left,right)的一棵樹,分別考慮以三個節點開始的情況,從root節點開始的情況,直接採用從頭節點開始遍歷,採用sum-root.val的方法,找到路徑等於sum的個數,在以非頭節點開始的情況,則採用雙重遞歸的方式,將root.left、root.right重新當作新的root節點進行遞歸。
代碼:
class Solution {
public int pathSum(TreeNode root, int sum) {
if(root == null){
return 0;
}
int num = start_path(root,sum) + pathSum(root.left, sum) + pathSum(root.right,sum);
return num;
}
public int start_path(TreeNode root,int sum){
if(root == null){
return 0;
}
int ret = 0;
if(root.val == sum){
ret++;
}
ret += start_path(root.left,sum - root.val) + start_path(root.right,sum - root.val);
return ret;
}
}
8.另一個樹的子樹(題號:572)
題目描述:給定兩個非空二叉樹 s 和 t,檢驗 s 中是否包含和 t 具有相同結構和節點值的子樹。s 的一個子樹包括 s 的一個節點和這個節點的所有子孫。s 也可以看做它自身的一棵子樹。
解題思路:利用雙重遞歸的思路,首先將樹看成root、left、right三個節點。在第一重遞歸,遞歸三部曲,第一步:當s爲null或者t爲null時,返回false;第二步:遞歸主體,將以s爲根節點的樹與以t爲根節點的樹進行比較,同時比較以s.left和s.right爲根節點的樹與t樹進行比較;第三步:返回比較結果,三者的比較是或的關係。在第二重遞歸,將使用遞歸遍歷的方式,對兩棵樹進行比較。
代碼:
參考代碼:優秀
public boolean isSubtree(TreeNode s, TreeNode t) {
if (s == null) return false;
return isSubtreeWithRoot(s, t) || isSubtree(s.left, t) || isSubtree(s.right, t);
}
private boolean isSubtreeWithRoot(TreeNode s, TreeNode t) {
if (t == null && s == null) return true;
if (t == null || s == null) return false;
if (t.val != s.val) return false;
return isSubtreeWithRoot(s.left, t.left) && isSubtreeWithRoot(s.right, t.right);
}
我的代碼:垃圾
class Solution {
public boolean isSubtree(TreeNode s, TreeNode t) {
if(s == null || t == null){
return false;
}
boolean result1 = bijiao(s,t);
if(result1 == true){
return true;
}
return isSubtree(s.left,t)||isSubtree(s.right,t);
}
private boolean bijiao(TreeNode s, TreeNode t){
if(s == null && t == null) return true;
if(s == null || t == null){
return false;
}
boolean result = false;
if(s.val == t.val){
result = bijiao(s.left,t.left)&&bijiao(s.right,t.right);
}
return result;
}
}
9.對稱二叉樹(題號:101)
題目描述:給定一個二叉樹,檢查它是否是鏡像對稱的,
解題思路:直接使用遞歸比較就行,設root的左子節點爲t1,右子節點爲t2,調用遞歸函數進行比較,比較t1.left與t2.right,比較t1.right與t2.left,由此往下遞歸,得到的結果取&&運算。
代碼:
參考代碼:優秀!!!
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return isSymmetric(root.left, root.right);
}
private boolean isSymmetric(TreeNode t1, TreeNode t2) {
if (t1 == null && t2 == null) return true;
if (t1 == null || t2 == null) return false;
if (t1.val != t2.val) return false;
return isSymmetric(t1.left, t2.right) && isSymmetric(t1.right, t2.left);
}
我的代碼:很垃圾,將其中一個子樹翻轉,再比較,多此一舉
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null){
return true;
}
return bijiao(root.left,overturn(root.right));
}
private TreeNode overturn(TreeNode root){
if(root == null){
return null;
}
TreeNode node = overturn(root.left);
root.left = overturn(root.right);
root.right = node;
return root;
}
private boolean bijiao(TreeNode l,TreeNode r){
if(l == null && r == null){
return true;
}
if(l == null || r == null){
return false;
}
if(l.val != r.val){
return false;
}
return bijiao(l.left,r.left) && bijiao(l.right,r.right);
}
}
10.二叉樹的最小深度(題號:111) 第2次
題目描述:給定一個二叉樹,找出其最小深度。最小深度是從根節點到最近葉子節點的最短路徑上的節點數量。
說明: 葉子節點是指沒有子節點的節點。
解題思路:還是迭代的思想,與二叉樹最大深度不同的是,這裏需要考慮左右子節點爲空的情況,比如左子節點爲空,則其沒有葉子節點,這時如果右子節點不爲空,則繼續最小深度在右子節點中,這裏最關鍵的一步是判斷root節點的左右子節點爲空時的情況(如果某一個子節點爲空,則返回另一個子節點的遞歸結果,若同時爲空,返回1)。
代碼:
參考代碼1:
public int minDepth(TreeNode root) {
if (root == null) return 0;
int left = minDepth(root.left);
int right = minDepth(root.right);
if (left == 0 || right == 0) return left + right + 1;
return Math.min(left, right) + 1;
}
我修改的代碼2:主要區別在於加減1的方式,
public int minDepth(TreeNode root) {
if (root == null) return 0;
int left = minDepth(root.left)+1;
int right = minDepth(root.right)+1;
if (left == 1 || right == 1) return left + right - 1;
return Math.min(left, right);
}
我的實現代碼(2020.1.1):
class Solution {
public int minDepth(TreeNode root) {
if(root == null){
return 0;
}
if(root.left == null && root.right == null){
return 1;
}
else if(root.left == null){
return minDepth(root.right)+1;
}
else if(root.right == null){
return minDepth(root.left)+1;
}
return Math.min(minDepth(root.left),minDepth(root.right))+1;
}
}
11.左葉子之和(題號:404) 第1次
題目描述:計算給定二叉樹的所有左葉子之和。
解題思路:採用遞歸的思想,三部曲,第一步:找到遞歸的出口,即讓根節點爲空是,返回0;第二步:返回值,對於一顆簡單樹(包含root,left,right)來說,返回“left的左葉子和”+“right的左葉子和”,如果root.left爲葉子節點,則返回root.left+“right的左葉子和”。
代碼:
我的代碼:優秀(在sumOfLeftLeaves函數中直接判斷左子節點是否爲葉子節點,並引入變量num來代表左葉子節點的值)
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if(root == null){
return 0;
}
int num = 0;
if(root.left != null){
if(root.left.left == null && root.left.right == null)
num = root.left.val;
}
int l = sumOfLeftLeaves(root.left);
int r = sumOfLeftLeaves(root.right);
return l+r+num;
}
}
參考代碼:同樣優秀(將判斷是否爲左葉子節點單列一個函數,並採用標準的思維方式編寫代碼)
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) return 0;
if (isLeaf(root.left)) return root.left.val + sumOfLeftLeaves(root.right);
return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
}
private boolean isLeaf(TreeNode node){
if (node == null) return false;
return node.left == null && node.right == null;
}
12.最長節點值相同的路徑(題號:687) 有待進一步理解???
題目描述:
給定一個二叉樹,找到最長的路徑,這個路徑中的每個節點具有相同值。 這條路徑可以經過也可以不經過根節點。
注意:兩個節點之間的路徑長度由它們之間的邊數表示。
解題思路:
這道題採用由下到上(從葉子節點到根節點)的思路會更加清晰,首先,假設一棵樹包含三個節點(root、left、right),如果left.val與right.val、root.val想等,這是暫存路徑長度path爲2,但是返回到上層只能返回1,因爲從上層節點到這一層的root之後,只能向左或者向右走,所以取左節點或者右節點路徑的最大值,當然,也就是說函數的返回值爲向左或向右的最大值。
代碼:
class Solution {
private int path = 0;
public int longestUnivaluePath(TreeNode root) {
numpath(root);
return path;
}
private int numpath(TreeNode root){
if(root == null){
return 0;
}
int left = numpath(root.left);
int right = numpath(root.right);
int leftpath = root.left != null && root.val == root.left.val ? left + 1 : 0;
int rightpath = root.right != null && root.val == root.right.val ? right + 1 : 0;
path = Math.max(path,leftpath + rightpath);
return Math.max(leftpath,rightpath);
}
}
13.打家劫舍 III,間隔遍歷(題號:337) 第二遍
題目描述:
在上次打劫完一條街道之後和一圈房屋後,小偷又發現了一個新的可行竊的地區。這個地區只有一個入口,我們稱之爲“根”。 除了“根”之外,每棟房子有且只有一個“父“房子與之相連。一番偵察之後,聰明的小偷意識到“這個地方的所有房屋的排列類似於一棵二叉樹”。 如果兩個直接相連的房子在同一天晚上被打劫,房屋將自動報警。
計算在不觸動警報的情況下,小偷一晚能夠盜取的最高金額。
解題思路:
代碼:
class Solution {
public int rob(TreeNode root){
if(root == null){
return 0;
}
int sum = 0;
sum = sum + root.val;
if(root.left != null){
sum = sum + rob(root.left.left)+rob(root.left.right);
}
if(root.right != null){
sum = sum + rob(root.right.left)+rob(root.right.right);
}
return Math.max(sum,rob(root.left)+rob(root.right));
}
}
參考代碼:1ms,擊敗100%用戶
class Solution {
public int rob(TreeNode root) {
int[] res = doRob(root);
return Math.max(res[0],res[1]);
}
//res[0]爲不包括根節點的最大值,res[1]爲包括根節點的最大值
private int[] doRob(TreeNode root){
int[] res = new int[2];
if(root == null)
return res;
int[] left = doRob(root.left);
int[] right = doRob(root.right);
//不包含根節點,最大值爲兩個子樹的最大值之和
res[0] = Math.max(left[0],left[1])+Math.max(right[0],right[1]);
//包含根節點,最大值爲兩個子樹不包含根節點的最大值加上根節點的值
res[1] = left[0] + right[0] + root.val;
return res;
}
}
14.二叉樹中第二小的節點(題號:671) 第一遍
題目描述:
給定一個非空特殊的二叉樹,每個節點都是正數,並且每個節點的子節點數量只能爲 2 或 0。如果一個節點有兩個子節點的話,那麼這個節點的值不大於它的子節點的值。給出這樣的一個二叉樹,你需要輸出所有節點中的第二小的值。如果第二小的值不存在的話,輸出 -1 。
解題思路:考慮從上到下的一種遞歸思路,因爲葉子節點肯定都是大於等於root節點的,所以可以將root節點的左右子節點中與root.val不相同的子節點暫存(作爲備選A),將與root.val相同的子節點(記爲節點B)繼續向下遍歷,因爲比root.val大同時比備選A小的葉子節點只能在B節點的子節點中出現,然後遞歸找到B子樹下面的除root.val之外的次小節點值,再與備選A進行比較,得到次小值。
代碼:
參考代碼:
class Solution {
public int findSecondMinimumValue(TreeNode root) {
if (root == null) return -1;
if (root.left == null && root.right == null) return -1;
int leftVal = root.left.val;
int rightVal = root.right.val;
if (leftVal == root.val) leftVal = findSecondMinimumValue(root.left);
if (rightVal == root.val) rightVal = findSecondMinimumValue(root.right);
if (leftVal != -1 && rightVal != -1) return Math.min(leftVal, rightVal);
if (leftVal != -1) return leftVal;
return rightVal;
}
}
15.相同的樹(題號:100) 第1次
題目鏈接:相同的樹
題目描述:
給定兩個二叉樹,編寫一個函數來檢驗它們是否相同。
如果兩個樹在結構上相同,並且節點具有相同的值,則認爲它們是相同的。
代瑪:
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q == null){
return true;
}
else if(p != null && q != null){
if(p.val == q.val)
return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
else
return false;
}
return false;
}
}
16.求根到葉子節點數字之和(題號:129) 第1次
題目鏈接:求根到葉子節點數字之和
題目描述:
給定一個二叉樹,它的每個結點都存放一個 0-9 的數字,每條從根到葉子節點的路徑都代表一個數字。
例如,從根到葉子節點路徑 1->2->3 代表數字 123。
計算從根到葉子節點生成的所有數字之和。
說明: 葉子節點是指沒有子節點的節點。
解題思路:利用遞歸的思路,另外寫一個返回值位int型,並且多一個入參val的函數,val代表高位,需要乘以10,再加上當前root.val值,遞歸的出口爲葉子節點所對應的最簡單的一顆二叉樹,即return val*10+root.val。
我的代碼:
class Solution {
public int sumNumbers(TreeNode root) {
if(root == null)
return 0;
if(root.left == null && root.right == null)
return root.val;
return sumNumbers(root.left,root.val)+sumNumbers(root.right,root.val);
}
public int sumNumbers(TreeNode root,int val){
if(root == null)
return 0;
if(root.left == null && root.right == null)
return val*10+root.val;
val = val*10 + root.val;
int l = sumNumbers(root.left,val);
int r = sumNumbers(root.right,val);
return l+r;
}
}
17.二叉樹的所有路徑(題號:257) 第1次
題目鏈接:二叉樹的所有路徑
題目描述:
給定一個二叉樹,返回所有從根節點到葉子節點的路徑。
說明: 葉子節點是指沒有子節點的節點。
解題思路:
代碼:
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> list = new ArrayList<String>();
if(root == null){
return list;
}
if(root.left == null && root.right == null){
list.add(root.val+"");
return list;
}
List<String> list_left = binaryTreePaths(root.left);
for(String s : list_left){
list.add(root.val+"->"+s);
}
List<String> list_right = binaryTreePaths(root.right);
for(String s : list_right){
list.add(root.val+"->"+s);
}
return list;
}
}
三、“樹”題目–遍歷
1.二叉樹的層平均值(題號:637) 第一次
題目鏈接:二叉樹的層平均值
題目描述:
給定一個非空二叉樹, 返回一個由每層節點平均值組成的數組。
解題思路:
代碼:
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> list = new ArrayList<>();
if(root == null) return list;
Queue<TreeNode> queue = new LinkedList();
queue.add(root);
while(!queue.isEmpty()){
double sum = 0;
int qsize = queue.size();
for(int i = 0; i < qsize; i++){
TreeNode node = queue.poll();
sum = sum + node.val;
if(node.left != null) queue.add(node.left);
if(node.right != null )queue.add(node.right);
}
list.add(sum/qsize);
}
return list;
}
}
2.找樹左下角的值(題號:513) 第一次
題目鏈接:找樹左下角的值
題目描述:給定一個二叉樹,在樹的最後一行找到最左邊的值。
解題思路:充分利用隊列的先入先出的思想,使用while循環,將最不可能的結果最先進入隊列,也就是一次進隊的爲root,然後root出隊,root.right、root.left依次進隊,最後while循環結束運行之後的最後一次出隊的節點即爲最左下角的值。
代碼:
參考代碼:優秀
public int findBottomLeftValue(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
root = queue.poll();
if (root.right != null) queue.add(root.right);
if (root.left != null) queue.add(root.left);
}
return root.val;
}
我的代碼:按照從左到右的一般順序進行遍歷,將最後一層遍歷出來之後,取最後一層隊列的第一個值。垃圾!
class Solution {
public int findBottomLeftValue(TreeNode root) {
Queue<TreeNode> queue = new LinkedList();
queue.add(root);
TreeNode result = root;
while(!queue.isEmpty()){
int size = queue.size();
result = queue.peek();
for(int i = 0; i < size ;i++){
TreeNode node = queue.poll();
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
}
}
return result.val;
}
}
3.非遞歸實現二叉樹的前序遍歷(題號:144) 第一次
題目描述:
給定一個二叉樹,返回它的前序遍歷。
解題思路:定義一個棧,首先將root節點壓入s1棧中,然後用while循環,將s1棧中的節點node彈出,並判斷node是否有左右子節點,若有,現將右子節點壓入棧中,再將左子節點壓入棧中,然後將彈出的node節點的val值添加到數組list中,進行下一次循環,直到s1中爲空爲止。
代碼:
非遞歸實現方式:
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<Integer>();
Stack<TreeNode> s1 = new Stack<TreeNode>();
if(root == null) return list;
s1.push(root);
while(!s1.isEmpty()){
TreeNode node = s1.pop();
if(node.right != null) s1.push(node.right);
if(node.left != null) s1.push(node.left);
list.add(node.val);
}
return list;
}
}
遞歸實現方式:
class Solution {
private List<Integer> list = new ArrayList<Integer>();
public List<Integer> preorderTraversal(TreeNode root) {
if(root == null){
return list;
}
list.add(root.val);
preorderTraversal(root.left);
preorderTraversal(root.right);
return list;
}
}
4.非遞歸實現二叉樹的後序遍歷(題號:145) 第一次
題目描述:
解題思路:
代碼:
我的代碼:
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
Stack<TreeNode> s1 = new Stack<TreeNode>();
Stack<TreeNode> s2 = new Stack<TreeNode>();
List<Integer> ret = new ArrayList<Integer>();
if(root == null) return ret;
s1.push(root);
if(root.left != null){
s2.push(root.left);
}
if(root.right != null){
s2.push(root.right);
}
while(!s2.isEmpty()){
TreeNode node = s2.pop();
s1.push(node);
if(node.left != null) s2.push(node.left);
if(node.right != null) s2.push(node.right);
}
while(!s1.isEmpty()){
ret.add(s1.pop().val);
}
return ret;
}
}
5.非遞歸實現二叉樹的中序遍歷(題號:94) 第0次
四、“樹”題目–二叉查找樹
1.修剪二叉搜索樹(題號:669) 第1次
題目描述:
給定一個二叉搜索樹,同時給定最小邊界L 和最大邊界 R。通過修剪二叉搜索樹,使得所有節點的值在[L, R]中 (R>=L) 。你可能需要改變樹的根節點,所以結果應當返回修剪好的二叉搜索樹的新的根節點。
解題思路:
代碼:
class Solution {
public TreeNode trimBST(TreeNode root, int L, int R){
if(root == null) return null;
if(root.val < L){
root = trimBST(root.right,L,R);
}
else if(root.val > R){
root = trimBST(root.left,L,R);
}
else {
if(root.left != null) root.left = trimBST(root.left,L,R);
if(root.right != null) root.right = trimBST(root.right,L,R);
}
return root;
}
}
2.二叉搜索樹中第K小的元素(題號:230) 第1次
題目描述:
給定一個二叉搜索樹,編寫一個函數 kthSmallest 來查找其中第 k 個最小的元素。
說明:
你可以假設 k 總是有效的,1 ≤ k ≤ 二叉搜索樹元素個數。
解題思路:
我的思路:二叉查找樹中第k小的節點也即中序遍歷後得到的第k個節點,利用遞歸中序遍歷的思路,可以得到遞歸的結果,將結果添加到數組鏈表ArrayList中,再使用get方法獲取第k小的值。(我實現的代碼效率較低)
參考思路:也是利用中序遍歷,但是不將遍歷到的從小到大的數據存放到鏈表中,而是遍歷到後就不管了,等到找到符合要求的第k小值,再將其保存到result變量。
代碼:
我的代碼:
class Solution {
public int kthSmallest(TreeNode root, int k) {
List<Integer> list = new ArrayList<Integer>();
find(root,list);
int result = list.get(k-1);
return result;
}
private void find(TreeNode root, List<Integer> list){
if(root == null){
return ;
}
find(root.left,list);
list.add(root.val);
find(root.right,list);
}
}
參考代碼:
class Solution {
private int result = 0;
private int cnt = 0;
public int kthSmallest(TreeNode root, int k) {
find(root,k);
return result;
}
private void find(TreeNode root,int k){
if(root == null){
return ;
}
find(root.left,k);
cnt++;
if(k == cnt){
result = root.val;
return ;
}
find(root.right,k);
}
}
3.把二叉搜索樹轉換爲累加樹(題號:538) 第1次
題目描述:
給定一個二叉搜索樹(Binary Search Tree),把它轉換成爲累加樹(Greater Tree),使得每個節點的值是原來的節點值加上所有大於它的節點值之和。
解題思路:由於二叉搜索樹
代碼:
class Solution {
private int sum = 0;
public TreeNode convertBST(TreeNode root) {
if(root == null){
return root;
}
if(root.right != null) convertBST(root.right);
sum = sum + root.val;
root.val = sum;
if(root.left != null) convertBST(root.left);
return root;
}
}
4.二叉搜索樹的最近公共祖先(題號:235) 第1次
題目鏈接:二叉搜索樹的最近公共祖先
題目描述:
給定一個二叉搜索樹, 找到該樹中兩個指定節點的最近公共祖先。
解題思路:
代碼:
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null)
return null;
if(root.val > p.val && root.val > q.val) root = lowestCommonAncestor(root.left,p,q);
if(root.val < p.val && root.val < q.val) root = lowestCommonAncestor(root.right,p,q);
return root;
}
}
5.將有序數組轉換爲二叉搜索樹(題號:108) 第1次
題目鏈接:將有序數組轉換爲二叉搜索樹
題目描述:
將一個按照升序排列的有序數組,轉換爲一棵高度平衡二叉搜索樹。
本題中,一個高度平衡二叉樹是指一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過 1。
解題思路:這裏答案不唯一,比如數組長度爲偶數6,此時可以讓第3個或者第4個數作爲根節點的值,然後往後遞歸,若數組長度爲奇數,則直接讓中間的那個數作爲root節點的值。
代碼:
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return createTree(nums,0,nums.length-1);
}
public TreeNode createTree(int[] nums,int l,int r){
if(l > r)
return null;
int index = (l+r)/2;
TreeNode root = new TreeNode(nums[index]);
root.left = createTree(nums,l,index-1);
root.right = createTree(nums,index+1,r);
return root;
}
}
6.有序鏈表轉換二叉搜索樹(題號:109) 第0次
題目鏈接:有序鏈表轉換二叉搜索樹
題目描述:給定一個單鏈表,其中的元素按升序排序,將其轉換爲高度平衡的二叉搜索樹。
本題中,一個高度平衡二叉樹是指一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過 1。
解題思路:
代碼:
7.兩數之和 IV - 輸入 BST(題號:653) 第0次
題目鏈接:兩數之和 IV - 輸入 BST
題目描述:
給定一個二叉搜索樹和一個目標結果,如果 BST 中存在兩個元素且它們的和等於給定的目標結果,則返回 true。
解題思路:
代碼:
class Solution {
public boolean findTarget(TreeNode root, int k) {
List<Integer> list = new ArrayList<Integer>();
find(list,root);
for(int i = 0; i < list.size(); i++){
for(int j = 0; j < list.size(); j++){
if(i != j && k == (list.get(i) + list.get(j))){
return true;
}
}
}
return false;
}
public void find(List<Integer> list,TreeNode root){
if(root == null){
return ;
}
find(list,root.left);
list.add(root.val);
find(list,root.right);
}
}
8.二叉搜索樹的最小絕對差(題號:530) 第1次
題目鏈接:二叉搜索樹的最小絕對差
題目描述:
給定一個所有節點爲非負值的二叉搜索樹,求樹中任意兩節點的差的絕對值的最小值。
解題思路:
代碼:
我的代碼:比較垃圾
class Solution {
public int getMinimumDifference(TreeNode root) {
ArrayList<Integer> array = new ArrayList<Integer>();
find(array,root);
int index = 0;
int min = array.get(array.size()-1);
while(index < array.size() - 1){
min = Math.min(min,Math.abs(array.get(index) - array.get(index + 1)));
index++;
}
return min;
}
public void find(ArrayList<Integer> array,TreeNode root){
if(root == null){
return ;
}
find(array,root.left);
array.add(root.val);
find(array,root.right);
}
}