Cracking Coding Interview - 4.4 Check Balanced

Check Balanced: Implement a function to check if a binary tree is balanced. For the purposes of this question, a balanced tree is defined to be a tree such that the heights of the two subtrees of any node never differ by more than one.

Hints:#21, #33, #49, #105, #124

解法1 - 深度优先(审题错误)

平衡的定义是一颗树中任意节点的两颗子树高度不的超过1。比如下面就是平衡的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
   1
  /
 2

   1
  / \
 2   3
 
    1
   / \
  2   3
 / \
4   5

下面是不平衡的:

1
2
3
4
5
6
7
      1
     / \
    2   3
   / \
  4   5
 /
6

可以看到(2)这个子树的高度是3,而(3)这个子树的高度是1,高度相差2,所以不平衡。

首先想到的是计算左右子树高度,然后判断差是否超过1:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public boolean checkBalanced(Node root) {
  int lHeight = height(root.left);
  int rHeight = height(root.right);
  return Math.abs(lHeight - rHeight) <= 1;
}

private int height(Node node) {
  if (node == null) {
    return 0;
  }
  int lHeight = height(node.left);
  int rHeight = height(node.right);
  return Math.max(lHeight, rHeight) + 1;
}

解法2 - 广度优先(审题错误)

解法1是深度优先的,他会遍历到所有节点,是否可以用广度优先的算法来解。

因为广度优先是一层一层遍历的,在遍历过程中记录第一个叶子节点的层数,并且比较当前遍历的层数的差,超过1就说明不平衡:

1
2
3
4
5
6
7
      1
     / \
    2   3   <- 叶子节点
   / \
  4   5
 /
6           <- 当前层

这样就不需要遍历所有节点了。

要注意以下处理这种情况:

1
2
3
4
5
6
7
      1
     /
    2   
   /
  3
 /
4

这种情况下可以认为叶子节点的层数为1。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public boolean checkBalanced(Node root) {
  int firstLeafLevel = 0;
  if (root.left == null || root.right == null) {
    firstLeafLevel = 1;
  }
  int currentLevel = 1;
  List<Node> current = new ArrayList<>();
  current.add(root);
  while (!current.isEmpty()) {
    if (currentLevel - firstLeafLevel > 1) {
      return false;
    }
    List<Node> parent = current;
    current = new ArrayList<>();
    for (Node p : parent) {
      if (p.left != null) {
        current.add(p.left);
      }
      if (p.right != null) {
        current.add(p.right);
      }
      if (firstLeafLevel != 0 && p.left == null && p.right == null) {
        // 第一个叶子节点的深度
        firstLeafLevel = currentLevel;
      }
    }
    if (!current.isEmpty()) {
      current.level++;
    }
  }
  return true;
}

解法3

上面两个解法审题错误,从根节点来看左右子树高度不超过1不代表左子树的左右子树高度不超过1。所以要对每个节点都计算一下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public boolean checkBalanced(Node root) {
  int lHeight = height(root.left);
  int rHeight = height(root.right);
  if (Math.abs(lHeight - rHeight) <= 1) {
    return true;
  }
  return checkBalanced(root.left) && checkBalanced(root.right);
}

private int height(Node node) {
  if (node == null) {
    return 0;
  }
  int lHeight = height(node.left);
  int rHeight = height(node.right);
  return Math.max(lHeight, rHeight) + 1;
}

解法4

但是上面牵涉到很多重复计算,那么可以在计算height的时候就同时判断是否平衡:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Tmp {
  int height;
  boolean balanced;
}
public Tmp height(Node node) {
  if (node == null) {
    return new Tmp(0, true);
  }
  Tmp l = height(node.left);
  if (!l.balanced) {
    return false;
  }
  Tmp r = height(node.right);
  if (!r.balanced) {
    return false;
  }
  int h = Math.max(l.height, r.height) + 1;
  if (Math.abs(l.height - r.height) > 1) {
    return new Tmp(h, false);
  }
  return new Tmp(h, true);
}

其实还可以更简单一点,用异常:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public int height(Node node) {
  if (node == null) {
    return 0;
  }
  int lHeight = height(node.left);
  int rHeight = height(node.right);
  if (Math.abs(lHeight - rHeight) > 1) {
    throw new NotBalanced();
  }
  return Math.max(lHeight, rHeight) + 1;
}

或者用Integer.MIN_VALUE作为一异常值:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public int height(Node node) {
  if (node == null) {
    return 0;
  }
  int lHeight = height(node.left);
  if (lHeight == Integer.MIN_VALUE) {
    return Integer.MIN_VALUE;
  }
  int rHeight = height(node.right);
  if (rHeight == Integer.MIN_VALUE) {
    return Integer.MIN_VALUE;
  }
  if (Math.abs(lHeight - rHeight) > 1) {
    throw Integer.MIN_VALUE;
  }
  return Math.max(lHeight, rHeight) + 1;
}

public boolean checkBalanced(Node root) {
  return height(root) != Integer.MIN_VALUE;
}

版权

评论