给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定的有序链表: [-10, -3, 0, 5, 9],
一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:
0
/ \
-3 9
/ /
-10 5
题目来源于力扣,题目为109. 有序链表转换二叉搜索树。
这里直接po上我的错误代码以及费劲力气找到的原因,吸取教训。
public class ListNode {
int val;
ListNode next;
ListNode() {
}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {
}
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
package Day4_有序链表转换二叉搜索树;
public class Solution {public TreeNode sortedListToBST(ListNode head) {
if(head == null) return null;
TreeNode originalNode = new TreeNode(head.val);
TreeNode treeNode = null;
head = head.next;
// 将所有节点初步构成一棵有序二叉树
while(head != null){
treeNode = new TreeNode(head.val);
System.out.println("即将放入值:" + head.val);
putTreeNode(originalNode, treeNode);
head = head.next;
}
getBalancedTree(originalNode);
return originalNode;
}
// 将树设置为平衡二叉树
public void getBalancedTree(TreeNode originalNode){
if(originalNode == null) return;
getBalancedTree(originalNode.left);
getBalancedTree(originalNode.right);
int flag = isBalanced(originalNode);
if(flag == 0){
return;
}else if(flag == 1){
originalNode.right.left = originalNode;
originalNode = originalNode.right;
}else{
originalNode.left.right = originalNode;
originalNode = originalNode.left;
}
}
// 判断以传入节点开始的树是否为一棵二叉树
public int isBalanced(TreeNode originalNode){
if(originalNode == null){
return 0;
}else{
int leftDepth = getTreeDepth(originalNode.left, 0);
int rightDepth = getTreeDepth(originalNode.right, 0);
int result = leftDepth - rightDepth;
if(result * result <= 1){
return 0;
}else{
if(result < 0){ // 右边比左边长,需进行左旋
return 1;
}else{ // 左边比右边长,需进行右旋
return -1;
}
}
}
}
// 传入根结点,获取根结点开始的树的最大深度(即左右子树中较深的那个)
public int getTreeDepth(TreeNode originalNode, int depth){
if(originalNode == null){
return depth + 0;
}else{
System.out.println(originalNode.val);
int leftDepth = getTreeDepth(originalNode.left, depth + 1);
int rightDepth = getTreeDepth(originalNode.right, depth + 1);
return leftDepth > rightDepth ? leftDepth : rightDepth;
}
}
// 将节点按照"左子节点均小于父节点,右子节点均大于等于父节点"的方式放入二叉树
public void putTreeNode(TreeNode originalNode, TreeNode treeNode){
if(treeNode.val >= originalNode.val){
if(originalNode.right != null){
putTreeNode(originalNode.right, treeNode);
}else {
System.out.println(originalNode.val + "的右边放" + treeNode.val);
originalNode.right = treeNode;
}
}else{
if(originalNode.left != null){
putTreeNode(originalNode.left, treeNode);
}else{
System.out.println(originalNode.val + "的左边放" + treeNode.val);
originalNode.left = treeNode;
}
}
}
}
public class doMain {
public static void main(String[] args) {
ListNode headNode = new ListNode(-10);
ListNode nextNode = null, listNode = null;
nextNode = headNode;
int[] a = {-3,0,5,9};
for(int i = 0; i < a.length; i++){
listNode = new ListNode(a[i]);
nextNode.next = listNode;
nextNode = nextNode.next;
}
Solution solution = new Solution();
TreeNode treeNode = solution.sortedListToBST(headNode);
}
}
报错提示:栈溢出,在执行getTreeDepth时陷入死循环
报错原因:
- 在getBalancedTree方法中,当找到第一个非平衡点时,进行相应处理的代码有问题,代码如下。
if(flag == 0){
return;
}else if(flag == 1){
originalNode.right.left = originalNode;
originalNode = originalNode.right;
}else{
originalNode.left.right = originalNode;
originalNode = originalNode.left;
}
* 简单说就是:没有进行正确的左旋和右旋的时候
* 比如有 -3 0 5 9 这几个节点构成的二叉树(左小右大)
* 此时第一个非平衡点是 0,需要进行左旋
* 你的原左旋处理是:仅仅将 5 的左节点指向0。
* 但是你没有考虑到0的右节点还是指向 5
* 而且 -3 这个节点的右节点 要指向 5, 需要设置父节点,然后0的时候父节点是 -3,这样来操作 -3 的子节点
* originalNode = originalNode.right;这一句代码实际上没有任何作用
* 因为originalNode它并不是树上的那个点,它仅仅保存了指向某节点的地址而已。
* 对它进行赋值,那就是让它指向一个新的地方,不会对原来指向的节点有影响。
个人做题思路:
- 个人的思路是首先直接构建一棵二叉搜索树(左大右小的原则),
- 然后再按后序遍历,找到第一个非平衡点,进行平衡处理。
- 处理方式如上,但其实本题有一个条件——有序链表我没有用上,实际上可以通过有序链表来依次找出中位数构建二叉树。