NC88 寻找第K大

描述
有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。

给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在。
要求:时间复杂度 O(nlogn)O(nlogn),空间复杂度 O(1)O(1)
数据范围:0 <=n <= 1000, 0<K<n, 数组中每个元素满足 0<=val<=10000000。

示例1:
输入:[1,3,5,2,2],5,3
返回值:2
示例2
输入:[10,10,9,9,8,7,5,6,4,3,4,2],12,3
返回值:9
说明:去重后的第3大是8,但本题要求包含重复的元素,不用去重,所以输出9。

思想:
利用快排将数组先排序,排序之后,将第K大的取出即可。
快排的思想:
先从数列中取出一个数作为基准数(通常取第一个数)。
分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
再对左右区间重复第二步,直到各区间只有一个数。
快排的时间复杂度:O(nlogn)
需要注意的地方:
1)快排实质上是一个分治的思想,所以需要用到递归,递归的出口是left和right一致时,不需要再次排序,直接返回数组即可。
2)快排为了找到当前基准数的正确位置,需要用到两个游标 i 和 j,分别从两边开始找比基准值大和小的值,这里需要注意,如果选择的基准是最左测,这时需要先动j,即选从最右边选择到比基准值小的,因为选动的那个确定了截止范围,因为后面需要找到 i 和 j 相遇位置和基准数换,这个位置所在的数一定是要比基准数小的,因为基准数在最左测;同样的,要是选择最右侧的值作为基准值就要选择左边的i先动。
主要代码如下:

#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param a int整型一维数组 
# @param n int整型 
# @param K int整型 
# @return int整型
#
class Solution:
    def findKth(self , a: List[int], n: int, K: int) -> int:
        self.kp(a, 0, n-1)  # 将数组a进行快排
        return a[n-K]       # 返回第K大的数
    
    
    def kp(self, a: List[int], left : int, right: int):
        # 将数据快排后返回
        if left >= right:  # 递归出口
            return 
        else:
            p = a[left]   # 取最左测为基准值
            i = left      # 设置两个游标
            j = right
            while(i != j):   # 直到相遇
                while(a[j] >= p and i < j):  # i < j 保证不会过头 要是过头的话后面都是比基准值大的数 循环不会停止了
                    j= j - 1;
                while(a[i] <= p and i < j):
                    i= i + 1;
                temp = a[i]                 # 在相遇之前,遇到右侧小的和左侧大的进行数值的交换
                a[i] = a[j]
                a[j] = temp
            a[left] = a[i]                  # 两个游标相遇,相遇的位置就是基准值应该在的位置,进行交换
            a[i] = p
            self.kp(a, left, i-1)           # 从基准值处分成两段,递归进行排序
            self.kp(a, i+1, right)

扩展: 当K很小的时候,可使用冒泡排序,因为冒泡排序的思想每一次就是确定好一个位置。这时相对的时间复杂度会小,为O(n * k)。
冒泡排序的思想: 冒泡排序属于一种典型的交换排序。
  交换排序顾名思义就是通过元素的两两比较,判断是否符合要求,如过不符合就交换位置来达到排序的目的。冒泡排序名字的由来就是因为在交换过程中,类似水冒泡,小(大)的元素经过不断的交换由水底慢慢的浮到水的顶端。
  冒泡排序的思想就是利用的比较交换,利用循环将第 i 小或者大的元素归位,归位操作利用的是对 n 个元素中相邻的两个进行比较,如果顺序正确就不交换,如果顺序错误就进行位置的交换。通过重复的循环访问数组,直到没有可以交换的元素,那么整个排序就已经完成。

所以,只需要进行K此冒泡,就把最大的交换到它应该在的位置。

class Solution:
    def findKth(self , a: List[int], n: int, K: int) -> int:
        for i in range(K):     # 注意这两个循环设置的范围
            for j in range(n-1):    
                if a[j] > a[j+1]:
                    temp = a[j+1]
                    a[j+1] = a[j]
                    a[j] = temp
        return a[n - K]

补充一个进阶的思路过程,如果感兴趣可以都实现一下:
https://mp.weixin.qq.com/s/FFsvWXiaZK96PtUg-mmtEw
链接

