109 有序链表转换二叉树

24 篇文章 1 订阅

题目

给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

给定的有序链表: [-10, -3, 0, 5, 9],

一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:
0
/ \
-3 9
/ /
-10 5

  • 方法一:自顶向下建树
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
	//快慢指针法查找链表给定区间的中间节点,左闭右开区间
    ListNode* getMedian(ListNode* left, ListNode* right){
        ListNode *fast = left;
        ListNode *slow = left;
        while(fast!=right && fast->next!=right){
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }
    //递归自顶向下建树
    TreeNode* buildTree(ListNode* left, ListNode* right){
        if(left == right) return NULL;
        ListNode *mid = getMedian(left, right);//得到链表给定区间的中间节点
        TreeNode *root = new TreeNode(mid->val);
        root->left = buildTree(left, mid);//建左子树
        root->right = buildTree(mid->next, right);//建右子树
        return root;
    }

    TreeNode* sortedListToBST(ListNode* head) {
        return buildTree(head, NULL);
    }
};
  • 时间复杂度O(nlogn)

  • 空间复杂度O(logn)

  • 思路

    • 每次选择链表区间最中间的节点作为根节点,再递归建立其左右子树。区间选择左闭右开区间,这样在找到mid之后,其左子树的区间就是[left,mid),其右子树的区间就是[mid->next,right)
    • 左闭右开区间,递归函数在left等于right时退出。通过调用查找中值函数,找到根节点的值。再递归调用该函数建造其左右子树,最后返回根节点。
    • 查找中值函数传入区间的左边界和右边界,通过快慢指针法找到链表的中间节点,将其返回。
  • 方法二:自底向上

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
	//递归建二叉搜索树
	//left和right表示根节点所代表的子树的节点在链表中的范围,取左闭右闭区间
	//传入的链表指针为引用类型
    TreeNode* buildTree(ListNode*& head, int left, int right){
        if(left > right) return NULL;//如果左边界大于右边界返回NULL
        //mid划分左右子树,其为根节点
        int mid = left + (right-left)/2;
        TreeNode *root = new TreeNode();//先建一个根节点占位
        root->left = buildTree(head, left, mid-1);//递归建左子树
        root->val = head->val;//填根节点的数值
        head = head->next;//链表指针后移
        root->right = buildTree(head, mid+1, right);//递归建右子树
        return root;//返回根节点
    }
    
    TreeNode* sortedListToBST(ListNode* head) {
        int len = 0;//计算链表的长度
        ListNode *p = head;
        while(p!=NULL){
            ++len;
            p = p->next;
        }
        return buildTree(head, 0, len-1);
    }
};
  • 时间复杂度O(n)
  • 空间复杂度O(logn)
  • 思路
    • 由于中序遍历二叉搜索树得到的结果就是链表本身,故可以将二者结合起来。
    • 类似二叉树的中序遍历。
      • 先建一个根节点占位,再递归调用该函数建左子树,给当前的根节点赋值,再递归调用建右子树,最后返回根节点。
      • 传入参数中的左右边界表示以当前节点为根的子树的数据范围。先计算mid,用它划分左右子树,左子树的范围是[left,mid-1],右子树的范围是[mid, right+1].当左边界大于右边界时,到达了叶子节点的孩子节点,返回空指针。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值