java算法day11

  • 二叉樹的遞歸遍歷
  • 二叉樹的非遞歸遍歷寫法
  • 層序遍歷

遞歸怎么寫?

按照三要素可以保證寫出正確的遞歸算法:

1.確定遞歸函數的參數和返回值: 確定哪些參數是遞歸的過程中需要處理的,那么就在遞歸函數里加上這個參數, 并且還要明確每次遞歸的返回值是什么進而確定遞歸函數的返回類型。

2.確定終止條件: 寫完了遞歸算法, 運行的時候,經常會遇到棧溢出的錯誤,就是沒寫終止條件或者終止條件寫的不對,操作系統也是用一個棧的結構來保存每一層遞歸的信息,如果遞歸沒有終止,操作系統的內存棧必然就會溢出。

3.確定單層遞歸的邏輯: 確定每一層遞歸需要處理的信息。在這里也就會重復調用自己來實現遞歸的過程。


前置必會

一定要會自己寫出樹的類定義

public class TreeNode{TreeNode left;TreeNode right;int val;TreeNode(){}TreeNode(int val){this.val = val}TreeNode(int val,TreeNode right,TreeNode left){this.val = val;this.left = left;this.right = right;
}

144.二叉樹的前序遍歷

遞歸寫法

class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();dfs(root,result);return result;}void dfs(TreeNode root,List<Integer> result){if(root==null){return;}result.add(root.val);dfs(root.left,result);dfs(root.right,result);}}

非遞歸寫法:
我認為就是記思路。
1.用一個棧作為輔助。
2.前序遍歷是根左右,每次先處理的是中間節點,那么先將根節點放入棧中,然后將右孩子加入棧,再加入左孩子。之所以是反過來是因為,這樣出棧的時候才是根左右的順序。直接來看圖模擬
請添加圖片描述
即每次在處理根節點的時候,將根節點出隊,然后將其右孩子先進棧,再將左孩子進棧。
這樣進行處理之后,出棧的結果就會是前序遍歷的結果。

如果還是不懂,我建議直接結合代碼,然后結合上面圖,記下來這個做法。我覺得這個直接想是不好想的。

非遞歸其實就是用輔助數據結構,配合循環

class Solution {public List<Integer> preorderTraversal(TreeNode root) {//結果集List<Integer> result = new ArrayList<>();//特判if(root == null){return result;}//創建輔助棧Deque<TreeNode> st = new ArrayDeque<>();//根節點先入棧st.push(root);//當棧不空的時候while(!st.isEmpty()){//先處理根節點,即將根節點出棧。這就對應著根TreeNode node = st.pop();//將出棧的根節點加入結果集result.add(node.val);//先將右節點加入棧中,可以這么想,早點加入,那么就晚點出。所以右節點出的時候,要比左節點晚,那么這里出也就是和上面節點出棧一個道理。所以這里就完成了根左右里面的根左。因為左節點進的晚,出的就早。if(node.right!=null){st.push(node.right);}//然后才是到左節點,晚點進就可以早點出。if(node.left!=null){st.push(node.left);}}return result;}
}

這是我第二寫總結的流程:
1.初始化
創建一個空的結果列表
創建一個輔助棧
將根節點壓入棧中

2.主循環: 當棧不為空時,執行以下操作:

a. 處理當前節點:
從棧中彈出一個節點
將該節點的值添加到結果列表中

b. 壓入子節點:
如果該節點有右子節點,將右子節點壓入棧中
如果該節點有左子節點,將左子節點壓入棧中
返回結果列表

這種方法的關鍵點在于
根節點最先被處理,這符合前序遍歷的"根-左-右"順序。
右子節點先于左子節點入棧,這確保了左子節點會先于右子節點被處理。
這種非遞歸方法的優點是:

避免了遞歸調用的開銷
對于深度很大的樹,可以防止棧溢出
實現簡單,易于理解
與中序遍歷的非遞歸方法相比,前序遍歷的非遞歸實現更為直觀,因為它可以直接按照遍歷順序處理節點,而不需要像中序遍歷那樣先到達最左節點。

145.二叉樹的后序遍歷

遞歸寫法

class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> result  = new ArrayList<>();dfs(root,result);return result;}public void dfs(TreeNode root,List<Integer> result){if(root==null){return;}dfs(root.left,result);dfs(root.right,result);result.add(root.val);}
}

非遞歸寫法:
這個解法是一個技巧解。
由于前序遍歷是根左右,而后續遍歷是左右根。所以如果調整一下前序遍歷的順序,先加左節點,再加右節點,那么得到的結果就是按根右左規則得到的。所以此時做翻轉,那么得到的結果就是按左右根得到的結果。與后序遍歷的結果不謀而合。
所以解法就是線序遍歷調整左右入棧方式,然后再對最終結果做翻轉。

