剑指 Offer 41. 数据流中的中位数
// js没有堆结构真的太伤了,注意在两个堆都为空时,虽然是向min插入,但是后面插入到了max,所以元素数为奇数时是返回max的堆顶元素。在Insert时,先插入到哪个堆与后面的中位数值对应即可。
var MedianFinder = function () {
class Heap {
constructor(cmp = (x, y) => x < y) {
this.arr = [];
this.arr.push(0);
this.cmp = cmp;
}
sink() {
let index = 1;
while (index * 2 < this.arr.length) {
let left = index * 2;
const tmp = this.arr[index];
if ((left + 1) < this.arr.length && this.cmp(this.arr[left + 1], this.arr[left]/*&&this.cmp(this.arr[left+1],tmp)*/)) {
this.arr[index] = this.arr[left + 1];
index = left + 1;
this.arr[index] = tmp;
continue;
// 这里有个逻辑错误
//右子节点大于左子节点也不一定右子结点大于根节点
//但是由于sink是把堆尾的元素向前移动的
//所以代码居然ac了?
//这个地方加上右子节点和根节点的比较更严谨一点
}
if (this.cmp(this.arr[left], tmp)) {
this.arr[index] = this.arr[left];
this.arr[left] = tmp;
index = left;
continue;
}
break;
}
}
swim() {
let index = this.arr.length - 1;
while (index > 1 && this.cmp(this.arr[index], this.arr[Math.floor(index / 2)])) {
const tmp = this.arr[index];
this.arr[index] = this.arr[Math.floor(index / 2)];
this.arr[Math.floor(index / 2)] = tmp;
index = Math.floor(index / 2);
}
}
push(val) {
this.arr.push(val);
this.swim();
}
pop() {
const store = this.arr[1];
this.arr[1] = this.arr[this.arr.length - 1];
this.arr.pop();
this.sink();
return store;
}
peak() {
return this.arr[1] ? this.arr[1] : 0;
}
size() {
return this.arr.length-1;
}
}
this.min = new Heap();// 存储较大值
this.max = new Heap((x, y) => x > y);// 存储较小值
};
/**
* @param {number} num
* @return {void}
*/
MedianFinder.prototype.addNum = function (num) {
if (this.min.size() != this.max.size()) {
this.max.push(num);
this.min.push(this.max.pop());
}
else {
this.min.push(num);
this.max.push(this.min.pop());
}
};
/**
* @return {number}
*/
MedianFinder.prototype.findMedian = function () {
console.log(this.min.peak() , this.max.peak())
return this.min.size() == this.max.size() ? (this.min.peak() + this.max.peak()) / 2 : this.max.peak();
};
剑指 Offer 55 - II. 平衡二叉树
//自底向上,如果在第一次不平衡时能直接返回效率会更高一点。
var isBalanced = function(root) {
return helper(root)!=-1;
};
var helper = (root)=>{
if(!root) return 0;
if(helper(root.left)==-1){
return -1;
}
if(helper(root.right)==-1){
return -1;
}
return Math.abs(helper(root.left)-helper(root.right))>1?-1:Math.max(helper(root.left),helper(root.right))+1;
}
剑指 Offer 68 - II. 二叉树的最近公共祖先
// 找到递归的终止条件,和判断标准即可。更新公共祖先需要两节点分别在左右子树中,或者某个节点在另一个结点的子树中。
var lowestCommonAncestor = function (root, p, q) {
let ans = root;
let help = (root)=>{
if(!root) return false;
let left = help(root.left);
let right = help(root.right);
if((left&&right)||(root==p||root==q)&&(left||right)){
ans = root;
}
return left||right||root==p||root==q;// 为了能遍历到p和q
}
help(root);
return ans;
};
剑指 Offer 33. 二叉搜索树的后序遍历序列
// 注意边界条件,找到一个大于根节点则后面的必须都大于根节点,否则就不平衡了。
var verifyPostorder = function(postorder) {
if(postorder.length==0) return true;
let dfs = (i,j)=>{
if(i>=j) return true;
let mid = i;
while(postorder[mid]<postorder[j]) mid++;
let right = mid;
while(postorder[right]>postorder[j]) right++;
return right==j&&dfs(i,mid-1)&&dfs(mid,j-1);
}
return dfs(0,postorder.length-1)
};