将有序链表转换为高度平衡的二叉树

首先来看一个简单的例子,如何将有序数组转换为平衡二叉树?

模拟堆排序的方式,如果每次把数组的中位数当作根节点,把中位数左边的序列的中位数当作左子节点,右边的序列的中位数当作右子节点,递归上面的过程即可得到一个平衡二叉树。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode * arr2BST(vector<int>& nums, int start, int end) {
        if (start > end) {
            return NULL;
        }
        
        int mid = start + (end - start) / 2;
        TreeNode * root = new TreeNode(nums[mid]);
        root->left = arr2BST(nums, start, mid-1);
        root->right = arr2BST(nums, mid+1, end);
        
        return root;
    }
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        if(nums.size() == 0) {
            return NULL;
        }
        
        return arr2BST(nums, 0, nums.size() - 1);
    }
};

类似的,我们想想也可以将链表看作是数组,由于上面的过程中,上面的过程中,主要有两个地方需要转换为链表的操作,即start和end是数组的下标,我们需要转换为链表的节点,每次计算出mid,然后next大法计算出当前节点后第mid个节点即可。思考一下时间复杂度,由于每次找mid节点都会做比较,由于是折中查找所以时间复杂度是lgn,所以时间复杂度是nlgn。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode * list2BST(ListNode * head, int start, int end) {
        if (start > end) {
            return NULL;
        }
        if (start == end) {
            return new TreeNode(head->val);
        }
        
        int mid = (end - start) / 2;
        ListNode * p = head;
        for (int i = 0; i < mid && p != NULL; ++i) {
             p = p->next;
        }
        if (p == NULL) {
            return NULL;
        }
        TreeNode * root = new TreeNode(p->val);
        root->left = list2BST(head, start, mid-1);
        root->right = list2BST(p->next, mid+1, end);
        
        return root;
    }
    
    TreeNode* sortedListToBST(ListNode* head) {
        if (head == NULL) {
            return NULL;
        }
        int end = 0;
        for (ListNode * p = head; p != NULL; p=p->next, ++end);
        
        return list2BST(head, 0, end-1);
    }
};

当然,这里的时间消耗在查找mid节点,假如存在函数f,f遍历链表的某个序列的时候总是返回这个序列的中间节点,那么就不用for循环找mid节点了。这种自底而上的形式非常类似于二叉树的中序遍历。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode * list2BST(ListNode * &head, int start, int end) {
        if (start > end) {
            return NULL;
        }
        
        int mid = start + (end - start) / 2;
        TreeNode * left = list2BST(head, start, mid-1);
        TreeNode * root = new TreeNode(head->val);
        root->left = left;
        head = head->next;
        root->right = list2BST(head, mid+1, end);
        
        return root;
    }
    
    TreeNode* sortedListToBST(ListNode* head) {
        if (head == NULL) {
            return NULL;
        }
        int end = 0;
        for (ListNode * p = head; p != NULL; p=p->next, ++end);
        
        return list2BST(head, 0, end-1);
    }
};

在上面的代码中,从底向上,依次告诉上层递归:“我是left,是左子序列的中间节点,我是right,我是右子序列的中间节点”。

    原文作者:平衡二叉树
    原文地址: https://blog.csdn.net/p_j_stl/article/details/81276832
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