class Solution {public List<Integer> postorderTraversal(TreeNode root) {Deque<TreeNode> st = new ArrayDeque<>();List<Integer> result = new ArrayList<>();if(root==null){return result;}st.push(root);while(!st.isEmpty()){TreeNode node = st.pop();result.add(node.val);if(node.left!=null){st.push(node.left);}if(node.right!=null){st.push(node.right);}}Collections.reverse(result);return result;}
}

94.二叉樹的中序遍歷

遞歸寫法

class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();dfs(root,result);return result;}public void dfs(TreeNode root,List<Integer> result){if(root==null){return;}dfs(root.left,result);result.add(root.val);dfs(root.right,result);}
}

非遞歸寫法:
看這個圖,然后結合圖片,記下這個做法:
請添加圖片描述
1.初始化
創建一個空的結果列表和一個空的棧
將當前節點設置為根節點

2.主循環: 當當前節點不為空或棧不為空時,執行以下操作:

a. 左子樹遍歷
如果當前節點不為空
將當前節點壓入棧
移動到左子節點

b. 節點處理
如果當前節點為空(即已經到達最左端)
從棧中彈出一個節點
將該節點的值添加到結果列表中
將當前節點移動到右子節點

3.返回結果列表

這種方法模擬了遞歸的過程:

首先盡可能深入地遍歷左子樹
然后處理節點本身
最后遍歷右子樹
使用棧來保存已經遍歷過的父節點,以便在處理完左子樹后能夠回溯。

還是按代碼思維走一遍,又和自己想的還是有一點區別。

class Solution {public List<Integer> inorderTraversal(TreeNode root) {//結果集List<Integer> result = new ArrayList<>();//特判if(root==null){return result;}//輔助棧Deque<TreeNode> st = new ArrayDeque<>();//用一個遍歷指針指向rootTreeNode cur = root;//這里就是進遞歸處理的邏輯,循環條件決定了能不能遞歸處理下去。//cur!=null表明這個元素不空,可以進棧,!st.isEmpty(),是用來回溯的,表明棧中還有走過的元素需要進行處理。所以棧中走過的元素沒處理完也要繼續處理。while(cur!=null || !st.isEmpty()){//根據中序,左根右的走法,需要一路向最左下走。走的過程就一直入棧,保存之前的狀態。如果cur==null,說明走到最左下的節點的左分支上了,也就是null。if(cur!=null){st.push(cur);cur = cur.left;}else{//不能繼續往左走了才處理這里,這里就是開始回溯,回溯一下回到最左下的節點,此節點并不是null。那就把這個元素出棧,把這個元素的val加入結果集。由于每個元素都要左根右,這里處理了根節點,那還要往右節點走。下一波顯然cur還是null,那么此時就會彈出沿著路線返回的根節點,往后都是這樣。注意是依靠彈出的節點進行轉移,因為棧里面的節點才是記錄先前的狀態,別自己瞎寫一個。cur = st.pop();result.add(cur.val);cur = cur.right;}}//當st里面為空的時候,就是所有節點都處理完的時候。return result;}
}

102.二叉樹的層序遍歷

用隊列。
看一個圖就懂了。請添加圖片描述
隊列先進先出,符合一層一層遍歷的邏輯。
下面的代碼就是二叉樹層序遍歷的模板題,會這個模板,之后遇到只要是層序遍歷的題,隨便殺。

總的來說,這個解法看完,里面的len的處理我是當時沒想到的。

class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> result = new ArrayList<>();checkFun(root,result);return result;}public void checkFun(TreeNode node,List<List<Integer>> result){//特判if(node==null){return;}//輔助隊列Deque<TreeNode> que = new ArrayDeque<>();//根節點先入隊que.offerLast(node);//隊列不空就代表流程還沒有結束while(!que.isEmpty()){//記錄一層元素的結果集List<Integer> itemList = new ArrayList<Integer>();//在一開始先記錄長度,該長度即隊列目前的長度,就是該層元素的個數。//記錄len就是為了做一個界限,即處理完這一層元素后,就要收集一次結果集。int len = que.size();//這個循環做依次將該層元素出隊,并擴展其左右節點加入隊列當中。while(len>0){//先出隊TreeNode tmpNode = que.pollFirst();//加入結果集itemList.add(tmpNode.val);//擴展左右節點,加入隊列中。if(tmpNode.left!=null){que.offerLast(tmpNode.left);}if(tmpNode.right!=null){que.offerLast(tmpNode.right);}//做完之后該層元素數量要-1len--;}//處理完一層后記錄一次結果。result.add(itemList);}}
}

