【LeetCode 熱題 100】114. 二叉樹展開為鏈表——(解法二)分治

Problem: 114. 二叉樹展開為鏈表
給你二叉樹的根結點 root ,請你將它展開為一個單鏈表:
展開后的單鏈表應該同樣使用 TreeNode ,其中 right 子指針指向鏈表中下一個結點,而左子指針始終為 null 。
展開后的單鏈表應該與二叉樹 先序遍歷 順序相同。

【LeetCode 熱題 100】114. 二叉樹展開為鏈表——(解法一)后序遍歷+頭插法

文章目錄

  • 整體思路
  • 完整代碼
  • 時空復雜度
    • 時間復雜度:O(N)
    • 空間復雜度:O(H)

整體思路

這段代碼同樣旨在解決 “二叉樹展開為鏈表” 的問題,即將二叉樹原地轉換成一個按前序遍歷順序串聯的“鏈表”。與上一個“后序遍歷+頭插法”的版本不同,此版本采用的是一種 “分解問題” (Divide and Conquer) 的思想,通過遞歸函數返回子問題(子樹)展開后的尾節點來輔助父問題的解決。

  1. DFS函數的設計

    • 該算法的核心是一個輔助函數 dfs(node),它的設計目標是:
      a. 原地展開node 為根的子樹。
      b. 返回這棵子樹被展開成鏈表后的尾節點
  2. 分解與合并邏輯 (Divide and Conquer)

    • 分解 (Divide):對于當前節點 node,問題被分解為兩個子問題:展開左子樹和展開右子樹。這是通過遞歸調用 leftTail = dfs(node.left)rightTail = dfs(node.right) 來實現的。
      • leftTail 會接收到左子樹展開后鏈表的尾節點。
      • rightTail 會接收到右子樹展開后鏈表的尾節點。
    • 解決 (Conquer):當兩個子問題都解決后(即左右子樹都已各自拉平),開始處理當前節點 node,將其與兩個已拉平的子鏈表合并。
      • 合并的目標是形成 node -> (左子鏈表) -> (右子鏈表) 的結構。
      • if (leftTail != null): 這個判斷檢查是否存在左子樹。
        • leftTail.right = node.right;: 這是最關鍵的一步。它將左子鏈表的尾部 (leftTail) 的 right 指針,連接到原先 node 的右子樹(現在已經是右子鏈表的頭部)。這就把左右兩個鏈表串起來了。
        • node.right = node.left;: 將 node 的右指針指向其左孩子,即左子鏈表的頭部。
        • node.left = null;: 將 node 的左指針置空。
      • 完成這三步后,以 node 為根的子樹已經被成功展開。
  3. 返回尾節點

    • 在合并完成后,需要確定并返回當前整個大鏈表(node + 左子鏈表 + 右子鏈表)的尾節點。
    • 這個尾節點的位置有三種可能:
      a. 如果存在右子樹,那么尾節點就是右子樹的尾節點 (rightTail)。
      b. 如果不存在右子樹但存在左子樹,那么尾節點就是左子樹的尾節點 (leftTail)。
      c. 如果左右子樹都不存在,那么尾節點就是 node 本身。
    • return rightTail != null ? rightTail : leftTail != null ? leftTail : node; 這句三元表達式完美地實現了這個邏輯。

這個算法通過自底向上的方式,在每一層都完成子樹的展開和連接,最終將整個樹拉平。

完整代碼

class Solution {/*** 將給定的二叉樹原地展開為鏈表。* @param root 二叉樹的根節點*/public void flatten(TreeNode root) {// 調用輔助的DFS函數,主函數不需要返回值dfs(root);}/*** 輔助DFS函數:原地展開以 node 為根的子樹,并返回展開后鏈表的尾節點。* @param node 當前子樹的根節點* @return 展開后鏈表的尾節點*/private TreeNode dfs(TreeNode node) {// 基線條件:如果節點為空,則沒有什么可展開的,返回 null。if (node == null) {return null;}// 1. 分解:遞歸地展開左右子樹,并獲取它們展開后的尾節點。TreeNode leftTail = dfs(node.left);   // 展開左子樹,獲取左鏈表的尾TreeNode rightTail = dfs(node.right); // 展開右子樹,獲取右鏈表的尾// 2. 解決/合并:處理當前節點 node,將其與已展開的左右子鏈表連接。// 如果存在左子樹(即左子鏈表),才需要進行連接操作。if (leftTail != null) {// a. 將左鏈表的尾部的 right 指針,指向右子鏈表的頭部 (node.right)。leftTail.right = node.right;// b. 將 node 的右指針指向左子鏈表的頭部 (node.left)。node.right = node.left;// c. 將 node 的左指針置空。node.left = null;}// 3. 返回當前已展開大鏈表的尾節點。// 優先級:右子樹的尾 > 左子樹的尾 > 當前節點本身。if (rightTail != null) {return rightTail;}if (leftTail != null) {return leftTail;}return node;}
}

時空復雜度

時間復雜度:O(N)

