1. 题意
给你一颗二叉搜索树,让你返回一颗平衡二叉搜索树(avl
树)。
2. 题解
avl
旋转的做法后面再补吧!
也有可能不补了~
2.1 贪心构造
我们可以先将二叉搜索树序列化,
将它的中序遍历序列放到一个数组v
中。
接下来就是策略了,
对于一个有序序列 v [ l , r ] v[l,r] v[l,r]
我们每次构造平衡二叉树选择根的时候都选择数组的中间位置
m i d : = ⌊ l + r 2 ⌋ r o o t . v a l : = v [ m i d ] \begin{align*} mid &:=\ \lfloor \frac{l+r}{2}\rfloor\\ root.val & := v[mid] \end{align*} midroot.val:= ⌊2l+r⌋:=v[mid]
。
再分别递归的构造左右子树。
具体的意思还是看代码,其实就是二分地构造平衡二叉搜索树。
还是看代码吧
cpp
/**
* Definition for a binary tree node.
* 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:
void inorder_output(TreeNode* rt, vector<int> &v) {
stack<TreeNode *> st;
TreeNode *root = rt;
while ( !st.empty() || root != NULL ) {
if ( root ) {
st.push(root);
root = root->left;
continue;
}
if ( !st.empty()) {
TreeNode *tp = st.top();
st.pop();
v.push_back( tp->val );
if ( tp->right)
root = tp->right;
}
}
}
TreeNode* build_AVL_by_inorder(vector<int> &v, int l, int r) {
if ( l > r)
return NULL;
int mid = l + ((r - l) >> 1);
TreeNode *rt = new TreeNode(v[mid]);
rt->left = build_AVL_by_inorder( v, l, mid - 1);
rt->right = build_AVL_by_inorder( v, mid + 1, r);
return rt;
}
TreeNode* balanceBST(TreeNode* root) {
vector<int> v;
inorder_output( root, v);
TreeNode *ret;
int l = 0;
int r = static_cast<int>(v.size() - 1);
return build_AVL_by_inorder( v, l, r);
}
};
这个策略的正确性证明:
我们用数学归纳法来证明,
我们令k
表示树中的节点的个数。
显然 k = 1 k=1 k=1或者 k = 2 k=2 k=2时,这样构造的二叉树平衡。
我们现在假设 k = n k=n k=n时这个策略构造的二叉树平衡,我们要
推出 k = n + 1 k=n+1 k=n+1时这个策略构造的二叉树也平衡。
事实上我们并只需要关心左右两子树的高度差是否平衡就可以了。
我们用 l n ln ln各 r n rn rn分别表示由这种策略构造的左子树和右子树
分成两种情况:
当 n n n为偶数时,对于节点数为 n + 1 n+1 n+1构造的树 l n = r n = n 2 ln=rn=\frac{n}{2} ln=rn=2n,
由于是同一种策略同样的节点数,因此树高肯定一样,
因此 n n n为偶数时树平衡。
当 n n n为奇数时,对于节点数为 n + 1 n+1 n+1构造的树 l n = n − 1 2 , r n = n + 1 2 ln=\frac{n-1}{2},rn=\frac{n+1}{2} ln=2n−1,rn=2n+1。
我们令 d k d_k dk表示,以上面这种策略构造的二叉树的深度。
现在我们只需要证明对于
d k + 1 − d k ≤ 1 d_{k+1}-d_{k} \le 1 dk+1−dk≤1
上面的树就平衡了,整个证明就成立了。
首先我们容易得到
d k = ⌊ log 2 k ⌋ + 1 d_k = \lfloor \log_2 k\rfloor +1 dk=⌊log2k⌋+1
实际上并不容易得到,我也不知道怎么得到的真接看的答案。
应该是一个个试,最后得出规律的。
首先, 我们可以得出,当 k ≥ 1 k \ge 1 k≥1时
log 2 ( k + 1 ) − log 2 k ≤ 1 \log_2 (k+1) - \log_2k \le 1 log2(k+1)−log2k≤1
因为
log 2 ( k + 1 ) − log 2 k = log 2 k + 1 k = log 2 ( 1 + 1 k ) k ≥ 1 , 1 + 1 k ≤ 2 log 2 ( 1 + 1 k ) ≤ 1 \log_2{(k+1)}-\log_2k = \log_2{\frac{k+1}{k}}\\=\log_2({1+\frac{1}{k}})\\ k\ge1,1+\frac{1}{k} \le2\\ \log_2{(1+\frac{1}{k})} \le1 log2(k+1)−log2k=log2kk+1=log2(1+k1)k≥1,1+k1≤2log2(1+k1)≤1
现在我们要由这个结论来推我们要的结果,有两种方式。
先来说反证法
我们令 a = log 2 k a=\log_2 k a=log2k, b = log 2 ( k + 1 ) b=\log_2{(k+1)} b=log2(k+1),
我们假设存在某个 k ≥ 1 k\ge1 k≥1,使得
b − a ≥ 2 b-a \ge 2 b−a≥2成立;
那么必然存在某个整数 n n n使得 a < n a<n a<n且 b ≥ n + 2 b\ge n+2 b≥n+2成立,
因此 b − a > ( n + 2 ) − n = 2 b-a >(n+2)-n=2 b−a>(n+2)−n=2即 b − a > 2 b-a>2 b−a>2成立,但由上面我们
的结论知道 b − a = log 2 ( k + 1 ) − log 2 k ≤ 1 b-a=\log_2(k+1)-\log_2k \le 1 b−a=log2(k+1)−log2k≤1。
因此产生了矛盾,因此假设不成立,
即对所有的 k ≥ 1 k\ge1 k≥1
b − a = ⌊ log 2 ( k + 1 ) ⌋ − ⌊ log 2 k ⌋ ≤ 1 b-a=\lfloor \log_2{(k+1)}\rfloor -\lfloor \log_2{k}\rfloor \le1 b−a=⌊log2(k+1)⌋−⌊log2k⌋≤1
成立。
下面再来说正向证明:
我们令 k = 2 r + b , 0 ≤ b < 2 r , 2 r ≤ k < 2 r + 1 k=2^r+b, 0\le b < 2^r, 2^r \le k < 2^{r+1} k=2r+b,0≤b<2r,2r≤k<2r+1,即 r = ⌊ log 2 k ⌋ r = \lfloor \log_2 k\rfloor r=⌊log2k⌋,
我们容易得到: k + 1 ∈ ( 2 r , 2 r + 1 ] k+1 \in (2^r,2^{r+1}] k+1∈(2r,2r+1] ,
因此 r + 1 = ⌈ log 2 ( k + 1 ) ⌉ r+1 = \lceil \log_2{(k+1)}\rceil r+1=⌈log2(k+1)⌉,
我们要证的式子实际上就是
⌊ log 2 ( k + 1 ) ⌋ − ⌊ log 2 k ⌋ ≤ 1 ⇔ ⌊ log 2 ( k + 1 ) ⌋ ≤ r + 1 \lfloor \log_2{(k+1)}\rfloor -\lfloor \log_2{k}\rfloor \le1 \Leftrightarrow \\ \lfloor \log_2{(k+1)}\rfloor \le r+1 ⌊log2(k+1)⌋−⌊log2k⌋≤1⇔⌊log2(k+1)⌋≤r+1
我们将 r + 1 r+1 r+1替换成 ⌈ log 2 ( k + 1 ) ⌉ \lceil \log_2{(k+1)}\rceil ⌈log2(k+1)⌉得
⌊ log 2 ( k + 1 ) ⌋ ≤ ⌈ log 2 ( k + 1 ) ⌉ \lfloor \log_2{(k+1)} \rfloor \le \lceil \log_2{(k+1)} \rceil ⌊log2(k+1)⌋≤⌈log2(k+1)⌉
这个式子显然成立,因此证明成立。
同样我们可以由 k + 1 ∈ ( 2 r , 2 r + 1 ] k+1 \in(2^r,2^r+1] k+1∈(2r,2r+1], ⌊ log 2 ( k + 1 ) ⌋ \lfloor \log_2{(k+1)}\rfloor ⌊log2(k+1)⌋必然
只能为 r r r或者 r + 1 r+1 r+1,从而得到
⌊ log 2 ( k + 1 ) ⌋ − ⌊ log 2 k ⌋ \lfloor \log_2{(k+1)}\rfloor -\lfloor \log_2{k}\rfloor \ ⌊log2(k+1)⌋−⌊log2k⌋
只能为 0 0 0或者 1 1 1得到证明。