这个题之前写过,求最小的k个数,这次力求自己写出来,并且写成一个模版,
然后我自己写,我写的思路运行超时,我写的大顶堆,报错真是服了,但是我写的大顶堆最后经过n次实验也是对的啊 我真是服了
又经过n次排查终于找到问题了,
这道题比较经典,明天还写这道题,用快排算法尝试
一下为排查过正确代码\
/**
* @param {number[]} arr
* @param {number} k
* @return {number[]}
*/
function smallestK(arr, k) {
/* if (arr.length < k) {
return arr;
} */
// const temp = arr.slice(0, k-1);
const h = new Heap()
for (let i = 0; i < arr.length; i++) {
const e = arr[i];
// 先插入k个数到最小堆中
if (i < k) {
h.insert(e)
} else if (e < h.container[0]) {
// 当前元素比 最小栈顶元素(也就是最小栈中最小的值) 还小才堆
// 保持最小堆一直是k个数 所以 需要先弹出 在入堆
h.pop();
h.insert(e)
}
}
return h.container;
}
const defaultCmp = (x, y) => x > y;
const swap = (arr, i, j) => [arr[i], arr[j]] = [arr[j], arr[i]];
class Heap1 {
constructor(cmp = defaultCmp) {
this.container = [];
this.cmp = cmp;
}
// 从下往上 入堆操作
insert(data) {
const { container, cmp } = this;
container.push(data);
let index = this.size() - 1;
while (index) {
let parent = index - 1 >> 1;
// 如果当前元素不大于当前元素的根元素 就停止
if (!cmp(container[index], container[parent])) {
return;
}
// 否则 交换
swap(container, index, parent);
// 上移动
index = parent;
}
}
// 弹出堆顶元素操作
pop() {
const { container, cmp } = this;
if (!this.size()) {
return null;
}
// 先交换首位节点
swap(container, 0, this.size() - 1);
// 交换完以后 弹出最后一个 即是刚刚交换道末尾的 堆顶元素
const res = container.pop();
// 开始 从上往下比较重新排序 需要堆顶坐标一个变量index,和另外一个标量用来做对比叫做exchange
let index = 0;
let exchange = 2 * index + 1; // 先赋值做节点
let length = this.size();
// 只要不越界就开始循环
while (exchange < length) {
// 判断有右节点不越界 并且右子节点比左节点大 则继续交换
let right = 2 * index + 2;
if (right < length && cmp(container[right], container[exchange])) {
exchange = right;
}
// exhchage 不比 index 大 就终止 break
if (!cmp(container[exchange], container[index])) {
break;
}
// 交换exchange和index
swap(container, exchange, index);
// 重置index和exchange 为下一步做对比
index = exchange;
exchange = 2 * index + 1;
}
// 返回弹出的最大值 即堆顶元素
return res;
}
// 堆的个数
size() {
return this.container.length;
}
// 堆顶元素
peek() {
if (this.size()) {
return this.container[0];
}
return null;
}
}
class Heap {
constructor(cmp = defaultCmp) {
// this.q = [];
this.container = [];
this.cmp = cmp;
}
// 入堆 从下往上插入 又称 上浮
insert(v) {
const { container, cmp } = this;
container.push(v);
let i = container.length - 1;
while (i) {
let p = (i-1) >> 1;
if (cmp(container[i], container[p])) {
swap(container, i, p)
i = p;
} else {
break;
}
}
}
// 弹出堆顶,并返回
pop1() {
const { container, cmp } = this;
let l = container.length;
swap(container, 0, l - 1);
const res = container.pop();
const length = l;
let index = 0,
exchange = index * 2 + 1;
while (exchange < length) {
// // 以最大堆的情况来说:如果有右节点,并且右节点的值大于左节点的值
let right = index * 2 + 2;
// ------
if (right < length && cmp(container[right], container[exchange])) {
exchange = right;
}
if (cmp(container[exchange], container[index])) {
swap(container, exchange, index);
index = exchange;
exchange = index * 2 + 1;
} else {
return;
}
}
return res;
}
// 出堆 从下往上 又称 下沉
pop() {
const { container, cmp } = this;
let i = 0;
let l = container.length;
let e = 2 * i + 1;
swap(container, i, l - 1);
container.pop();
while (e < l) {
let r = 2 * i + 2;
// 这里面cmp 参数穿多了
if (r < l && cmp( container[r], container[e])) {
e = r;
}
if (cmp( container[e], container[i])) {
swap(container, i, e);
i = e;
e = 2 * i + 1;
} else {
break;
}
}
}
}
一下有错误代码又正确代码
/**
* @param {number[]} arr
* @param {number} k
* @return {number[]}
*/
// function smallestK(arr, k) {
// /* if (arr.length < k) {
// return arr;
// } */
// // const temp = arr.slice(0, k-1);
// const h = new Heap()
// for (let i = 0; i < arr.length; i++) {
// const e = arr[i];
// // 先插入k个数到最小堆中
// if (i < k) {
// h.insert(e)
// } else if (e < h.container[0]) {
// // 当前元素比 最小栈顶元素(也就是最小栈中最小的值) 还小才堆
// console.log(i,h.container, h.container[0])
// // 保持最小堆一直是k个数 所以 需要先弹出 在入堆
// h.pop();
// h.insert(e)
// }
// }
// const ans = [];
// for (let i = 0; i < k; i++) {
// ans.unshift(h.pop())
// }
// return ans;
// }
const smallestK = (arr, k) => {
const minHeap = new Heap();
for (const num of arr) {
minHeap.insert(num);
}
const res = [];
for (let i = 0; i < k; i++) {
res.push(minHeap.pop());
}
return minHeap.container;
};
const defaultCmp = (x, y) => x < y;
const swap = (arr, i, j) => [arr[i], arr[j]] = [arr[j], arr[i]];
class Heap {
constructor(cmp = defaultCmp) {
this.container = [];
this.cmp = cmp;
}
// 从下往上 入堆操作
insert(data) {
const { container, cmp } = this;
container.push(data);
let index = this.size() - 1;
while (index) {
let parent = index - 1 >> 1;
// 如果当前元素不大于当前元素的根元素 就停止
if (!cmp(container[index], container[parent])) {
return;
}
// 否则 交换
swap(container, index, parent);
// 上移动
index = parent;
}
}
// 弹出堆顶元素操作
pop() {
const { container, cmp } = this;
if (!this.size()) {
return null;
}
// 先交换首位节点
swap(container, 0, this.size() - 1);
// 交换完以后 弹出最后一个 即是刚刚交换道末尾的 堆顶元素
const res = container.pop();
// 开始 从上往下比较重新排序 需要堆顶坐标一个变量index,和另外一个标量用来做对比叫做exchange
let index = 0;
let exchange = 2 * index + 1; // 先赋值做节点
let length = this.size();
// 只要不越界就开始循环
while (exchange < length) {
// 判断有右节点不越界 并且右子节点比左节点大 则继续交换
let right = 2 * index + 2;
if (right < length && cmp(container[right], container[exchange])) {
exchange = right;
}
// exhchage 不比 index 大 就终止 break
if (!cmp(container[exchange], container[index])) {
break;
}
// 交换exchange和index
swap(container, exchange, index);
// 重置index和exchange 为下一步做对比
index = exchange;
exchange = 2 * index + 1;
}
// 返回弹出的最大值 即堆顶元素
return res;
}
// 堆的个数
size() {
return this.container.length;
}
// 堆顶元素
peek() {
if (this.size()) {
return this.container[0];
}
return null;
}
}
// const swap = (arr, i, j) => [arr[i], arr[j]] = [arr[j], arr[i]];
// const defaultCmp = (a, b) => a < b;
// class Heap {
// constructor(cmp = defaultCmp) {
// this.q = [];
// this.cmp = cmp;
// }
// // 入堆 从下往上插入 又称 上浮
// insert(v) {
// const { q, cmp } = this;
// q.push(v);
// let i = q.length - 1;
// while (i) {
// let p = i-1 >> 1;
// if (p && cmp(q[p], cmp[q[i]])) {
// swap(q, i, p)
// i = p;
// } else {
// break;
// }
// }
// }
// // 出堆 从下往上 又称 下沉
// pop() {
// const { q, cmp } = this;
// let i = 0;
// let l = q.length;
// let e = 2 * i + 1;
// swap(q, i, l - 1);
// q.pop();
// while (e < l) {
// let r = 2 * i + 2;
// if (r < l && cmp(q, q[r], q[l])) {
// e = r;
// }
// if (cmp(q, q[i], q[e])) {
// swap(q, i, e);
// i = e;
// e = 2 * i + 1;
// } else {
// break;
// }
// }
// }
// }