《劍指 Offer (第 2 版)》第 36 題:二叉搜索樹與雙向鏈表(典型遞歸問題)

第 36 題:二叉搜索樹與雙向鏈表(典型遞歸問題)

傳送門:二叉搜索樹與雙向鏈表爬盗伲客網(wǎng) online judge 地址胞锰。

輸入一棵二叉搜索樹,將該二叉搜索樹轉(zhuǎn)換成一個排序的雙向鏈表兢榨。

要求不能創(chuàng)建任何新的結(jié)點嗅榕,只能調(diào)整樹中結(jié)點指針的指向。

注意

  • 需要返回雙向鏈表最左側(cè)的節(jié)點吵聪。

例如凌那,輸入下圖中左邊的二叉搜索樹,則輸出右邊的排序雙向鏈表吟逝。

《劍指 Offer (第 2 版)》第 36 題:二叉搜索樹與雙向鏈表(典型遞歸問題)-1

思路:

《劍指 Offer (第 2 版)》第 36 題:二叉搜索樹與雙向鏈表(典型遞歸問題)-2

分析:參考解答有一定價值帽蝶,要好好研究一下。畫圖就清楚解法了块攒。

Python 代碼:

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution(object):

    def convert(self, root):
        """
        :type root: TreeNode
        :rtype: TreeNode
        """
        if root is None:
            return None
        head, _ = self.__dfs(root)

        return head

    def __dfs(self, root):
        """
        返回雙向鏈表的兩端
        """
        # 如果這個結(jié)點是葉子結(jié)點
        if root.left is None and root.right is None:
            return (root, root)

        # 如果有左孩子励稳,還有右邊孩子
        if root.left and root.right:
            ll, lr = self.__dfs(root.left)
            rl, rr = self.__dfs(root.right)
            # 下面穿針引線
            lr.right = root
            root.left = lr
            root.right = rl
            rl.left = root
            return (ll, rr)
        
        # 走到這里,就是二者之一為空
        if root.left:
            ll, lr = self.__dfs(root.left)
            lr.right = root
            root.left = lr
            return (ll, root)

        if root.right:
            rl, rr = self.__dfs(root.right)
            root.right = rl
            rl.left = root
            return (root, rr)

C++ 代碼:返回一個 pair

《劍指 Offer (第 2 版)》第 36 題:二叉搜索樹與雙向鏈表(典型遞歸問題)-3

Java 代碼:

class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;
    }
}

public class Solution {

    private TreeNode linkedListTail;
    private TreeNode res;

    public TreeNode Convert(TreeNode pRootOfTree) {
        convert(pRootOfTree);
        return res;
    }

    /**
     * 中序遍歷
     *
     * @param root
     */
    private void convert(TreeNode root) {
        if (root == null) {
            return;
        }
        convert(root.left);
        // 中序遍歷真正做事情的地方
        if (linkedListTail == null) { // 對應(yīng)剛開始的時候
            linkedListTail = root;
            // 在最左邊的地方記錄需要返回的雙向鏈表的根結(jié)點
            res = root;
        } else {
            linkedListTail.right = root;
            root.left = linkedListTail;
            linkedListTail = root;
        }
        convert(root.right);
    }
}

Python 代碼:

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution(object):

    def __init__(self):
        self.linked_list_tail = None
        self.res = None

    def convert(self, root):
        """
        :type root: TreeNode
        :rtype: TreeNode
        """
        self.__dfs(root)
        return self.res

    # 中序遍歷
    def __dfs(self, root):
        if root is None:
            return
        self.__dfs(root.left)

        if self.linked_list_tail is None:
            self.linked_list_tail = root
            self.res = root
        else:
            self.linked_list_tail.right = root
            root.left = self.linked_list_tail
            self.linked_list_tail = root
        self.__dfs(root.right)

Java 代碼:分治算法

public class Solution2 {
    public TreeNode convert(TreeNode root) {
        if (root == null) {
            return root;
        }
        TreeNode left = rightMost(root.left);
        TreeNode right = leftMost(root.right);
        convert(root.left);
        convert(root.right);
        if (left != null) {
            left.right = root;
        }
        root.left = left;
        if (right != null) {
            right.left = root;
        }
        root.right = right;
        
        // 最后返回最左邊的結(jié)點
        while (root.left != null) {
            root = root.left;
        }
        return root;
    }

