Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >2020-03-02:在无序数组中,如何求第K小的数?

2020-03-02:在无序数组中,如何求第K小的数?

原创
作者头像
福大大架构师每日一题
修改于 2021-03-03 01:35:48
修改于 2021-03-03 01:35:48
9130
举报

2020-03-02:在无序数组中,如何求第K小的数?

福哥答案2021-03-02:

1.堆排序。时间复杂度:O(N*lgK)。有代码。

2.单边快排。时间复杂度:O(N)。有代码。

3.bfprt算法。时间复杂度:O(N)。有代码。

代码用golang编写,代码如下:

代码语言:txt
AI代码解释
复制
package main

import (
    "container/heap"
    "fmt"
    "math/rand"
    "sort"
)

func main() {

    //1 2 3 4 5 6 7
    arr := []int{1, 2, 3, 4, 5, 10, 9, 8, 7, 6}
    ret := minKth1(arr, 7)
    fmt.Println("1.堆排序:", ret)

    ret = minKth2(arr, 7)
    fmt.Println("2.单边快排:", ret)

    ret = minKth3(arr, 7)
    fmt.Println("3.bfprt算法:", ret)

}

// 利用大根堆,时间复杂度O(N*logK)
func minKth1(arr []int, k int) int {
    maxHeap := &IntHeap{}
    heap.Init(maxHeap)
    for i := 0; i < k; i++ {
        heap.Push(maxHeap, arr[i])
    }
    for i := k; i < len(arr); i++ {
        heap.Push(maxHeap, arr[i])
        heap.Pop(maxHeap)
        //heap.Push(maxHeap, arr[i])
    }
    return heap.Pop(maxHeap).(int)
}

type IntHeap sort.IntSlice

