LeetCode——二叉樹(Java)

二叉樹

  • 簡介
  • [簡單] 144. 二叉樹的前序遍歷、94. 二叉樹的中序遍歷、145. 二叉樹的后序遍歷
  • 二叉樹層序遍歷
    • [中等] 102. 二叉樹的層序遍歷
    • [中等] 107. 二叉樹的層序遍歷 II
    • [中等] 199. 二叉樹的右視圖
    • [簡單] 637. 二叉樹的層平均值
    • [中等] 429. N 叉樹的層序遍歷
    • [中等] 515. 在每個樹行中找最大值
    • [中等] 116. 填充每個節點的下一個右側節點指針、[中等]117. 填充每個節點的下一個右側節點指針 II
    • [簡單] 104. 二叉樹的最大深度
    • [簡單] 111. 二叉樹的最小深度
  • [簡單] 226. 翻轉二叉樹
  • [簡單] 101. 對稱二叉樹
  • [簡單] 100. 相同的樹
  • [簡單] 572. 另一棵樹的子樹
  • [簡單] 222. 完全二叉樹的節點個數
  • [簡單] 110. 平衡二叉樹
  • [簡單] 257. 二叉樹的所有路徑

簡介

記錄一下自己刷題的歷程以及代碼。寫題過程中參考了 代碼隨想錄的刷題路線。會附上一些個人的思路,如果有錯誤,可以在評論區提醒一下。
涉及:二叉樹前中后序遍歷、層序遍歷、隊列Queue、頭插法、遞歸、ArrayList、LinkedList、遞歸、StringBuilder

[簡單] 144. 二叉樹的前序遍歷、94. 二叉樹的中序遍歷、145. 二叉樹的后序遍歷

144. 二叉樹的前序遍歷
94. 二叉樹的中序遍歷
145. 二叉樹的后序遍歷

前中后序遍歷可以公用一套遞歸思路,都是比較經典的模板:

//先序遍歷
遞歸訪問(){對節點做操作遞歸訪問(左子樹)遞歸訪問(右子樹)
}//中序遍歷
遞歸訪問(){遞歸訪問(左子樹)對節點做操作遞歸訪問(右子樹)
}//后序遍歷
遞歸訪問(){遞歸訪問(左子樹)遞歸訪問(右子樹)對節點做操作
}
  1. 二叉樹的前序遍歷
class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> answer = new ArrayList<>();preorder(root, answer);return answer;}public void preorder(TreeNode root, List<Integer> answer){if(root == null) return;answer.add(root.val);preorder(root.left,answer);preorder(root.right,answer);return;}
}
  1. 二叉樹的中序遍歷
class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> answer = new ArrayList<>();inorder(root, answer);return answer;}public void inorder(TreeNode root, List<Integer> answer){if(root == null) return;inorder(root.left,answer);answer.add(root.val);inorder(root.right,answer);return;}
}
  1. 二叉樹的后序遍歷
class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> answer = new ArrayList<>();postorder(root, answer);return answer;}public void postorder(TreeNode root, List<Integer> answer){if(root == null) return;postorder(root.left,answer);postorder(root.right,answer);answer.add(root.val);return;}
}

二叉樹層序遍歷

[中等] 102. 二叉樹的層序遍歷

原題鏈接

經典的BFS
用隊列保存樹節點,每次統計隊列的size(),也就是第n層節點數量。
處理這一層的節點,將其子節點全部加入隊列,循環往復到隊列為空。

class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> ans = new ArrayList<List<Integer>>();Queue<TreeNode> queue = new ArrayDeque<>();if(root == null) return ans;queue.add(root);while(!queue.isEmpty()){List<Integer> nums = new ArrayList<Integer>();int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();nums.add(temp.val);if (temp.left != null) queue.add(temp.left);if (temp.right != null) queue.add(temp.right);}ans.add(nums);}return ans;}
}

[中等] 107. 二叉樹的層序遍歷 II

原題鏈接

方法①:
與102的最基本的層序遍歷相似的邏輯,使用遞歸的方法把每次ans.add(nums);操作順序進行了倒序。

