力扣刷题-2099. 找到和最大的长度为 K 的子序列

题目

题解

本题目的就是求数组中前k个大的数,因此我将它拿来练习一下堆排序。

堆排序可以做出来,但结果会不符合力扣答案按序号的要求。

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

//建立小根堆解决问题

//堆结构
typedef struct Heap{
    int* data;
    int size;
}Heap;

//堆初始化
void initialHeap(Heap* h){
    for(int i = (h->size-1)/2;i >= 1;i--){
        //特殊情况:序号最大的非叶节点可能会没有右孩子
        if (i == (h->size - 1) / 2 && i * 2 + 1 == h->size) {
            if (h->data[i * 2] < h->data[i]) {
                int temp = h->data[i];
                h->data[i] = h->data[2 * i];
                h->data[2 * i] = temp;
            }
            continue;
        }
        //其他调整调整
        if(h->data[i*2]<h->data[i] && h->data[i*2]<=h->data[2*i+1]){
            int temp = h->data[i];
            h->data[i] = h->data[2*i];
            h->data[2*i] = temp;
        }else if(h->data[i*2+1]<h->data[i] && h->data[i*2+1]<=h->data[2*i]){
            int temp = h->data[i];
            h->data[i] = h->data[2*i+1];
            h->data[2*i+1] = temp;
        }
    }
}

//更新堆
void renewHeap(Heap* h, int x){
    if(x <= h->data[1]) return;
    h->data[1] = x;
    //从上往下调整,把最小的放在根上
    int index = 1;  //目前正在调整的索引
    while(index <= (h->size-1)/2){
        //特殊情况:序号最大的非叶节点可能会没有右孩子
        if (index == (h->size - 1) / 2 && index * 2 + 1 == h->size) {
            if (h->data[index * 2] < h->data[index]) {
                int temp = h->data[index];
                h->data[index] = h->data[2 * index];
                h->data[2 * index] = temp;
            }
            break;
        }
        //其他非叶结点的调整
        if(h->data[index]<=h->data[2*index] && h->data[index]<=h->data[2*index+1]){ //该索引位置已经比左右两孩子的值都小了,无需调整
            break;
        }
        if(h->data[index*2]<h->data[index] && h->data[index*2]<=h->data[2*index+1]){
            int temp = h->data[index];
            h->data[index] = h->data[2*index];
            h->data[2*index] = temp;
            index = index*2;
        }else if(h->data[index*2+1]<h->data[index] && h->data[index*2+1]<=h->data[2*index]){
            int temp = h->data[index];
            h->data[index] = h->data[2*index+1];
            h->data[2*index+1] = temp;
            index = index*2+1;
        }
    }
}

int* maxSubsequence(int* nums, int numsSize, int k, int* returnSize){
    //声明一个堆,其中堆的大小是k+1,因为索引为0的位置不用,实际存放的数据还是k个。
    Heap* h = (Heap*)malloc(sizeof(Heap));
    h->size = k+1;
    h->data = (int*)malloc(sizeof(int)*h->size);
    //往堆内填充初试数据
    for(int i = 0;i < k;i++){
        h->data[i+1] = nums[i];
    }
    //初始化堆
    initialHeap(h);
    //更新堆
    for(int i = k;i < numsSize;i++){
        renewHeap(h,nums[i]);
    }
    //要符合返回结果的格式,将堆中的元素移至从索引0开始
    *returnSize = k;
    for(int i = 0;i < k;i++){
        h->data[i] = h->data[i+1];
    }
    return h->data;
}

要点

  1. 堆排序的使用:先填充数组;然后初始化数组(从序号最大的非叶结点开始从下至上);最后依次更新数组,更新的过程是替换根结点之后从上至下进行调整,且只调整被涉及到的结点。

  1. 堆排序和完全二叉树一样,如果存储在数组中,是从索引为1的位置开始存储。只有这样才符合索引为i的结点其左孩子索引为2i,其右孩子索引为2i+1的公式。

  1. 堆排序要考虑最后一个非叶结点可能会出现没有右孩子的情况。

  1. 若要求前k个最大值的话,堆排序建立最小堆。

  1. 若要求前k个最小值的话,堆排序建立最大堆。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东东咚咚东

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值