【LeetCode】108、109题——将有序数组、链表转化为二叉搜索树

1.题目

  1. 108题

    将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。

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

在这里插入图片描述

  1. 109题

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

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

在这里插入图片描述

2.解法

  1. 108题——递归

    解题思路

    • 类似于二分法,数组两边边界下标,取中值mid,mid下标所在的数值及为二叉树的根节点。
    • 取mid下标左段和右段数组段进行递归计算。

    注意

    • 若 mid = (left + right) / 2 可能会造成数值越界(数组中出现 int 型的最大值最小值的情况),所以取mid = left + (right - left) / 2 会更为安全。

    • 该题答案不唯一。当数组段长度为偶数时,mid = left + (right - left) / 2 默认取下界,取其上界作为root节点的值也是满足二叉搜索树要求的。
      在这里插入图片描述
      在这里插入图片描述

    代码实现

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        public TreeNode sortedArrayToBST(int[] nums) {
            return convertToBST(nums, 0, nums.length-1);
        }
    
        public TreeNode convertToBST(int[] nums, int left, int right){
            if(left > right) return null;
            int mid = left + (right - left) / 2;
            TreeNode root = new TreeNode(nums[mid]);
            root.left = convertToBST(nums, left, mid-1);
            root.right = convertToBST(nums, mid+1,right);
            return root;
        }
    }
    

    时间复杂度O(N) ,每个元素只访问一次。

    空间复杂度O(log N) ,二叉搜索树空间 O(N) ,递归栈深度 O(log N)


  2. 109题——快慢指针

    解题思路

    • 定义一个快指针 fast 和一个慢指针 slow,慢指针一次走一步,快指针一次走两步,这样当快指针走到链表末尾,慢指针刚好在链表的中间位置,取slow所在链表的值为根节点的值。
    • 以 slow 所在节点为分界点,链表起点到 slow 前一个节点为左段,slow 后一个节点到链表末尾为右段,左右两段再进行递归计算。

    代码实现

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        public TreeNode sortedListToBST(ListNode head) {
            if(head == null) return null;
            if(head.next == null) return new TreeNode(head.val);
            ListNode slow = head;
            ListNode fast = head;
            ListNode pre = head;
    
            while(fast != null && fast.next != null){
                fast = fast.next.next;
                slow = slow.next;
            }
    
            while(pre.next != slow){
                pre = pre.next;
            }
            TreeNode root = new TreeNode(slow.val);
            ListNode headRight = slow.next;
            //对slow左段进行分割,即断开slow前一个节点pre对slow节点的引用
            pre.next = null;
            root.left = sortedListToBST(head);
            root.right = sortedListToBST(headRight);
            return root;
        }
    }
    

    时间复杂度O(N log N) ,假设每个链表含有 N 个节点,要得到其中间节点,需要 N / 2 步;将链表分为两个子链表时,找到两个子链表的中间节点则需 2 *(N / 4)步,依次类推,每次需要的步数总和为:
    N 2 + 2 ⋅ N 4 + 4 ⋅ N 8 + 8 ⋅ N 16 + . . . \frac{N}{2}+2\cdot\frac{N}{4}+4\cdot\frac{N}{8}+8\cdot\frac{N}{16}+... 2N+24N+48N+816N+...
    而每次将列表分成一半,需要 log N 的时间结束,因此上面的式子可以写成:
    ∑ i = 1 l o g N 2 i − 1 ⋅ N 2 i = ∑ i = 1 l o g N N 2 = N 2 l o g N = O ( N l o g N ) \sum_{i=1}^{log N}{2^{i-1}\cdot}\frac{N}{2^i}=\sum_{i=1}^{log N}{\frac{N}{2}}=\frac{N}{2} logN=O(NlogN) i=1logN2i12iN=i=1logN2N=2NlogN=O(NlogN)

    空间复杂度O(log N)


  3. 109题——将链表转化为数组,再递归

    解题思路

    • 将链表转化为数组,后递归实现二叉搜索树。

    代码实现

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        public TreeNode sortedListToBST(ListNode head) {
            List<Integer> list = convertToArray(head);
            return listToBST(list, 0, list.size()-1);
        }
    
        public TreeNode listToBST(List<Integer> list, int left, int right){
            if(left > right) return null;
            int mid = left + (right - left) / 2;
            TreeNode root = new TreeNode(list.get(mid));
            root.left = listToBST(list, left, mid-1);
            root.right = listToBST(list, mid+1, right);
            return root;
        }
    
        public List<Integer> convertToArray(ListNode head){
            List<Integer> list = new ArrayList<>();
            while(head != null){
                list.add(head.val);
                head = head.next;
            }
            return list;
        }
    }
    

    时间复杂度O(N) ,因为将链表转化为数组,取中间元素的开销变成了 O(1) ,整体时间复杂度下降。

    空间复杂度O(N) ,因为创建数组的开销,以空间换时间,相较于之前的空间复杂度 O(log N) 有所提升。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值