leetcode:109. 有序链表转换二叉搜索树

题目来源

109. 有序链表转换二叉搜索树

类似的题目:108. 将有序数组转换为二叉搜索树

题目描述

在这里插入图片描述

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) {}
};

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:
    TreeNode* sortedListToBST(ListNode* head) {

    }
};

题目解析

递归(推荐)

108. 将有序数组转换为二叉搜索树不同的是,数组取中很容易使用下标得到,但是链表没那么容易,不过我们可以使用快慢指针来取得终点。当获取到链表的中点作为而二叉树节点的时候,我们还需要得到该节点的左右子树
由于我们得到的是一个有序链表而不是数组,我们不能直接使用下标来访问元素。我们需要知道链表中的中间元素。
我们可以利用两个指针来访问链表中的中间元素。假设我们有两个指针 slow_ptr 和 fast_ptr。slow_ptr 每次向后移动一个节点而 fast_ptr 每次移动两个节点。当 fast_ptr 到链表的末尾时 slow_ptr 就访问到链表的中间元素。对于一个偶数长度的数组,中间两个元素都可用来作二叉搜索树的根。
当找到链表中的中间元素后,我们将链表从中间元素的左侧断开,做法是使用一个 prev_ptr 的指针记录 slow_ptr 之前的元素,也就是满足 prev_ptr.next = slow_ptr。断开左侧部分就是让 prev_ptr.next = None。
我们只需要将链表的头指针传递给转换函数,进行高度平衡二叉搜索树的转换。所以递归调用的时候,左半部分我们传递原始的头指针;右半部分传递 slow_ptr.next 作为头指针。

一个很容易出错的点:当链表中只有一个节点的时候就要及时返回,因为它是无法通过快慢指针取中的,只会进入死循环

class Solution {
public:
    TreeNode* sortedListToBST(ListNode* head) {
        if(head == NULL){
            return NULL;
        }

        if(head->next == NULL){
            return new TreeNode(head->val);
        }

        ListNode *fast = head, *slow = head, *pre = head;
        while (fast != NULL && fast->next != NULL){
            fast = fast->next->next;
            pre = slow;
            slow = slow->next;
        }
        pre->next = NULL;

        TreeNode *node = new TreeNode(slow->val);
        node->left = sortedListToBST(head);
        node->right = sortedListToBST(slow->next);
        return node;
    }
};

使用半开半闭区间

class Solution {
    TreeNode * helper(ListNode* head, ListNode* tail){
        if(head == tail){
            return nullptr;
        }

        ListNode *fast = head, *slow = head;
        while (fast != tail && fast->next != tail){
            slow = slow->next;
            fast = fast->next->next;
        }

        TreeNode *node = new TreeNode(slow->val);
        node->left = helper(head, slow);
        node->right = helper(slow->next, tail);
        return node;
    }
public:
    TreeNode* sortedListToBST(ListNode* head) {
        return helper(head, nullptr);
    }
};

中序遍历模拟

因为我们知道题目给定的升序数组,其实就是二叉搜索树的中序遍历。那么我们完全可以按照这个顺序去为每个节点赋值。

实现的话,我们套用中序遍历的递归过程,并且将start和end作为递归参数,当start == end的时候,就返回null

先回想一下中序遍历的算法

class Solution {
    void helper(TreeNode* root, std::vector<int> &ans){
       if(root == nullptr){
           return;
       }
       
       helper(root->left, ans);
       ans.emplace_back(root->val);
       helper(root->right, ans);
    }
public:
    std::vector<int> inorderTraversal(TreeNode* root) {
        std::vector<int> ans;
        helper(root, ans);
        return ans;
    }
};

之前是将node和val进行保存,这里的话我们是给当前节点仅需赋值,为了实现一次赋值,我们需要一个cur指针指向给定的数列,每赋一个值就进行后移。

class Solution {
    ListNode *curr = nullptr;
    TreeNode* helper(int start, int end){
        if (start == end) {
            return nullptr;
        }

        int mid = (unsigned )(start + end) >> 1;
        //遍历左子树并且将根节点返回
        TreeNode *left = helper(start, mid);
        //遍历当前根节点并进行赋值
        TreeNode *root = new TreeNode(curr->val);
        root->left = left;
        curr = curr->next;
        //遍历右子树并且将根节点返回
        TreeNode *right = helper(mid + 1, end);
        root->right = right; //指针后移,进行下一次的赋值
        return root;
    }
public:
    TreeNode* sortedListToBST(ListNode* head) {
        curr = head;
        int end = 0;
        while (curr != nullptr){
            end++;
            curr = curr->next;
        }
        curr = head;
        return helper(0, end);
    }
};


在这里插入图片描述

转换为数组然后BST

索引作为参数,就是参数,不要一下子长度一下子索引

class Solution {
    private  ArrayList<Integer> arrayList;

    public Solution() {
        arrayList = new ArrayList<>();
    }

    // 转换为数组,然后转为BST
    public  TreeNode sortedListToBST(ListNode head) {
          while (head != null){
              arrayList.add(head.val);
              head = head.next;
          }
          return  arrayListToBST(0,  arrayList.size() - 1) ;
    }
    
    public  TreeNode arrayListToBST(int left, int right){
        if (right < left){
            return null;
        }
        
        int mid = left + (right - left)/2;
        TreeNode node = new TreeNode(arrayList.get(mid));
        node.left = arrayListToBST(left, mid - 1);
        node.right = arrayListToBST(mid + 1, right);
        return node;
    }
}

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值