class Solution {public List<List<Integer>> levelOrderBottom(TreeNode root) {List<List<Integer>> ans = new ArrayList<List<Integer>>();Queue<TreeNode> queue = new ArrayDeque<>();if(root == null) return ans;queue.add(root);recursion(queue, ans);return ans;}public void recursion(Queue<TreeNode> queue, List<List<Integer>> ans){if(!queue.isEmpty()){List<Integer> nums = new ArrayList<Integer>();int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();nums.add(temp.val);if (temp.left != null) queue.add(temp.left);if (temp.right != null) queue.add(temp.right);}recursion(queue, ans);ans.add(nums);}return;}
}

方法②:
使用LinkedList,用頭插法的方式構造返回值。(LinkedList底層為鏈表,頭插法比較方便,ArrayList底層是連續存儲,頭插法復雜度為O(n))

class Solution {public List<List<Integer>> levelOrderBottom(TreeNode root) {List<List<Integer>> ans = new LinkedList<>();Queue<TreeNode> queue = new ArrayDeque<>();if(root == null) return ans;queue.add(root);while(!queue.isEmpty()){List<Integer> nums = new ArrayList<Integer>();int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();nums.add(temp.val);if (temp.left != null) queue.add(temp.left);if (temp.right != null) queue.add(temp.right);}ans.add(0, nums);}return ans;}}

[中等] 199. 二叉樹的右視圖

原題鏈接

與102的最基本的層序遍歷相似的邏輯,構建返回值時每次只把當前層最右邊的數加入ans即可。

class Solution {public List<Integer> rightSideView(TreeNode root) {List<Integer> ans = new ArrayList<Integer>();Queue<TreeNode> queue = new ArrayDeque<>();if(root == null) return ans;queue.add(root);while(!queue.isEmpty()){List<Integer> nums = new ArrayList<Integer>();int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();nums.add(temp.val);if (temp.left != null) queue.add(temp.left);if (temp.right != null) queue.add(temp.right);}ans.add((nums.get(nums.size()-1)));}return ans;}
}

[簡單] 637. 二叉樹的層平均值

原題鏈接

class Solution {public List<Double> averageOfLevels(TreeNode root) {Queue<TreeNode> queue = new ArrayDeque<>();List<Double> ans = new ArrayList<>();if(root == null) return ans;queue.add(root);while(!queue.isEmpty()){double num = 0;int k = queue.size();int i = k;while(k-- > 0){TreeNode temp = queue.remove();num += temp.val;if(temp.left != null) queue.add(temp.left);if(temp.right != null) queue.add(temp.right);}ans.add(num / i);}return ans;}
}

[中等] 429. N 叉樹的層序遍歷

原題鏈接

class Solution {public List<List<Integer>> levelOrder(Node root) {List<List<Integer>> ans = new ArrayList<List<Integer>>();Queue<Node> queue = new ArrayDeque<>();if(root == null) return ans;queue.add(root);while(!queue.isEmpty()){List<Integer> nums = new ArrayList<Integer>();int k = queue.size();while(k-- > 0) {Node temp = queue.remove();nums.add(temp.val);for(int i = 0; i < temp.children.size(); i++) {queue.add(temp.children.get(i));}}ans.add(nums);}return ans;}
}

[中等] 515. 在每個樹行中找最大值

原題鏈接

class Solution {public List<Integer> largestValues(TreeNode root) {List<Integer> ans = new ArrayList<>();Queue<TreeNode> queue = new ArrayDeque<>();if(root == null) return ans;queue.add(root);while(!queue.isEmpty()){int max = queue.peek().val;int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();max = max > temp.val ? max : temp.val;if(temp.left != null) queue.add(temp.left);if(temp.right != null) queue.add(temp.right);}ans.add(max);}return ans;}
}

[中等] 116. 填充每個節點的下一個右側節點指針、[中等]117. 填充每個節點的下一個右側節點指針 II

[中等] 116. 填充每個節點的下一個右側節點指針
[中等]117. 填充每個節點的下一個右側節點指針 II
方法①:
正常的層序遍歷,每層除了最后一個節點之外都對next賦值