    TreeNode leftMost(TreeNode root) {
        if (root == null) {
            return null;
        }
        while (root.left != null) {
            root = root.left;
        }
        return root;
    }

    TreeNode rightMost(TreeNode root) {
        if (root == null) {
            return null;
        }
        while (root.right != null) {
            root = root.right;
        }
        return root;
    }
}

C++ 代碼:

class Solution {
public:
    TreeNode* convert(TreeNode* root) {
        if (!root) return root;
        stack<TreeNode*> st;
        while (root){
            st.push(root);
            root = root->left;
        }
        TreeNode* ans = st.top();
        TreeNode* last = NULL;
        while (!st.empty()){
            TreeNode* tmp = st.top();
            st.pop();
            if (!last) last = tmp;
            else {
                last->right = tmp;
                tmp->left = last;
                last = tmp;
            }
            tmp = tmp->right;
            while (tmp){
                st.push(tmp);
                tmp = tmp->left;
            }
        }
        return ans;
    }
};

Java 代碼:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode convert(TreeNode root) {
        if (root == null) return null;
        TreeNode dummy = new TreeNode(-1);
        TreeNode pre = dummy;
        Stack<TreeNode> stack = new Stack<>();
        while (root != null || stack.size() != 0){
            while (root != null){
                stack.push(root);
                root = root.left;
            }
            if (stack.size() != 0){
                TreeNode node = stack.pop();
                pre.right = node;
                node.left = pre;
                pre = pre.right;
                root = node.right;
            }
        }
        dummy.right.left = null;
        dummy = dummy.right;
        return dummy;
    }
}

Java 代碼:

class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;
    }
}

public class Solution {

    private TreeNode linkedListTail;
    private TreeNode res;

    public TreeNode Convert(TreeNode pRootOfTree) {
        convert(pRootOfTree);
        return res;
    }

    /**
     * 中序遍歷
     *
     * @param root
     */
    private void convert(TreeNode root) {
        if (root == null) {
            return;
        }
        convert(root.left);
        // 中序遍歷真正做事情的地方
        if (linkedListTail == null) {
            linkedListTail = root;
            // 在最左邊的地方記錄需要返回的雙向鏈表的根結(jié)點
            res = root;
        } else {
            linkedListTail.right = root;
            root.left = linkedListTail;
            linkedListTail = root;
        }
        convert(root.right);
    }
}

參考資料:https://www.nowcoder.com/questionTerminal/947f6eb80d944a84850b0538bf0ec3a5

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末囱井,一起剝皮案震驚了整個濱河市驹尼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌庞呕,老刑警劉巖新翎,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡料祠,警方通過查閱死者的電腦和手機骆捧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門澎羞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來髓绽,“玉大人,你說我怎么就攤上這事妆绞∷撑唬” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵括饶,是天一觀的道長株茶。 經(jīng)常有香客問我,道長图焰,這世上最難降的妖魔是什么启盛? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮技羔,結(jié)果婚禮上僵闯,老公的妹妹穿的比我還像新娘。我一直安慰自己藤滥,他們只是感情好鳖粟,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拙绊,像睡著了一般向图。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上标沪,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天榄攀,我揣著相機與錄音,去河邊找鬼金句。 笑死檩赢,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的趴梢。 我是一名探鬼主播漠畜,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼坞靶!你這毒婦竟也來了憔狞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤彰阴,失蹤者是張志新(化名)和其女友劉穎瘾敢,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡簇抵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年庆杜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碟摆。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡晃财,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出典蜕,到底是詐尸還是另有隱情断盛,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布愉舔,位于F島的核電站钢猛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏轩缤。R本人自食惡果不足惜命迈,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望火的。 院中可真熱鬧壶愤,春花似錦、人聲如沸卫玖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽假瞬。三九已至陕靠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間脱茉,已是汗流浹背剪芥。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留琴许,地道東北人税肪。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像榜田,于是被迫代替她去往敵國和親益兄。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容