107.二叉樹的層序遍歷Ⅱ

在上題的基礎上將結果集翻轉就結束了。

class Solution {public List<List<Integer>> levelOrderBottom(TreeNode root) {List<List<Integer>> result = new ArrayList<>();checkFun(root,result);Collections.reverse(result);return result;}public void checkFun(TreeNode node,List<List<Integer>> result){if(node==null){return;}Deque<TreeNode> que = new ArrayDeque<>();que.offerLast(node);while(!que.isEmpty()){List<Integer> itemList = new ArrayList<Integer>();int len = que.size();while(len>0){TreeNode tmpNode = que.pollFirst();itemList.add(tmpNode.val);if(tmpNode.left!=null){que.offerLast(tmpNode.left);}if(tmpNode.right!=null){que.offerLast(tmpNode.right);}len--;}result.add(itemList);}}
}

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

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

相關文章

第二證券:銷量暴跌95%,這一巨頭市值蒸發超3000億元!

在多重要素刺激下&#xff0c;PCB工作站上風口。 波音銷量墮入停滯 6月僅售出3架客機 據央視財經&#xff0c;在一系列丑聞的影響下&#xff0c;波音公司本年出售遭到明顯沖擊。當地時間9日&#xff0c;波音發布的數據閃現&#xff0c;在以前一個月&#xff0c;該公司僅賣出…

關于Java面向對象的一些問題(2024.7.10)