<think>嗯,用户询问的是如何在其他系统或环境中移植和使用Linux的nc命令。这个问题涉及到网络工具移植的底层技术,需要仔细思考。 用户可能正在尝试将网络工具迁移到嵌入式系统或非Linux平台,比如将nc移植到路由器固件或Windows环境。从ta提问的方式看,应该具备一定的Linux基础,但对交叉编译和网络编程可能不太熟悉。 关于nc命令的移植,核心难点在于它的跨平台实现。Linux版本通常依赖GNU库,而其他环境可能需要调整套接字API调用。考虑到用户提供的引用材料中提到了交叉编译(引用[2])和网络命令使用(引用[1]),重点应该放在这两个方面。 首先需要解释nc的本质:它其实是个使用BSD套接字API的网络工具。移植时最直接的方法是寻找现有跨平台实现,比如OpenBSD的版本或BusyBox集成版。不过用户如果坚持要移植原版,就得解决三个关键点:1)环境检测(通过autoconf或手动修改config.h)2)依赖库替换(如用Winsock代替Linux套接字)3)编译工具链切换。 特别要注意引用[2]提到的交叉编译参数--host的设置,这在嵌入式移植时至关重要。比如给ARM板编译时就需要指定arm-linux-gnueabihf工具链。另外Windows移植还需要处理行尾符转换问题,这点容易被忽略。 用户可能没意识到的是,很多场景其实不需要重新移植。比如在Windows上完全可以用WSL原生运行Linux版nc,或者直接使用兼容工具包。不过如果用户的目标平台是OpenWrt这类嵌入式系统,建议优先考虑BusyBox的nc实现,体积能缩小到原版的1/5。 最后生成的问题要覆盖用户可能的后续需求:性能优化、安全加固这些高级话题应该包含在内,毕竟移植只是第一步,实际部署时这些才是重点。</think>以下是在其他系统或环境中移植和使用Linux的`nc`(netcat)命令的详细指南: --- ### **一、移植核心思路** 1. **源码获取** - 下载官方源码(如OpenBSD版):`https://cdn.openbsd.org/pub/OpenBSD/OpenBSD-stable.tar.gz` - 或GNU版:`git clone https://github.com/openbsd/src.git` 2. **跨平台编译关键点** - **环境检测**:修改`configure`脚本或`config.h`文件,适配目标平台的系统调用(如Windows的Winsock API)[^2]。 - **依赖库替换**: - Linux套接字 → Windows:`WSAStartup()`初始化,`closesocket()`替代`close()`。 - 信号处理 → Windows:用`SetConsoleCtrlHandler()`替代`signal()`。 - **编译工具链**: - 嵌入式系统(如ARM):指定交叉编译工具链(`--host=arm-linux-gnueabihf`)[^2]。 - Windows:使用MinGW或Cygwin编译。 3. **代码修改示例(Windows适配)** ```c #ifdef _WIN32 #include <winsock2.h> #pragma comment(lib, "ws2_32.lib") #else #include <sys/socket.h> #endif int main() { #ifdef _WIN32 WSADATA wsa; WSAStartup(MAKEWORD(2,2), &wsa); // 初始化Winsock #endif // ... 套接字操作代码 ... #ifdef _WIN32 WSACleanup(); // 清理Winsock资源 #endif } ``` --- ### **二、替代方案(无需移植)** | **平台** | **替代工具** | **安装方法** | |----------------|--------------------------|--------------------------------| | **Windows** | `ncat` (Nmap自带) | 下载Nmap:`https://nmap.org` | | **macOS** | 自带`nc`命令 | 终端直接使用 | | **嵌入式系统** | BusyBox集成版`nc` | 编译BusyBox时启用`CONFIG_NC`选项 | | **跨平台** | `socat` (更强) | `apt install socat` 或源码编译 | --- ### **三、使用示例** 1. **基础通信**(同Linux语法) - 服务端:`nc -l -p 1234` - 客户端:`nc 192.168.1.100 1234` *注:Windows版可能需加`-n`参数禁用DNS解析* 2. **文件传输** - 接收端:`nc -l -p 1234 > output.iso` - 发送端:`nc 192.168.1.100 1234 < input.iso` 3. **端口扫描** ```bash nc -zv 192.168.1.100 20-30 # 扫描20~30端口 ``` --- ### **四、常见移植问题** 1. **编译错误** - **未定义符号**:检查目标平台的套接字API差异(如`inet_aton()`在Windows中为`inet_addr()`)。 - **链接失败**:Windows需链接`ws2_32.lib`,Linux需`-lpthread`。 2. **运行时问题** - **权限不足**:非Windows系统需`sudo`执行监听低端口(<1024)。 - **防火墙拦截**:确保目标系统防火墙开放对应端口。 --- ### **五、安全建议** - **避免明文传输敏感数据**:结合加密工具(如`openssl`): ```bash # 加密传输 nc -l -p 1234 | openssl aes-256-cbc -d -k "密码" ``` - **最小权限原则**:在嵌入式系统中使用`dropbear`等轻量级SSH替代方案。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值