<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ?LeetCode刷題實戰(zhàn)94:二叉樹的中序遍歷

          共 2782字,需瀏覽 6分鐘

           ·

          2020-11-13 13:25

          算法的重要性,我就不多說了吧,想去大廠,就必須要經(jīng)過基礎(chǔ)知識和業(yè)務(wù)邏輯面試+算法面試。所以,為了提高大家的算法能力,這個公眾號后續(xù)每天帶大家做一道算法題,題目就從LeetCode上面選 !

          今天和大家聊的問題叫做?二叉樹的中序遍歷,我們先來看題面:

          https://leetcode-cn.com/problems/binary-tree-inorder-traversal/

          Given the root of a binary tree, return the inorder traversal of its nodes' values.

          題意


          給定一個二叉樹的根節(jié)點 root ,返回它的 中序 遍歷。用遞歸做這道題非常簡單,你能不用遞歸實現(xiàn)嗎?

          樣例

          解題

          https://www.cnblogs.com/techflow/p/13587858.html
          我們先來介紹一下二叉樹的中序遍歷,二叉樹有三種遍歷方式,分別是先序、中序和后序。對于初學者而言,可能會覺得這三種順序傻傻分不清楚,不知道它們之間有什么分別。其實說白了非常簡單,遍歷方式其實指的是我們在遞歸遍歷的時候的選擇順序
          假設(shè)我們目前遞歸到的節(jié)點是u,它有左右兩個孩子。在保證左孩子一定先于右孩子訪問的前提下,我們有三種策略。第一種是先把u加入訪問序列,之后再分別遍歷左右子樹,第二種是先遞歸遍歷左子樹,然后把u加入訪問序列,最后再遍歷右子樹。第三種策略是先遞歸遍歷左右子樹,最后再把u加入訪問序列。
          這三種策略之間有什么不同呢?其實最大的不同就在于u加入訪問序列的順序不同,如果是先加入u再訪問,那么就是先序。如果是先訪問了左子樹再來加入u,則是中序,最后如果是先遞歸了左右子樹,最后再加入u,則是后序。說白了也就是u先加入就是先序,中間加入就是中序,最后加入就是后序。如果你還覺得有點蒙的話,我們來看下代碼就非常清晰了。

          # 先序
          def?dfs(u):
          ????visited.append(u)
          ????dfs(u.left)
          ????dfs(u.right)
          ????
          # 中序
          def?dfs(u):
          ????dfs(u.left)
          ????visited.append(u)
          ????dfs(u.right)
          ????
          ????
          # 后序
          def?dfs(u):
          ????dfs(u.left)
          ????dfs(u.right)
          ????visited.append(u)


          但是題目當中要求我們不通過遞歸來實現(xiàn),這該怎么辦呢?
          其實也有辦法,我們需要從遞歸的實現(xiàn)原理入手。我們知道在編譯器內(nèi)部,當我們從一個函數(shù)調(diào)用另外一個函數(shù)的時候,這些函數(shù)的信息會被存儲在一個棧結(jié)構(gòu)內(nèi)。棧中間的每一個節(jié)點會記錄函數(shù)的名稱以及它目前運行的位置,以及一些中間變量等等。所以當我們遞歸的時候,其實就是當前的函數(shù)不停的入棧的過程。
          比如我們dfs函數(shù)在第5行代碼處遞歸調(diào)用了dfs函數(shù),那么編譯器內(nèi)部的堆棧會記錄[(dfs, 5), (dfs, 1)]。如果我們在dfs的第一行又調(diào)用了sum函數(shù),那么編譯器又會把sum這個函數(shù)加入堆棧,變成:[(dfs, 5), (dfs, 1), (sum, 1)]。當函數(shù)執(zhí)行完成之后,會從棧中彈出。
          簡而言之,遞歸其實就是利用編譯器自行維護的棧結(jié)構(gòu)來簡化我們代碼和功能的編寫。既然這道題當中要求我們不能使用遞歸,那么我們就只能自己來使用棧來模擬這個過程了。由于我們自己需要維護棧當中的元素,使得整個過程會稍微復(fù)雜一些。
          在這道題目當中,我們使用棧來記錄樹上的節(jié)點。棧頂?shù)墓?jié)點即是當前訪問的節(jié)點。

          class Solution:
          ????def inorderTraversal(self, root:?TreeNode) -> List[int]:
          ????????ret?= []
          ????????stack = []
          ????????stack.append(root)
          ????????while?len(stack) > 0:
          ????????????# 獲取棧頂頂點
          ????????????cur = stack[-1]
          ????????????if?cur is?None:
          ????????????????stack.pop()
          ????????????????continue
          ????????????????
          ????????????# 如果左孩子存在,那么優(yōu)先遍歷左孩子
          ????????????if?cur.left?is?not None:
          ????????????????stack.append(cur.left)
          ????????????????# 把左指針置為空,防止死循環(huán)
          ????????????????# 這里也可以用set來維護
          ????????????????cur.left?= None
          ????????????????continue
          ????????????????
          ????????????# 左邊遍歷結(jié)束之后加入序列
          ????????????ret.append(cur.val)
          ????????????stack.pop()
          ????????????if?cur.right?is?not None:
          ????????????????stack.append(cur.right)? ? ? ??
          ????????return?ret


          如果只是二叉樹的遍歷,那這個誰都會,但如果不能使用遞歸,那么就很考驗硬實力了。需要我們對遞歸的底層原理有深入的理解,并且熟悉棧這個數(shù)據(jù)結(jié)構(gòu)的使用。這段代碼的邏輯不難理解,但實現(xiàn)還是挺鍛煉人的,推薦大家試試。
          好了,今天的文章就到這里,如果覺得有所收獲,請順手點個在看或者轉(zhuǎn)發(fā)吧,你們的支持是我最大的動力。


          上期推文:

          LeetCode50-80題匯總,速度收藏!
          LeetCode刷題實戰(zhàn)81:搜索旋轉(zhuǎn)排序數(shù)組 II
          LeetCode刷題實戰(zhàn)82:刪除排序鏈表中的重復(fù)元素 II
          LeetCode刷題實戰(zhàn)83:刪除排序鏈表中的重復(fù)元素
          LeetCode刷題實戰(zhàn)84:?柱狀圖中最大的矩形
          LeetCode刷題實戰(zhàn)85:最大矩形
          LeetCode刷題實戰(zhàn)86:分隔鏈表
          LeetCode刷題實戰(zhàn)87:擾亂字符串
          LeetCode刷題實戰(zhàn)88:合并兩個有序數(shù)組
          LeetCode刷題實戰(zhàn)89:格雷編碼
          LeetCode刷題實戰(zhàn)90:子集 II
          LeetCode刷題實戰(zhàn)91:解碼方法
          LeetCode刷題實戰(zhàn)92:反轉(zhuǎn)鏈表 II
          LeetCode刷題實戰(zhàn)93:復(fù)原IP地址

          瀏覽 21
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩不卡一二三 | 免费男女激情内射视频网站大全 | 亚洲一级av | 韩国亚洲一二区 | 青春草亚洲视频在线观看 |