class Solution {public Node connect(Node root) {List<Integer> ans = new ArrayList<>();Queue<Node> queue = new ArrayDeque<>();if(root == null) return root;queue.add(root);while(!queue.isEmpty()){int k = queue.size();while(k-- > 0) {Node temp = queue.remove();if(k > 0) {temp.next = queue.peek();}if(temp.left != null) queue.add(temp.left);if(temp.right != null) queue.add(temp.right);}}return root;}
}

方法②:
使用next鏈接來對同層次節點做遍歷,可以省去隊列的開銷
注意Node引用需要申請在方法外,不能做參數傳遞,java中都是值傳遞

class Solution {Node last = null, nextStart = null;public Node connect(Node root) {List<Integer> ans = new ArrayList<>();if(root == null) return root;Node p = root;while(p!=null){if(p.left != null){handle(p.left);}if(p.right != null){handle(p.right);}p = p.next;if(p == null && nextStart != null){p = nextStart;nextStart = null;last = null;}}return root;}public void handle(Node p){if(nextStart == null){nextStart = p;}if(last != null){last.next = p;}last = p;}}

[簡單] 104. 二叉樹的最大深度

原題鏈接

方法①:層序遍歷

class Solution {public int maxDepth(TreeNode root) {int depth = 0;if(root == null) return depth;Queue<TreeNode> queue = new ArrayDeque<>();queue.add(root);while(!queue.isEmpty()){depth++;int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();if (temp.left != null) queue.add(temp.left);if (temp.right != null) queue.add(temp.right);}}return depth;}
}

方法②:遞歸
樹的高度就是 其子樹的最大高度 + 1,用在多叉樹上也是一樣的思路

class Solution {public int maxDepth(TreeNode root) {if(root == null) return 0;int leftDepth = maxDepth(root.left);int rightDepth = maxDepth(root.right);return (leftDepth > rightDepth ? leftDepth : rightDepth) + 1;}
}

[簡單] 111. 二叉樹的最小深度

原題鏈接
方法①:層序遍歷找左右子樹皆空的點即可

class Solution {public int minDepth(TreeNode root) {int depth = 0;if(root == null) return depth;Queue<TreeNode> queue = new ArrayDeque<>();queue.add(root);while(!queue.isEmpty()){depth++;int k = queue.size();while(k-- > 0) {TreeNode temp = queue.remove();if(temp.left == null && temp.right == null) return depth;if (temp.left != null) queue.add(temp.left);if (temp.right != null) queue.add(temp.right);}}return depth;}
}

方法②:遞歸求解
用遞歸求解記住需要的是到葉子節點的深度
如果非葉子節點,假設只有單邊左子樹,右子數應當是找不到葉子節點也就是距離無窮大,可以設置一個Integer.MAX_VALUE做為返回值,這樣通過比較,遞歸的上一層就會獲得左子樹找到葉子節點的最小距離 + 1

class Solution {public int minDepth(TreeNode root) {if(root == null) return 0;if(root.left == null && root.right == null) return 1;int leftMin = Integer.MAX_VALUE;int rightMin = Integer.MAX_VALUE;if(root.left != null) leftMin = minDepth(root.left);if(root.right != null) rightMin = minDepth(root.right);return (leftMin < rightMin ? leftMin : rightMin) + 1;}
}

[簡單] 226. 翻轉二叉樹

原題鏈接

前序遍歷的基礎上每一次遍歷節點做翻轉操作。
切記前序、后續、層次遍歷都可以,但是不可以是中序遍歷,因為中序遍歷是左 中 右 的順序,遞歸調整左子樹之后,處理當前節點會把左右子樹對調,這樣進入右子數遞歸時其實還是對原先的左子樹做操作。

class Solution {public TreeNode invertTree(TreeNode root) {preorder(root);return root;}public void preorder(TreeNode root){if(root == null) return;TreeNode temp = root.left;root.left = root.right;root.right = temp;preorder(root.left);preorder(root.right);return;}
}

[簡單] 101. 對稱二叉樹