package question20240710;public class Question {/*1. 什么叫做多態&#xff0c;條件是什么&#xff1f;2. 使用多態特性&#xff0c;帶來了什么樣的好處&#xff1f;3. 使用多態特性&#xff0c;注意什么樣的弊端&#xff1f;4. 關于多態的弊端我們如何解決&#xff1f;5. 在…

excel有條件提取單元格特定文本(篩選純文字的單元格或含有數字的單元格、單元格提取不同的文本長度)

實際工作背景 需要對導出的銀行流水中的數十個村以及對應的村小組進行分組統計&#xff0c;但是初始的表格中村和小組是混在一起的&#xff0c;如下圖所示&#xff1a; 目的&#xff1a;將大樹村和大樹村小組名稱分別篩選出來 1.觀察發現&#xff0c;大樹村小組的單元格第4…

代碼隨想錄算法訓練營第四十九天| 647. 回文子串、 516.最長回文子序列

647. 回文子串 題目鏈接&#xff1a;647. 回文子串 文檔講解&#xff1a;代碼隨想錄 狀態&#xff1a;不會 思路&#xff1a; dp[i][j] 表示字符串 s 從索引 i 到索引 j 這一段子串是否為回文子串。 當s[i]與s[j]不相等&#xff0c;那沒啥好說的了&#xff0c;dp[i][j]一定是fa…

構建與操作共享棧

歸納編程學習的感悟, 記錄奮斗路上的點滴, 希望能幫到一樣刻苦的你! 如有不足歡迎指正! 共同學習交流! ??歡迎各位→點贊 ??+ 收藏? + 留言???既然選擇了遠方,當不負青春,砥礪前行! 共享棧是一種優化的棧實現方式,它允許兩個或多個棧共享同一段連續的內存空間…

Tkinter 部件使用教程

tkinter學習教程 C語言中文網Tkinter教程 菜鳥編程-Python GUI編程(Tkinter) tkinter基本組件 messagebox 【tkinter標準對話框】messagebox&#xff1a;信息傳遞&#xff0c;消息對話框&#xff01; bind bind事件信息 listbox Tkinter 組件詳解之Listbox radiobutton Tkinter…

數據結構——Trie

題目&#xff1a; 維護一個字符串集合&#xff0c;支持兩種操作&#xff1a; I x 向集合中插入一個字符串 x&#x1d465;&#xff1b;Q x 詢問一個字符串在集合中出現了多少次。 共有 N&#x1d441; 個操作&#xff0c;所有輸入的字符串總長度不超過 10^5&#xff0c;字符串僅…

【分布式系統】Ceph對象存儲系統之RGW接口

目錄 一.對象存儲概述 二.創建RGW接口 1.在管理節點創建一個 RGW 守護進程 2.創建成功后默認情況下會自動創建一系列用于 RGW 的存儲池 3.默認情況下 RGW 監聽 7480 號端口 4.開啟 httphttps &#xff0c;更改監聽端口 5.在 rgw 節點上查看端口 6.在客戶端訪問驗證 7.…

Mybatis study

一、Mybatis Plus mybatis-plus指定實體類字段不查詢 加標簽 TableField(exist false) Spring Data Jpa學習 干我們這行&#xff0c;啥時候懈怠&#xff0c;就意味著長進的停止&#xff0c;長進的停止就意味著被淘汰&#xff0c;只能往前沖&#xff0c;直到鳳凰涅槃的一天&am…

【onnx】onnxruntime-gpu無法使用問題

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 onnxruntime-gpu無法使用 1. 正文 CUDA版本&#xff1a;12.1 nvcc -VCUDNN的版本 cat /usr/include/cudnn_version.h |grep CUDNN_MAJOR -A 2說明: 可…

C#中的Dictionary

Dictionary<TKey, TValue> 是一個泛型集合&#xff0c;它存儲鍵值對&#xff08;key-value pairs&#xff09;&#xff0c;其中每個鍵&#xff08;key&#xff09;都是唯一的。這個集合類提供了快速的數據插入和檢索功能&#xff0c;因為它是基于哈希表實現的。 注意 ke…

拉曼操作維護使用手冊(中英文對照)

1 INTRODUCTION 介紹 This document contains information needed to install and operate the Laser Gas Analyzer (LGA). The information contained herein is believed to be accurate and reliable, however, inaccuracies and omissions of pertinent information are po…

Vue 3 組件通信全解:從基礎到高級技巧

引言 Vue 3 引入了 Composition API&#xff0c;這為組件通信帶來了新的靈活性和強大的功能。 組件通信基礎 組件的定義和作用 在前端開發中&#xff0c;組件可以被看作是構建用戶界面的獨立單元。它封裝了特定的功能和樣式&#xff0c;可以被重復使用&#xff0c;并且可以…

【數據結構——鏈表的深度探索】從實現到應用,保姆級攻略

【數據結構——鏈表深度探索】從實現到應用&#xff0c;保姆級攻略 &#x1f341;1. 鏈表的介紹&#x1f341;2. 鏈表的實現&#x1f341;2.1 單向鏈表&#x1f341;2.1.1 size()&#x1f341;2.1.2 display()&#x1f341;2.1.3 contains(int key)&#x1f341;2.1.4 addFirst…

墨西哥:海外新聞稿媒體分發-海外pr發稿干貨分享-大舍傳媒

大舍傳媒&#xff1a;海外新聞稿媒體分發平臺 墨西哥觀查者 (mexicoviewer) 墨西哥觀查者是墨西哥一家知名的新聞媒體平臺&#xff0c;該平臺專注于報道墨西哥國內外的時事新聞、政治、經濟、文化等多個領域的內容。其更新速度快&#xff0c;報道對象廣泛&#xff0c;深受墨西…

微信小程序---模板語法

一、聲明和綁定數據 小程序頁面中使用的數據均需要在 Page() 方法的 data 對象中進行聲明定義 在將數據聲明好以后&#xff0c;需要在 WXML 中綁定數據&#xff0c;數據綁定最簡單的方式是使用 Mustache 語法&#xff08;雙大括號&#xff09;將變量包起來。 在 {{ }} 內部可…

開始性能測試之前的準備工作!

性能測試是軟件測試中不可或缺的一部分&#xff0c;它可以幫助我們評估軟件系統的性能表現&#xff0c;并找出潛在的性能瓶頸。在進行性能測試之前&#xff0c;需要做好充分的準備工作&#xff0c;以確保測試的有效性和準確性。 1. 確定性能測試的目標和范圍 * 明確測試目標:性…

《數據庫原理》SQLServer期末復習_題型+考點

目錄 題型&#xff1a; 一. 概況分析題&#xff08;5小題&#xff0c;每小題2分&#xff0c;共10分&#xff09; 二. 計算題&#xff08;3小題&#xff0c;每小題5分&#xff0c;共15分&#xff09; 三. 數據庫設計&#xff08;2小題&#xff0c;每小題10分&#xff0c;共2…

什么是數組,什么是對象,并說出他們的區別

數組就是一組數據的集合。 對象就是用來儲存變量的。 創建方式不同&#xff1a; 對象可以通過new關鍵字創建對象&#xff0c;或者通過對象字面量創建 數組&#xff1a;new Array() 數組表 示有序數據的集合&#xff0c;而對象表示無序數據的集合 數組的數據沒有名稱&#xff08…

在mysql中delete和truncated的相同點和區別點

相同點 刪除數據&#xff1a;兩者都會刪除表中的數據。影響數據&#xff1a;兩者都不刪除表結構&#xff0c;只影響表中的數據。 區別點 操作方式&#xff1a; DELETE&#xff1a;逐行刪除數據&#xff0c;可以使用 WHERE 子句來指定刪除的條件。如果不加 WHERE 子句&#…