Leetcode算法【114. 二叉樹展開爲鏈表】

上週經過一位小夥伴,加入了一個氛圍很好的小羣,人很少,可是你們保持着對知識的渴望,讓我很感動。程序員

我本身也有一個羣,人數也很少,可是能真正互動起來一塊兒學習,一塊兒進步的,仍是太少。因此,如今也在學習如何讓本身成爲更好的羣主,帶動羣活躍,帶動一個社羣活躍,帶動小夥伴們一塊兒進步,是個人願景。固然,也不否定如今不少羣友正在朝着積極向上的方向走着,我要作的,也是時刻保持對知識的渴望,作到「持續學習」。算法

誰讓咱是一名優秀的程序員呢。上週日也學習了一遍遞歸,還經過一個二叉樹的例子來簡單介紹了下。我以前解決二叉樹相關的問題,基本上用的都是遞歸,結果那天分享的朋友用了隊列,讓我眼前一亮,原來程序的世界真是奇妙。編程

因此,思想碰撞真的是一件很開心的事情。你們在持續的學習,持續的交流中,會打開一些思惟定式,接納更多的方式,大家以爲呢?數據結構

Algorithm LeetCode算法

114. 二叉樹展開爲鏈表 (https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/)數據結構和算法

題目描述:給定一個二叉樹,原地將它展開爲鏈表。學習

例如,給定二叉樹指針

示例1:code

1  
   / \
  2   5
 / \   \
3   4   6

將其展開爲:遞歸

1
 \
  2
   \
    3
     \
      4
       \
        5
         \
          6

本文題解參考地址:https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--26/隊列

解法:後序遍歷法

題目其實就是將二叉樹經過右指針,組成一個鏈表。

從例子上能夠看出,其實就是讓咱們把二叉樹,經過先序遍歷展現出來。因此咱們首先想到的是能不能用先序遍歷的方式,每遍歷一個節點,就將上一個節點的右指針更新爲當前節點。

先序遍歷的順序是 1->2->3->4->5->6,以下:

遍歷到2,把1的右指針指向2,即變成 1->2 3 4 5 6

遍歷到3,把2的右指針指向3,即變成 1->2->3 4 5 6

理想情況下,以此類推便可。

可是,若是咱們把1的右指針指向2,那麼這時候1本來的右節點就丟失了,也就是咱們後續找不到5這個節點。

因此,又引發了咱們的思考,如何才能不讓5丟失呢?後序遍歷能夠嗎?

也就是咱們依次遍歷6 5 4 3 2 1,而後每遍歷一個節點就將當前節點的右指針更新爲上一個節點,以下:

遍歷到5,把5的右指針指向6,即變成6 <- 5 4 3 2 1

遍歷到4,把4的右指針指向5,即變成6 <- 5 <- 4 3 2 1

以此類推,由於咱們更新當前右指針的時候,當前節點的右節點已經訪問過了,因此就不會存在丟失節點的問題。

把這個轉變成後序遍歷,遍歷順序就是 右子樹 -> 左子樹 -> 根節點

// 將二叉樹構建完成
public static void main(String[] args) {
	TreeNode treeNode = new TreeNode(1);
	treeNode.left = new TreeNode(2);
	treeNode.left.left = new TreeNode(3);
	treeNode.left.right = new TreeNode(4);
		
	treeNode.right = new TreeNode(5);
	treeNode.right.right = new TreeNode(6);
	flattern(treeNode);
}
/**
 * 
 * @Title      :  
 * @Description: 後續遍歷
 * @param treeNode
 * @return     :void
 * @throws
 */
public static void flattern(TreeNode root) {
	Stack<TreeNode> treeNodes = new Stack<>();
	TreeNode current = root;
	TreeNode preview = null;
		
	while (current != null || !treeNodes.isEmpty()) {
		while (current != null) {
			// 添加根節點
			treeNodes.push(current);
			// 添加右節點
			current = current.right;
		}
			
		// 已經訪問到最右邊的節點
		current = treeNodes.peek();
		// 當右節點已經被訪問過或者左節點不存在的狀況,就去訪問根節點
		if (current.left == null || current.left == preview) {
			treeNodes.pop();
			current.right = preview;
			current.left = null;
			preview = current;
			current = null;
		} else {
			current = current.left;
		}
	}
}

補充說明:先序遍歷

在介紹着後序遍歷的時候,咱們先用先序遍歷的例子以及缺陷,來講明爲何咱們選擇後序遍歷。那麼,就必定不能用先序遍歷了嗎?顯然,答案是不對的。

有一種特殊的先序遍歷,提早將右節點保存到棧中,咱們利用這種遍歷方式就能夠防止右節點的丟失。由於棧是先進後出,因此咱們先將右節點入棧。

再根據上面先序遍歷的分析,由於咱們用棧保存了右孩子,因此不須要擔憂右孩子丟失了。用一個 pre 變量保存上次遍歷的節點便可。

public static void flatten1(TreeNode root) { 
    if (root == null){
        return;
    }
    Stack<TreeNode> s = new Stack<TreeNode>();
    s.push(root);
    TreeNode pre = null;
    while (!s.isEmpty()) {
        TreeNode temp = s.pop(); 
        if(pre!=null){
            pre.right = temp;
            pre.left = null;
        }
        if (temp.right != null){
	        s.push(temp.right);
	    }
	    if (temp.left != null){
	         s.push(temp.left);
	    } 
	    pre = temp;
    }
}

結語

二叉樹,是一顆神奇的樹,理論上咱們均可以經過先序、中序、後續遍從來拆解他,獲得咱們想要的結果,在作題的時候也是如此。

可是真正體現到編程的世界裏,仍是和理論作題有一點不一樣,編程須要咱們用機器語言是實現,去思考,去打通咱們算法的任督二脈,這樣就是LeetCode存在的魅力,他是一個氛圍很好的社區,擁有它,就擁有了算法的世界,擁有了進階的可能。

安利了LeetCode,安利下本身的號,儘可能作到每週一題,分模塊的學習。小編最大的後悔就是沒能在大學學好數據結構和算法這門課,如今吃虧了,吃大虧了。好在萬變不離其宗,只要經過本身的勤奮,沒有什麼是不可能的。

加油,奔跑吧兄弟們!

做者:Dimple

公衆號:奔跑吧攻城獅

本文由博客一文多發平臺 OpenWrite 發佈!

相關文章
相關標籤/搜索