原題鏈接

經典的遞歸思路,對左右子樹做反方向的遞歸即可,在左子樹上做前序遍歷,每次遞歸left的左節點時就去遞歸right的右節點,遞歸left的右節點時則遞歸right的左節點。

class Solution {public boolean isSymmetric(TreeNode root) {if(root == null) return true;TreeNode left = root.left;TreeNode right = root.right;return recursion(left, right);}public boolean recursion(TreeNode left, TreeNode right){if(left == null && right == null)return true;else if(left != null && right != null) {if (left.val != right.val)return false;if (recursion(left.left, right.right) && recursion(left.right, right.left))return true;}return false;}
}

[簡單] 100. 相同的樹

原題鏈接

兩棵樹同頻做前序遍歷即可,其他遍歷方式也是ok的。

class Solution {public boolean isSameTree(TreeNode p, TreeNode q) {return recursion(p, q);}public boolean recursion(TreeNode p, TreeNode q){if(p == null && q == null)return true;else if(p != null && q != null) {if (p.val != q.val)return false;if (recursion(p.left, q.left) && recursion(p.right, q.right))return true;}return false;}
}

[簡單] 572. 另一棵樹的子樹

原題鏈接

兩層遞歸
①preorder:對root 的前序遍歷,找到與subRoot相同值的節點,作為比較的起點②cmprecursion:對root的節點以及subRoot的根節點 做 同頻前序遍歷對比

class Solution {public boolean isSubtree(TreeNode root, TreeNode subRoot) {if(subRoot == null) return true;if(root == null) return true;return preorder(root, subRoot);}public boolean preorder(TreeNode p, TreeNode q){if(p == null) return false;if(p.val == q.val && cmprecursion(p, q))return true;if(preorder(p.left, q) || preorder(p.right, q)) return true;return false;}public boolean cmprecursion(TreeNode p, TreeNode q){if(p == null && q == null) return true;else if(p != null && q != null){if(p.val != q.val) return false;if(cmprecursion(p.left, q.left) && cmprecursion(p.right, q.right))return true;}return false;}
}

[簡單] 222. 完全二叉樹的節點個數

原題鏈接

遞歸

class Solution {public int countNodes(TreeNode root) {if(root == null) return 0;return countNodes(root.left) + countNodes(root.right) + 1;}
}

[簡單] 110. 平衡二叉樹

原題鏈接

遞歸,后序遍歷
用-2標記 以當前節點為根節點的子樹非平衡二叉樹,在遞歸中一旦出現-2就層層傳遞到root,用來標識存在子樹為非平衡二叉樹

class Solution {public boolean isBalanced(TreeNode root) {if(countDepth(root) == -2) return false;return true;}public int countDepth(TreeNode p){if(p == null) return 0;int leftDepth = countDepth(p.left);int rightDepth = countDepth(p.right);int flag = leftDepth - rightDepth;if(leftDepth == -2 || rightDepth == -2 || flag > 1 || flag < -1) return -2;else return (leftDepth > rightDepth ? leftDepth : rightDepth) + 1;}
}

[簡單] 257. 二叉樹的所有路徑

原題鏈接

思路就是DFS深度優先遍歷找到每一條路徑,效率差異主要體現在對字符串拼接的處理上,使用StringBuilder會更高效一些。
在這里插入圖片描述

