leetcode_数组类算法_数组中的第k个最大元素

数组中的第k个最大元素

描述:同上

错误代码

c语言代码⬇️

错误原因:无

正确代码

c语言代码⬇️

//思路:先排序,然后再找第k大的数

void quicksort(int* ary, int low, int high){
    int l = low;
    int r = high;
    if(l >= r)
        return ;
    int pivot = l;
    int key = ary[pivot];
    while(l < r){
        while(l < r && ary[r] <= key)
            r--;
        ary[pivot] = ary[r];
        pivot = r;

        while(l < r && ary[l] >= key)
            l++;
        ary[pivot] = ary[l];
        pivot = l;
    }
    ary[pivot] = key;
    quicksort(ary, low, pivot-1);
    quicksort(ary, pivot+1, high);
}

int findKthLargest(int* nums, int numsSize, int k){
    quicksort(nums, 0, numsSize-1);
    return nums[k-1];
}

填坑法快排,彳亍

执行结果:
通过
显示详情
执行用时:80 ms
, 在所有 C 提交中击败了22.32%的用户
内存消耗:6.2 MB
, 在所有 C 提交中击败了54.79%的用户
通过测试用例:
32 / 32
快排时间复杂度nlog(n)在c语言中击败20%左右的用户,看来此方法仍然有点慢,应该有更好的方法。
思考🤔

思考结果2:用一个大小为k的数组来存放当前遍历的最大的k个值,每遍历一个值就和新建的数组从尾到头比较并进行替换判断,似乎时间复杂度可以达到0(n2),应该是不如快排。

思考结果3:申请大片存储空间,用数组存储每个数字出现的次数,再从尾到头统计次数,到达k时输出下标,用空间换时间,时间复杂度o(n),空间复杂度也会达到o(n)。

思之无果,上网搜之,应用堆排序。
代码如下⬇️
堆排序思路:
1.将数组视为一个堆
2.进行建堆操作,从第一个非叶节点(length/2)开始往上遍历,不断的调整至符合堆的性质
3.开始堆排序,将堆顶元素与最后元素进行交换,将交换后的堆看成两个堆,1⃣️由原堆顶元素组成的有序堆,2⃣️由最后元素交换过去后的待调整的无序堆。现在对堆顶元素进行调整,调整好后继续进行步骤3.
最后可形成有序堆

//思路:先排序,然后再找第k大的数,此处是建立大顶堆,排序后由小到大

void adjustHeap(int *arr, int i, int length){
    int temp = arr[i];

    for(int k = i*2+1; k < length; k = k*2+1){
        if(k+1 < length && arr[k+1] > arr[k] ){
            k++;
        }

        if(arr[k] > temp){
            arr[i] = arr[k];
            i = k;
        }else{
            break;
        }
    }
    arr[i] = temp;
}

void heapSort(int* arr, int length){
    for(int i = length/2 - 1; i >= 0; i--){
        adjustHeap(arr, i, length);
    }

    for(int i = length - 1; i > 0; i--){
        swap(&arr[i], &arr[0]);
        adjustHeap(arr, 0, i);
    }
}

void swap(int* a,int* b){
    int t = *a;
    *a = *b;
    *b = t;
}

int findKthLargest(int* nums, int numsSize, int k){
    heapSort(nums, numsSize);
    return nums[numsSize - k];
}

执行结果:通过
显示详情
执行用时:8 ms, 在所有 C 提交中击败了82.05%的用户
内存消耗:6.1 MB, 在所有 C 提交中击败了58.47%的用户
相比于前者提高明显

趁热打铁,通过建立小顶堆,获得一个递减的序列

//趁热打铁,写一个小顶堆来联系

void adjustHeap(int* arr, int i, int length){
    int temp = arr[i];
    for(int k = i*2+1; k < length; k = k*2+1){
        if(k+1 < length && arr[k+1] < arr[k]){
            k++;
        }
        if(arr[k] < temp){
            arr[i] = arr[k];
            i = k;
        }else{
            break;
        }
    }
    arr[i] = temp;//此处极易忘记,应该给调整的元素一个安家之所
    			  //!!!!!应加倍小心
}

void swap(int* a, int* b){
    int t = *a;
    *a = *b;
    *b = t;
}

void heapSort(int* arr, int length){
    for(int i = length/2-1; i >= 0; i--){
        adjustHeap(arr, i, length);
    }
    for(int i = length-1; i > 0; i--){
        swap(&arr[0], &arr[i]);
        adjustHeap(arr, 0, i);
    }
}

int findKthLargest(int* nums, int numsSize, int k){
    heapSort(nums, numsSize);
    return nums[k-1];
}

第二天练习堆排序,代码如下⬇️

// 再来一遍堆排序,建立大顶堆,递增序列
void adjustHeap(int* arr, int i, int length){
    int pivot = arr[i];

    for(int k = i*2+1; k < length; k = k*2+1){
        if(k+1 < length && arr[k+1] > arr[k]){
            k++;
        }
        if(arr[k] > pivot){
            arr[i] = arr[k];
            i = k;
        }else{
            break;
        }
    }

    arr[i] = pivot;
}

void swap(int* a, int* b){
    int t = *a;
    *a = *b;
    *b = t;
}

void heapSort(int* arr, int length){
    for(int i = length/2-1; i >= 0; i--){
        adjustHeap(arr, i, length);
    }
    for(int i = length-1; i > 0; i--){
        swap(&arr[i], &arr[0]);
        adjustHeap(arr, 0, i);
    }
}
int findKthLargest(int* nums, int numsSize, int k){
    heapSort(nums, numsSize);
    return nums[numsSize-k];
}

容易出错的地方:再heapSort的第二个for循环里的adjustHeap方法中的第三个参数,随着每一次堆顶和堆尾的交换,原有堆的长度在不断的减小,所以应该是i,而不应该是length。

原参考的代码中,在adjustHeap函数中,被比较的元素命名为temp,私以为命名为pivot更加合适,被调整的元素更像快排中的pivot元素,一直用做和其他元素进行比较,命名为pivot更加见名知义。

时隔数天,再来一遍堆排序

//堆排序练习第三遍
//建立小顶堆,堆排序后数列递减有序

void adjustHeap(int *arr, int i, int length){

    int pivot = arr[i];
    for(int k = i*2+1; k < length; k = k*2+1){
        if(k+1 < length && arr[k+1] < arr[k]){
            k++;
        }

        if(arr[k] < pivot){
            arr[i] = arr[k];
            i = k;
        }
    }
    arr[i] = pivot;
}

void swap(int *a, int *b){
    int t = *a;
    *a = *b;
    *b = t;
}

void heapSort(int *arr, int length){
    for(int i = length/2-1; i >= 0; i--){
        adjustHeap(arr, i, length);
    }

    for(int i = length-1; i > 0; i--){
        swap(&arr[0], &arr[i]);
        adjustHeap(arr, 0, i);
    }
}

int findKthLargest(int* nums, int numsSize, int k){
    heapSort(nums, numsSize);
    return nums[k-1];
}

总结

总结:桥洞底下盖小被,啊堆堆堆

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值