  1. 節點訪問:該算法通過DFS遞歸遍歷了樹中的每一個節點。每個節點被訪問和處理一次。
  2. 操作:在每個節點上,執行的都是常數時間的指針操作。
  3. 綜合分析
    • 如果樹中有 N 個節點,dfs 函數會被調用 N 次。
    • 因此,總的時間復雜度與節點數成正比,即 O(N)

空間復雜度:O(H)

  1. 主要存儲開銷:算法是原地修改,沒有創建新的數據結構來存儲節點。主要的額外空間開銷來自于 遞歸調用棧
  2. 空間大小:遞歸調用的深度取決于樹的高度 H
    • 在最好的情況下(一個完全二叉樹),樹的高度 H 約為 log N,空間復雜度為 O(log N)。
    • 在最壞的情況下(一個極度傾斜的鏈狀樹),樹的高度 H 等于 N,此時遞歸棧的深度也為 N,空間復雜度為 O(N)

綜合分析
算法的輔助空間復雜度主要由遞歸棧的深度決定,即樹的高度 H。因此,空間復雜度為 O(H)。在最壞情況下,H 可能為 N,所以最壞空間復雜度也可以表述為 O(N)

參考靈神

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

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

相關文章

【WPF】WPF 自定義控件 實戰詳解,含命令實現

🧩《WPF 自定義控件》實戰詳解本文將圍繞如何編寫一個自定義控件(如帶右鍵菜單的圖片控件 ImageView),逐步講解其定義、命令綁定與 ContextMenu 中常見的語法技巧。🧱 一、創建一個 WPF 自定義控件的步驟 WPF 中自定義…

Flink 2.0 DataStream算子全景

在實時流處理中,Apache Flink的DataStream API算子是構建流處理 pipeline 的基礎單元。本文基于Flink 2.0,聚焦算子的核心概念、分類及高級特性。 一、算子核心概念:流處理的"原子操作 1. 數據流拓撲(Stream Topology&#x…

Flask 入門到實戰(2):使用 SQLAlchemy 打造可持久化的數據層

Flask 入門到實戰:使用 SQLAlchemy 打造可持久化的數據層一、前言:為什么用 Flask-SQLAlchemy? 在 Python Web 開發中,操作數據庫的方式主要有兩種: 直接寫 SQL(繁瑣且難維護)使用 ORM&#xff…

50天50個小項目 (Vue3 + Tailwindcss V4) ? | GithubProfies(GitHub 個人資料)

&#x1f4c5; 我們繼續 50 個小項目挑戰&#xff01;—— GithubProfies組件 倉庫地址&#xff1a;https://github.com/SunACong/50-vue-projects 項目預覽地址&#xff1a;https://50-vue-projects.vercel.app/ 使用 Vue 3 的 Composition API&#xff08;<script setup…

simscape中坐標系和坐標變換Frames and Transforms

為了更便捷地描述單個物體的運動&#xff0c;最好以該物體的質心為坐標原點建立坐標系&#xff0c;從而可以非常方便地描述其旋轉運動。因此&#xff0c;在計算多個物體之間的位置關系時&#xff0c;為了計算方便&#xff0c;需要頻繁地更換坐標框架&#xff0c;這也是multibod…

構建分布式光伏“四可”能力:支撐新型電力系統安全穩定運行的關鍵路徑

隨著我國新能源裝機規模的跨越式增長&#xff0c;國家能源戰略對新能源電站的規范化接入與精細化調度管理提出了更高要求。在電力市場化改革深化與新型電力系統構建的關鍵時期&#xff0c;保障電網安全穩定、提升新能源高效消納能力已成為核心議題。國家能源局于2025年1月17日正…

UART寄存器介紹

在 STM32 微控制器中&#xff0c;UART&#xff08;通用異步收發傳輸器&#xff09;通信通過多個寄存器實現配置和數據傳輸。下面詳細解析 UART 的核心寄存器及其功能。1. 狀態寄存器&#xff08;USART_SR&#xff09;狀態寄存器反映 UART 當前的工作狀態&#xff0c;用于判斷數…

寫一個算法對一組值進行歸一化映射,使它們在視覺上有明顯的區分度,尤其在數據集分布不均時仍能體現差異

問題&#xff1a; 有一批數據&#xff0c;都是隨機值范圍是不確定&#xff0c;我需要用這個值來繪制同樣數量圓&#xff0c;不同值他們的圓半徑不同&#xff0c;考慮到數據有時候大小偏差不大&#xff0c;這1000個值有可能是集中在10,20之間&#xff0c;也可能是分布廣泛&#…

具身智能零碎知識點(五):VAE中對使用KL散度的理解

VAE中對使用KL散度的理解什么是 VAE (Variational AutoEncoder)&#xff1f;從自編碼器 (AE) 說起VAE&#xff1a;讓潛在空間變得“有意義”和“連續”KL 散度是如何用到的&#xff1f;通俗理解 KL 散度在 VAE 中的作用&#xff1a;帶來的好處&#xff1a;KL 散度公式 (無需背誦…

理解:進程、線程、協程

線程、進程和協程是并發編程的重要組成部分。進程&#xff08;Process&#xff09;定義進程是操作系統分配資源的基本單位&#xff0c;表示一個正在執行的程序。一旦一個程序被加載到內存中&#xff0c;它就成為一個進程&#xff0c;而每個進程都有其獨立的內存空間。特征進程之…

總結一下找素數的三種方法

目錄 一試除法 二埃氏篩 三線性篩(歐拉篩) 一試除法 思想&#xff1a;就是判斷某個數x是不是素數,就判斷從2開始到小于根號x的范圍內有沒有能夠取余不等于0的,這個說明當前值就是x的一個因子&#xff0c;所以不是素數。 代碼&#xff1a; import java.util.Scanner;public…

基于Yolov8車輛檢測及圖像處理系統【有代碼】

0 引言 隨著城市化進程的加速和機動車保有量的快速增長,交通管理、智能監控和自動駕駛等領域對車輛目標檢測技術的需求日益增長。車輛目標檢測是計算機視覺領域的一個重要研究方向,其目標是從圖像或視頻序列中準確識別和定位車輛,為后續的車輛跟蹤、行為分析和交通流量統計…

MySQL密碼管理器“mysql_config_editor“

目錄 核心能力 常用命令速查 為什么更安全&#xff1f; 典型場景 mysql_config_editor 是 MySQL 官方自帶的一款命令行小工具&#xff0c;作用一句話&#xff1a;把賬號、密碼、主機、端口等連接信息加密存起來&#xff0c;下次連接時只敲一個名字即可&#xff0c;不用再寫…

Kubernetes高級調度01

目錄 第一章&#xff1a;初始化容器&#xff08;InitContainer&#xff09;—— 應用啟動前的 “準備軍” 1.1 InitContainer 的基本概念與核心特性 1.2 InitContainer 與普通容器的關鍵區別 1.3 InitContainer 的實戰場景與示例解析 1.3.1 示例 1&#xff1a;延遲啟動 —…

LSV負載均衡

什么是訪問壓力&#xff1f;--負載 兩個客戶同時訪問一個服務器&#xff0c;會導致服務器崩潰調度---Cluster集群&#xff08;為了解決一個特定問題&#xff0c;多臺服務器組合使用形成的一個系統&#xff09;LSV 1、集群Cluster LB&#xff1a;負載均衡&#xff0c;有多個主機…

復習筆記 38

緒論 其實沒有一種安穩快樂&#xff0c;永遠也不差 專題 2 知識點 繼續學數學強化吧&#xff1f;可以。還有概率論要學。還有高數后半部分的數一專項要學。還有政治要學。要學的內容確實還是挺多的啊。加油。下載了一個閱讀的軟件&#xff0c;可以做一做真題的閱讀理解。政治英…

GaussDB like 的用法

1 like 作用在 where 子句中使用 like 運算符來搜索列中的指定模式。 有兩個通配符與 like 運算符一起使用&#xff1a;&#xff05; - 百分號表示零個&#xff0c;一個或多個字符 _ - 下劃線表示單個字符注&#xff1a;也同時支持正則表達式。2 like 語法select column1, colu…

單例模式:確保全局唯一實例

單例模式確保一個類只有一個實例&#xff0c;并提供全局訪問點。適用于需要全局唯一對象的場景&#xff08;如配置管理器、數據庫連接池&#xff09;。代碼示例&#xff1a;import java.util.stream.IntStream;public class ConfigManager {public static void main(String[] a…

深入理解 QSettings:Qt 中的應用程序配置管理

在開發 Qt 應用程序時&#xff0c;管理應用程序的配置信息是一個常見的需求。無論是保存用戶的偏好設置、窗口大小&#xff0c;還是應用程序的運行時配置&#xff0c;都需要一種高效且靈活的方式來存儲和檢索這些信息。Qt 提供了一個強大的工具——QSettings&#xff0c;它能夠…

基于SpringBoot+Vue的體育館預約管理系統(支付寶沙盒支付、騰訊地圖API、協同過濾算法、可視化配置、可視化預約)

“ &#x1f388;系統亮點&#xff1a;支付寶沙盒支付、騰訊地圖API、協同過濾算法、可視化配置、可視化預約”01系統開發工具與環境搭建—前后端分離架構 項目架構&#xff1a;B/S架構 運行環境&#xff1a;win10/win11、jdk17前端&#xff1a; 技術&#xff1a;框架Vue.js&am…