class Solution {public List<String> binaryTreePaths(TreeNode root) {List<String> ans = new ArrayList<>();if(root == null) return ans;DFS(root, ans, "");return ans;}public void DFS(TreeNode p, List<String> ans, String string){StringBuilder sb = new StringBuilder(string);sb.append(p.val);if(p.left == null && p.right == null){ans.add(sb.toString());return;}sb.append("->");if(p.left != null)DFS(p.left, ans, sb.toString());if(p.right != null)DFS(p.right, ans, sb.toString());}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/716973.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/716973.shtml
英文地址,請注明出處:http://en.pswp.cn/news/716973.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java接口

接口的定義 抽象方法的集合&#xff0c;接口通常以interface來聲明。一個類通過繼承接口的方式&#xff0c;從而來繼承接口的抽象方法。 接口并不是類&#xff0c;編寫接口的方式和類很相似&#xff0c;但是他們屬于不同的概念。類描述的是對象的屬性和方法。接口則包含類要實…

AcWing 4726. 尋找數字

解題思路 在這個二插搜索樹中尋找&#xff0c;4和7數量相等&#xff0c;并且大于n的最小數。 相關代碼 import java.util.*;public class Main {static String s;static List<Integer> res new ArrayList<>();static long n;static long ansLong.MAX_VALUE;publ…

遞歸實現指數型枚舉(c++題解)

題目描述 從 1~n 這 n(n<16) 個整數中隨機選取任意多個&#xff0c;輸出所有可能的選擇方案。 輸入格式 一個整數n。 輸出格式 每行一種方案。同一行內的數必須升序排列&#xff0c;相鄰兩個數用恰好1個空格隔開。對于沒有選任何數的方案&#xff0c;輸出空行。 樣例 …

python 爬蟲 app爬取之charles的使用

專欄系列:http://t.csdnimg.cn/WfCSx 前言 前面介紹的都是爬取 Web 網頁的內容。隨著移動互聯網的發展,越來越多的企業并沒有提供 Web 網頁端的服務,而是直接開發了 App,更多更全的信息都是通過 App 來展示的。那么針對 App 我們可以爬取嗎?當然可以。 App 的爬取相比 …

使用HTML5畫布(Canvas)模擬圖層(Layers)效果

使用HTML5畫布&#xff08;Canvas&#xff09;模擬圖層&#xff08;Layers&#xff09;效果 在圖形處理和計算機圖形學中&#xff0c;圖層&#xff08;Layers&#xff09;是指將圖像分成不同的可獨立編輯、組合和控制的部分的技術或概念。每個圖層都可以包含不同的圖形元素、效…

18.題目:編號760 數的計算

題目&#xff1a; ###該題主要考察遞推、遞歸 將該題看成若干個子問題 #include<bits/stdc.h> using namespace std; const int N20; int a[N];int dfs(int dep){int res1;for(int i1;i<a[dep-1]/2;i){a[dep]i;resdfs(dep1);}return res; }int main(){int n;cin>…

python并發 map函數的妙用

1.map是什么&#xff1f; map函數是Python中的一個內置函數&#xff0c;用于將一個函數應用到一個或多個可迭代對象的每個元素上&#xff0c;生成一個新的可迭代對象。它的一般形式是&#xff1a; map(function, iterable1, iterable2, ...)其中&#xff0c;function是一個函…

解決GCC連接器(lld)出現問題 relocation truncated to fit (重定向截斷)

本文大致提點這個問題&#xff0c;有哪些可行的解決方案。 這是常見 C/C 的一類連接器錯誤&#xff0c;我們需要知道它一般是怎么產生的&#xff0c;才能知道如何正確的解決它。 例如&#xff1a;&#xff08;當發生這類問題時&#xff0c;連接器通常會輸出這樣的信息&#x…

《Spring Security 簡易速速上手小冊》第8章 常見問題與解決方案(2024 最新版)

文章目錄 8.1 異常處理和日志記錄8.1.1 基礎知識詳解8.1.2 重點案例&#xff1a;統一異常處理案例 Demo拓展 8.1.3 拓展案例 1&#xff1a;日志記錄策略案例 Demo拓展 8.1.4 拓展案例 2&#xff1a;日志聚合案例 Demo拓展 8.2 多租戶安全性問題8.2.1 基礎知識詳解8.2.2 重點案例…

深入Kafka client

分區分配策略 客戶端可以自定義分區分配策略, 當然也需要考慮分區消費之后的offset提交, 是否有沖突。 消費者協調器和組協調器 a. 消費者的不同分區策略, 消費者之間的負載均衡(新消費者加入或者存量消費者退出), 需要broker做必要的協調。 b. Kafka按照消費組管理消費者, …

VUE3:省市區聯級選擇器

一、實現效果 二、代碼展示 <template><div class"page"><select v-model"property.province"><option v-for"item in provinces" :key"item">{{ item }}</option></select><select v-model&…

今日學習總結2024.3.2

最近的學習狀態比較好&#xff0c;感覺非常享受知識進入腦子的過程&#xff0c;有點上頭。 實驗室一個星期唯一一天的假期周六&#xff0c;也就是今天&#xff0c;也完全不想放假出去玩啊&#xff0c;在實驗室泡了一天。 很后悔之前膽小&#xff0c;沒有提前投簡歷找實習&…

YOLOv9有效提點|加入MobileViT 、SK 、Double Attention Networks、CoTAttention等幾十種注意力機制(五)

專欄介紹&#xff1a;YOLOv9改進系列 | 包含深度學習最新創新&#xff0c;主力高效漲點&#xff01;&#xff01;&#xff01; 一、本文介紹 本文只有代碼及注意力模塊簡介&#xff0c;YOLOv9中的添加教程&#xff1a;可以看這篇文章。 YOLOv9有效提點|加入SE、CBAM、ECA、SimA…

ETH網絡中的區塊鏈

回顧BTC網絡的區塊鏈系統 什么是區塊鏈&#xff1f;BTC網絡是如何運行的&#xff1f;BTC交易模式 - UXTO ETH網絡中的區塊鏈 ETH網絡的基石依舊是 區塊鏈。上面 什么是區塊鏈&#xff1f; 的文章依舊適用。 相比BTC網絡&#xff0c;ETH網絡的賬戶系統就相對復雜&#xff0c;所…

ZJGSU 1199 表達式計算

題目描述 在數據結構課上&#xff0c;老師給大家布置了一個表達式計算的問題 3*21*5. Its so easy!!! csw同學做了很不過癮&#xff0c;他想求解更復雜的表達式: 比如(123456)/789. 但一時之間他想不出好的辦法&#xff0c;諸位就幫幫他吧. 輸入 輸入包括多組數據, 每組測試…

實用工具:實時監控服務器CPU負載狀態并郵件通知并啟用開機自啟

作用&#xff1a;在服務器CPU高負載時發送郵件通知 目錄 一、功能代碼 二、配置開機自啟動該監控腳本 1&#xff0c;配置自啟腳本 2&#xff0c;啟動 三、功能測試 一、功能代碼 功能&#xff1a;在CPU負載超過預設置的90%閾值時就發送郵件通知&#xff01;郵件內容顯示…

【Spring連載】使用Spring Data訪問 MongoDB----對象映射之屬性轉換器

【Spring連載】使用Spring Data訪問 MongoDB----對象映射之屬性轉換器 一、聲明式值轉換器二、編程式值轉換器注冊三、MongoCustomConversions配置 雖然基于類型的轉換已經提供了影響目標存儲中某些類型的轉換和表示的方法&#xff0c;但當僅考慮特定類型的某些值或屬性進行轉換…

js中Generator函數詳解

定義&#xff1a; promise是為了解決回調地獄的難題出現的&#xff0c;那么 Generator 就是為了解決異步問題而出現的。 普通函數&#xff0c;如果調用它會立即執行完畢&#xff1b;Generator 函數&#xff0c;它可以暫停&#xff0c;不一定馬上把函數體中的所有代碼執行完畢…

Linux基本指令(下)

目錄 1. less指令 2. head與tail指令 3. find指令 示例 4. grep指令 示例 ?編輯 5. zip/unzip 打包與壓縮 示例 ?編輯 6. tar指令 7. find指令&#xff1a; -name 8. echo指令 9. 時間相關的指令 1.在顯示方面&#xff0c;使用者可以設定欲顯示的格式&#xff…

分布式ID(6):Redis實現分布式ID生成

Redis是一個高性能的鍵值數據庫,它可以用于生成分布式唯一標識符。需要注意的是Redis實現ID可以用,這也是很多公司的選擇。但是在redis服務器宕機的情況下,他也可能會出現重復生成ID的情況。 1 實現原理 利用Redis的原子操作:Redis提供了原子性的INCR和INCRBY命令,可用于…