func (h IntHeap) Len() int           { return len(h) }
func (h IntHeap) Less(i, j int) bool { return !(h[i] < h[j]) }
func (h IntHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

//func (h IntHeap) Len() int           { return sort.IntSlice(h).Len() }
//func (h IntHeap) Less(i, j int) bool { return !sort.IntSlice(h).Less(i, j) }
//func (h IntHeap) Swap(i, j int)      { sort.IntSlice(h).Swap(i, j) }

func (h *IntHeap) Push(x interface{}) {
    //fmt.Println("push----")
    // Push and Pop use pointer receivers because they modify the slice's length,
    // not just its contents.
    *h = append(*h, x.(int))
}

func (h *IntHeap) Pop() interface{} {

    old := *h
    n := len(old)
    x := old[n-1]
    *h = old[0 : n-1]
    return x
}

// 改写快排,时间复杂度O(N)
// k >= 1
func minKth2(arr []int, k int) int {
    arrc := make([]int, len(arr))
    copy(arrc, arr)
    return process2(arrc, 0, len(arr)-1, k-1)
}

// arr 第k小的数
// process2(arr, 0, N-1, k-1)
// arr[L..R]  范围上,如果排序的话(不是真的去排序),找位于index的数
// index [L..R]
func process2(arr []int, L int, R int, index int) int {
    if L == R { // L = =R ==INDEX
        return arr[L]
    }
    // 不止一个数  L +  [0, R -L]
    pivot := arr[L+rand.Intn(R-L)]
    rang := partition(arr, L, R, pivot)
    if index >= rang[0] && index <= rang[1] {
        return arr[index]
    } else if index < rang[0] {
        return process2(arr, L, rang[0]-1, index)
    } else {
        return process2(arr, rang[1]+1, R, index)
    }
}

func partition(arr []int, L int, R int, pivot int) []int {
    less := L - 1
    more := R + 1
    cur := L
    for cur < more {
        if arr[cur] < pivot {
            less++
            arr[less], arr[cur] = arr[cur], arr[less]
            cur++
        } else if arr[cur] > pivot {
            more--
            arr[cur], arr[more] = arr[more], arr[cur]
        } else {
            cur++
        }
    }
    return []int{less + 1, more - 1}
}

// 利用bfprt算法,时间复杂度O(N)
func minKth3(arr []int, k int) int {
    arrc := make([]int, len(arr))
    copy(arrc, arr)
    return bfprt(arrc, 0, len(arr)-1, k-1)
}

// arr[L..R]  如果排序的话,位于index位置的数,是什么,返回
func bfprt(arr []int, L int, R int, index int) int {
    if L == R {
        return arr[L]
    }
    // L...R  每五个数一组
    // 每一个小组内部排好序
    // 小组的中位数组成新数组
    // 这个新数组的中位数返回
    pivot := medianOfMedians(arr, L, R)
    rang := partition(arr, L, R, pivot)
    if index >= rang[0] && index <= rang[1] {
        return arr[index]
    } else if index < rang[0] {
        return bfprt(arr, L, rang[0]-1, index)
    } else {
        return bfprt(arr, rang[1]+1, R, index)
    }
}

// arr[L...R]  五个数一组
// 每个小组内部排序
// 每个小组中位数领出来,组成marr
// marr中的中位数,返回
func medianOfMedians(arr []int, L int, R int) int {
    size := R - L + 1
    offset := 0
    if size%5 != 0 {
        offset = 1
    }
    mArr := make([]int, size/5+offset)
    for team := 0; team < len(mArr); team++ {
        teamFirst := L + team*5
        // L ... L + 4
        // L +5 ... L +9
        // L +10....L+14
        mArr[team] = getMedian(arr, teamFirst, getMin(R, teamFirst+4))
    }
    // marr中,找到中位数
    // marr(0, marr.len - 1,  mArr.length / 2 )
    return bfprt(mArr, 0, len(mArr)-1, len(mArr)/2)
}

func getMedian(arr []int, L int, R int) int {
    insertionSort(arr, L, R)
    return arr[(L+R)/2]
}

func insertionSort(arr []int, L int, R int) {
    for i := L + 1; i <= R; i++ {
        for j := i - 1; j >= L && arr[j] > arr[j+1]; j-- {
            arr[j], arr[j+1] = arr[j+1], arr[j]
        }
    }
}
func getMin(a int, b int) int {
    if a < b {
        return a
    } else {
        return b
    }
}

执行结果如下:

在这里插入图片描述
在这里插入图片描述

左神java代码

评论

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
2021-03-04:一块金条切成两半,是需要花费和长度数值一样的铜板的
2021-03-04:一块金条切成两半,是需要花费和长度数值一样的铜板的。比如长度为20的金条,不管怎么切,都要花费20个铜板。 一群人想整分整块金条,怎么分最省铜板? 例如,给定数组{10,20,3
福大大架构师每日一题
2021/03/04
6060
2025-04-09:第 K 近障碍物查询。用go语言,我们有一个无限大的二维平面。给定一个正整数 k 和一个二维数组 quer
2025-04-09:第 K 近障碍物查询。用go语言,我们有一个无限大的二维平面。给定一个正整数 k 和一个二维数组 queries,每个元素 queries[i] = [x, y] 表示在平面上的坐标 (x, y) 处建立一个障碍物。系统保证在之前的查询中不会在同一坐标位置再建立障碍物。
福大大架构师每日一题
2025/04/09
770
2025-04-09:第 K 近障碍物查询。用go语言,我们有一个无限大的二维平面。给定一个正整数 k 和一个二维数组 quer
2021-04-22:给定很多线段,每个线段都有两个数[start, end],
2021-04-22:给定很多线段,每个线段都有两个数start, end,表示线段开始位置和结束位置,左右都是闭区间,规定:1)线段的开始和结束位置一定都是整数值,2)线段重合区域的长度必须>=1。返回线段最多重合区域中,包含了几条线段 。
福大大架构师每日一题
2021/05/04
3630
2021-04-22:给定很多线段,每个线段都有两个数[start, end],
​2021-03-30:给定一个整数组成的无序数组arr,值可能正、可能负、可能0。<=K
2021-03-30:给定一个整数组成的无序数组arr,值可能正、可能负、可能0。给定一个整数值K,找到arr的所有子数组里,哪个子数组的累加和<=K,并且是长度最大的。返回其长度。
福大大架构师每日一题
2021/03/30
5250
​2021-03-30:给定一个整数组成的无序数组arr,值可能正、可能负、可能0。<=K
滑动窗口最大值(LeetCode 239)
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
恋喵大鲤鱼
2023/12/18
2030
滑动窗口最大值(LeetCode 239)
理解 Golang 中的最大/最小堆、`heap` 与优先队列
最大堆、最小堆、 heap 、 优先队列在数据结构算法题目里都是一个东西。这里讨论 container/heap 的使用。
Piper破壳
2025/06/08
1580
文心一言 VS 讯飞星火 VS chatgpt (241)-- 算法导论17.3 7题
七、为动态整数多重集 S (允许包含重复值)设计一种数据结构,支持如下两个操作:① INSERT(S,x) 将 x 插入 S 中;② DELETE-LARGER-HALF(S) 将最大的 ⌈|S|/2⌉ 个元素从S中删除。解释如何实现这种数据结构,使得任意 m 个 INSERT 和 DELETE-LARGER-HAIF 操作的序列能在 O(m) 时间内完成。还要实现一个能在 O(|S|) 时间内输出所有元素的操作。如果要写代码,请用go语言。
福大大架构师每日一题
2024/04/25
1440
文心一言 VS 讯飞星火 VS chatgpt (241)-- 算法导论17.3 7题
2024-06-01:用go语言,给定一个从0开始索引的整数数组 nums 、两个正整数 k 和 dist 。 数组的代价是该数
2024-06-01:用go语言,给定一个从0开始索引的整数数组 nums 、两个正整数 k 和 dist 。
福大大架构师每日一题
2024/06/07
1820
2024-06-01:用go语言,给定一个从0开始索引的整数数组 nums 、两个正整数 k 和 dist 。 数组的代价是该数
2021-08-24:合并石头的最低成本。有 N 堆石头排成一排
2021-08-24:合并石头的最低成本。有 N 堆石头排成一排,第 i 堆中有 stonesi 块石头。每次移动(move)需要将连续的 K 堆石头合并为一堆,而这个移动的成本为这 K 堆石头的总数。找出把所有石头合并成一堆的最低成本。如果不可能,返回 -1 。
福大大架构师每日一题
2021/08/24
2620
2021-08-24:合并石头的最低成本。有 N 堆石头排成一排
2021-02-26:一个数组arr是二叉树的中序遍历结果,每条边的开销是父节...
2021-02-26:一个数组arr是二叉树的中序遍历结果,每条边的开销是父节点和子节点的乘积,总开销是所有边的开销之和。请问最小总开销是多少?
福大大架构师每日一题
2021/02/26
5610
2021-02-26:一个数组arr是二叉树的中序遍历结果,每条边的开销是父节...
LeetCode215.数组中的第K个最大元素
题目链接:LeetCode215  第一种做法,直接排序完了取,时间复杂度O(logn) class Solution { public int findKthLargest(int[]
mathor
2018/08/17
6930
LeetCode215.数组中的第K个最大元素
数据结构--堆 Heap
堆排序代码见:https://blog.csdn.net/qq_21201267/article/details/80993672#t7
Michael阿明
2021/02/20
3230
数据结构--堆 Heap
堆的Golang实现
在Leetcode刷题的时候,有些题目需要自己实现一个堆的结构,在此记录一下。例如Leetcode-23:合并k个升序链表。
dddyge
2022/09/07
8760
文心一言 VS 讯飞星火 VS chatgpt (101)-- 算法导论9.3 7题
要设计一个 O(n) 时间的算法来找到集合 S 中最接近中位数的 k 个元素,我们可以使用快速选择算法(QuickSelect)。该算法基于快速排序的思想,可以在平均情况下以线性时间复杂度找到第 k 小的元素。
福大大架构师每日一题
2023/09/27
2050
文心一言 VS 讯飞星火 VS chatgpt (101)-- 算法导论9.3 7题
2021-07-30:两个有序数组间相加和的Topk问题。给定两个
2021-07-30:两个有序数组间相加和的Topk问题。给定两个有序数组arr1和arr2,再给定一个整数k,返回来自arr1和arr2的两个数相加和最大的前k个,两个数必须分别来自两个数组。按照降序输出。要求时间复杂度为O(klogk)。
福大大架构师每日一题
2021/07/31
3530
2021-07-30:两个有序数组间相加和的Topk问题。给定两个
golang刷leetcode 技巧(47)无序数组的中位数
要解决这个问题首先要了解什仫是中位数,所谓的中位数就是在一组有序的数字中找到中间的那个数字。如果数字的个数是奇数则直接返回中间的那个数,如果数字的个数是偶数此时这组数据的中位数有两个,取中间两个数的平均值即可。
golangLeetcode
2022/08/02
1.2K0
2021-08-03:完美洗牌问题。给定一个长度为偶数的数组
2021-08-03:完美洗牌问题。给定一个长度为偶数的数组arr,假设长度为N*2,左部分:arrL1……Ln,右部分: arrR1……Rn,请把arr调整成arrL1,R1,L2,R2,L3,R3,…,Ln,Rn。要求:时间复杂度O(N),额外空间复杂度O(1)。
福大大架构师每日一题
2021/08/03
3940
2021-08-03:完美洗牌问题。给定一个长度为偶数的数组
2024-08-14:用go语言,给定两个长度分别为n和m的整数数组nums和changeIndices,下标从1开始。初始时,
2024-08-14:用go语言,给定两个长度分别为n和m的整数数组nums和changeIndices,下标从1开始。初始时,nums 中所有下标均未标记。
福大大架构师每日一题
2024/08/16
1530
2024-08-14:用go语言,给定两个长度分别为n和m的整数数组nums和changeIndices,下标从1开始。初始时,
2021-08-26:长度为N的数组arr,一定可以组成N^2个数字
2021-08-26:长度为N的数组arr,一定可以组成N^2个数字对。例如arr = 3,1,2,数字对有(3,3) (3,1) (3,2) (1,3) (1,1) (1,2) (2,3) (2,1) (2,2),也就是任意两个数都可以,而且自己和自己也算数字对,数字对怎么排序?第一维数据从小到大;第一维数据一样的,第二维数组也从小到大,所以上面的数值对排序的结果为:(1,1)(1,2)(1,3)(2,1)(2,2)(2,3)(3,1)(3,2)(3,3)。给定一个数组arr,和整数k,返回第k小的数值对。
福大大架构师每日一题
2021/08/26
4820
2021-08-26:长度为N的数组arr,一定可以组成N^2个数字
1046. 最后一块石头的重量
刚开始,我的思路是这样的。每次从石头中取出两个最重的(可以排序再取),然后将轻的移出队列,将重的减去轻的质量,然后再从石头中取出两个最重的(可以继续排序后再取)…
Regan Yue
2022/12/05
2480
推荐阅读
2021-03-04:一块金条切成两半,是需要花费和长度数值一样的铜板的
6060
2025-04-09:第 K 近障碍物查询。用go语言,我们有一个无限大的二维平面。给定一个正整数 k 和一个二维数组 quer
770
2021-04-22:给定很多线段,每个线段都有两个数[start, end],
3630
​2021-03-30:给定一个整数组成的无序数组arr,值可能正、可能负、可能0。<=K
5250
滑动窗口最大值(LeetCode 239)
2030
理解 Golang 中的最大/最小堆、`heap` 与优先队列
1580
文心一言 VS 讯飞星火 VS chatgpt (241)-- 算法导论17.3 7题
1440
2024-06-01:用go语言,给定一个从0开始索引的整数数组 nums 、两个正整数 k 和 dist 。 数组的代价是该数
1820
2021-08-24:合并石头的最低成本。有 N 堆石头排成一排
2620
2021-02-26:一个数组arr是二叉树的中序遍历结果,每条边的开销是父节...
5610
LeetCode215.数组中的第K个最大元素
6930
数据结构--堆 Heap
3230
堆的Golang实现
8760
文心一言 VS 讯飞星火 VS chatgpt (101)-- 算法导论9.3 7题
2050
2021-07-30:两个有序数组间相加和的Topk问题。给定两个
3530
golang刷leetcode 技巧(47)无序数组的中位数
1.2K0
2021-08-03:完美洗牌问题。给定一个长度为偶数的数组
3940
2024-08-14:用go语言,给定两个长度分别为n和m的整数数组nums和changeIndices,下标从1开始。初始时,
1530
2021-08-26:长度为N的数组arr,一定可以组成N^2个数字
4820
1046. 最后一块石头的重量
2480
相关推荐
2021-03-04:一块金条切成两半,是需要花费和长度数值一样的铜板的
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档