目录
226.翻转二叉树
翻转一棵二叉树。
示例:
输入:
4 / \ 2 7 / \ / \ 1 3 6 9输出:
4 / \ 7 2 / \ / \ 9 6 3 1
备注:
这个问题是受到 Max Howell 的 原问题 启发的 :
谷歌:我们90%的工程师使用您编写的软件(Homebrew),但是您却无法在面试时在白板上写出翻转二叉树这道题,这太糟糕了。
解法:递归思想
(1)先翻转左子树
(2)再翻转右子树
(3)左右子树翻转完毕,把左右子树换过来即可
/**
* Definition for a binary tree node.
* class TreeNode {
* public $val = null;
* public $left = null;
* public $right = null;
* function __construct($value) { $this->val = $value; }
* }
*/
class Solution {
function invertTree($root) {
if($root == null) return null; //递归终止条件,树为空,返回空
$this->invertTree($root->left); //递归:先将左子树进行翻转
$this->invertTree($root->right); //再将右子树进行翻转
$this->swap($root->left,$root->right); //左右子树已经翻转完毕,转换左右子树即可
return $root;
}
/**
* 交换左右子树指针
*/
public function swap(&$left,&$right){
$tmp = $left;
$left = $right;
$right = $tmp;
}
}
108. 将有序数组转换为二叉搜索树
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定有序数组: [-10,-3,0,5,9], 一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树: 0 / \ -3 9 / / -10 5
解法:根据二叉搜索树的定义,左右两个子树的高度差的绝对值不超过1
(1)数组左右均分长度,中间节点为子树根节点
(2)递归进行,建立左右子树
(3)当左长度 > 右长度,则寻找失败。当左长度 = 右长度,则子树只剩下一个节点,返回即可
class Solution {
function sortedArrayToBST($nums) {
$len = count($nums);
if($len == 0) return null; //数组长度为0,为空树
return $this->buildTree($nums,0,$len-1); //递归建立树的过程
}
public function buildTree($nums,$left,$right){
if($left > $right) return null; //左下标>右下标,不可能出现,返回null
if($left == $right) return new TreeNode($nums[$left]); //当左右下标一致时,该子树只有一个节点,直接返回
//左右等分高度,建立左右子树,中间节点作为子树的根节点,遍历该过程
$mid = ceil(($left + $right)/2);
$root = new TreeNode($nums[$mid]); //中间节点作为子树根节点
$root->left = $this->buildTree($nums,$left,$mid-1); //建立左子树
$root->right = $this->buildTree($nums,$mid+1,$right); //建立右子树
return $root;
}
}
450. 删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
- 首先找到需要删除的节点;
- 如果找到了,删除它。
说明: 要求算法时间复杂度为 O(h),h 为树的高度。
示例:
root = [5,3,6,2,4,null,7] key = 3 5 / \ 3 6 / \ \ 2 4 7 给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。 一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。 5 / \ 4 6 / \ 2 7 另一个正确答案是 [5,2,6,null,4,null,7]。 5 / \ 2 6 \ \ 4 7
解法:
(1)判断比较key和当前节点的值,对应递归遍历左/右子树,父节点连接删除后的子树,知道找到待删除的节点
(2)当找到待删除节点时,若左/右子树不存在,则对应连接右/左子树
(3)当待删除节点的左右子树都存在时,可以将待删除节点的右子树的最左节点作为新的根,并将原先这个最左节点的右子树连接到其父节点的左子树上,完成右子树的重构
class Solution {
function deleteNode($root, $key) {
if($root == null) return null; //树为空,直接返回空
if($key < $root->val){ //待删除的节点在左子树中
$root->left = $this->deleteNode($root->left, $key); //root->left指向执行完递归删除操作后的左子树
return $root;
}else if($key > $root->val){
$root->right = $this->deleteNode($root->right, $key); //待删除的节点在右子树中
return $root;
}else{
//已经找到待删除的节点,key == root->val
if($root->left == null) return $root->right; //该节点没有左子树,则可直接连接右子树
if($root->right == null) return $root->left; //该节点没有右子树,则可直接连接左子树
//左右子树都存在,则需要后继节点(右子树最左节点)作为新的根
$successor = $this->min($root->right); //寻找右子树最左节点
$successor->right = $this->delMin($root->right); //该节点的右子树连向去除节点后的重构右子树
$successor->left = $root->left; //该节点左子树连向删除节点的左子树
return $successor;
}
}
public function min($node){
//递归寻找最左节点
if($node->left == null)
return $node;
return $this->min($node->left);
}
private function delMin($node){
//重构右子树:递归寻找左子树,当寻找到最左节点时,把它的右子树连接到其父节点的左子树上
if($node->left == null) return $node->right;
$node->left = $this->delMin($node->left);
return $node;
}
}