题目:传送门
法一:(投机取巧法)
题目的意思就是在一棵BST中找到一个数X,然后得到这个数是第几大的(千万不要理解成找第X个大的数了)
然后我们就可以利用BST的特点来求解:中序遍历为有序序列
那么问题就转换成了在有序序列中找一个数,这时候可以暴力枚举,可以二分,想咋滴咋滴,反正就是能做了
Code:
int a[1000], cnt; //a数组存储中序遍历的序列
void inOrder(BinTree T){ //中序遍历,这个必须得会的吧!
if(!T) return;
inOrder(T->Left);
a[cnt++] = T->Key;
inOrder(T->Right);
}
int KthLargest ( BinTree T, int X ){
inOrder(T); //先走一波中序遍历,得到a数组
for(int i = cnt - 1; i >= 0; i--) //然后倒着枚举,因为a数组是升序的,而我们要找第k大的,所以倒着更符合逻辑,当然正着枚举也OK,也可以二分
if(a[i] == X) return cnt - i; //找到了就返回对应的次序
return 0; //没找到返回0
}
显然出题人的意思不是让你中序遍历然后求,虽然结果对了!!!
法二:递归做法
递归不太好解释,就直接上代码了,注释还是比较详细的:
int KthLargest ( BinTree T, int X ){
if(!T) return 0; //没找到,返回0
if(T->Key == X){ //找到了,那么 该结点的排名 = 该结点后继的排名 + 1
BinTree temp = T->Right;
if(!temp) return 1; //不存在右子树,那么就是最大的
while(temp->Left) temp = temp->Left; //找到后继
return KthLargest(T->Right, temp->Key) + 1; //返回 后继的排名 + 1
}
if(T->Key > X){ //大于X,就去左子树找
int t = KthLargest(T->Left, X);
if(!t) return 0; //在左子树上没找到,就返回0
return t + KthLargest(T, T->Key); //否则返回X 在左子树上的排名 + 当前根节点的排名
}
return KthLargest(T->Right, X); //小于X, 就去右子树上找(在右子树上的排名即为在整棵树上的排名)
}
今天又看到了lsq大佬的方法,详见 大佬解法