【分治算法】【Python实现】线性时间选择

news2025/2/23 7:23:27

文章目录

    • @[toc]
      • 问题描述
      • 随机选择算法
        • Python实现
        • 时间复杂性
      • BFPRT算法
        • 时间复杂性
        • Python实现

因上努力

个人主页:丷从心·

系列专栏:分治算法

学习指南:Python学习指南

果上随缘


问题描述

  • 给定线性序集中 n n n个元素和一个整数 k ( 1 ≤ k ≤ n ) k (1 \leq k \leq n) k(1kn),找出这 n n n个元素中第 k k k小的元素

随机选择算法

Python实现
import random


def partition(nums, low, high):
    pivot_index = random.randint(low, high)
    pivot = nums[pivot_index]

    # 将 pivot 元素移动到列表的最右边
    nums[pivot_index], nums[high] = nums[high], nums[pivot_index]

    # 通过交换操作, 将小于 pivot 的元素移动到左边, 大于 pivot 的元素移动到右边
    i = low
    for j in range(low, high):
        if nums[j] < pivot:
            nums[i], nums[j] = nums[j], nums[i]

            i += 1

    # 将 pivot 元素放置到正确的位置
    nums[i], nums[high] = nums[high], nums[i]

    return i


def quick_select(nums, low, high, k):
    if low == high:
        return nums[low]

    # 划分数组, 并获取 pivot 元素的索引
    pivot_index = partition(nums, low, high)

    j = pivot_index - low + 1

    if j == k:
        # 如果 pivot 元素的索引等于 k, 则返回该元素
        return nums[pivot_index]
    elif j > k:
        # 如果 pivot 元素的索引大于 k, 则在左侧继续查找
        return quick_select(nums, low, pivot_index - 1, k)
    else:
        # 如果 pivot 元素的索引小于 k, 则在右侧继续查找
        return quick_select(nums, pivot_index + 1, high, k - j)


def find_kth_smallest(nums, k):
    if k < 1 or k > len(nums):
        raise ValueError('Invalid value of k')

    return quick_select(nums, 0, len(nums) - 1, k)


nums = [3, 1, 5, 2, 4]
k = 2

res = find_kth_smallest(nums, k)

print(f'第 {k} 小的元素为 {res}')
2 小的元素为 2
时间复杂性
  • 随机选择算法在最坏情况下需要 Ω ( n 2 ) \Omega(n^{2}) Ω(n2)时间,平均情况下需要 O ( n ) O(n) O(n)时间

BFPRT算法

  • 如果能在线性时间内找到一个划分基准,使得按这个基准划分出的两个子数组的长度都至少为原数组长度的 ε \varepsilon ε倍( 0 < ε < 1 0 < \varepsilon < 1 0<ε<1是某个常数),那么在最坏情况下用 O ( n ) O(n) O(n)时间就可以完成选择任务

    • 例如,若 ε = 9 / 10 \varepsilon = 9 / 10 ε=9/10,算法递归调用所产生的子数组的长度至少缩短 1 / 10 1 / 10 1/10,所以在最坏情况下,算法所需的计算时间 T ( n ) T(n) T(n)满足递归式 T ( n ) ≤ T ( 9 n / 10 ) + O ( n ) T(n) \leq T(9n / 10) + O(n) T(n)T(9n/10)+O(n),由此可得 T ( n ) = O ( n ) T(n) = O(n) T(n)=O(n)
  • n n n个输入元素划分成 ⌈ n / 5 ⌉ \left\lceil n / 5 \right\rceil n/5个组,每组 5 5 5个元素(除可能有一个组不是 5 5 5个元素外),用任意一种排序算法,将每组中的元素排好序,并取出每组的中位数,共 ⌈ n / 5 ⌉ \left\lceil n / 5 \right\rceil n/5

  • 递归调用找出这 ⌈ n / 5 ⌉ \left\lceil n / 5 \right\rceil n/5个元素的中位数,如果 ⌈ n / 5 ⌉ \left\lceil n / 5 \right\rceil n/5是偶数,就找它的两个中位数中较大的一个,然后以这个元素作为划分基准

  • 设所有元素互不相同,找出的基准 x x x至少比 3 ⌊ ( n − 5 ) / 10 ⌋ 3 \left\lfloor (n - 5) / 10 \right\rfloor 3(n5)/10个元素大,至少比 3 ⌊ ( n − 5 ) / 10 ⌋ 3 \left\lfloor (n - 5) / 10 \right\rfloor 3(n5)/10个元素小,当 n ≥ 75 n \geq 75 n75时, 3 ⌊ ( n − 5 ) / 10 ⌋ ≥ n / 4 3 \left\lfloor (n - 5) / 10 \right\rfloor \geq n / 4 3(n5)/10n/4,所以按此基准划分所得的两个子数组的长度都至少缩短 1 / 4 1 / 4 1/4

时间复杂性
  • 设对 n n n个元素的数组调用算法需要 T ( n ) T(n) T(n)时间
  • 找中位数 x x x最多用 T ( n / 5 ) T(n / 5) T(n/5)时间
  • 按照算法所选的基准 x x x进行划分所得的两个子数组分别最多有 3 n / 4 3n / 4 3n/4个元素,无论对哪一个子数组调用算法都最多用 T ( 3 n / 4 ) T(3n / 4) T(3n/4)时间

T ( n ) ≤ { C 1 , n < 75 C 2 n + T ( n / 5 ) + T ( 3 n / 4 ) , n ≥ 75 T(n) \leq \begin{cases} C_{1} , & n < 75 \\ C_{2} n + T(n / 5) + T(3n / 4) , & n \geq 75 \end{cases} T(n){C1,C2n+T(n/5)+T(3n/4),n<75n75

T ( n ) = O ( n ) T(n) = O(n) T(n)=O(n)

Python实现
import statistics


def find_median_of_medians(arr):
    # 将数组划分为大小为 5 的子数组
    subarrays = [arr[i:i + 5] for i in range(0, len(arr), 5)]

    # 计算每个子数组的中位数
    medians = [statistics.median(subarray) for subarray in subarrays]

    # 如果元素数量小于等于 5, 直接返回中位数
    if len(medians) <= 5:
        return statistics.median(medians)

    # 递归调用中位数的中位数算法
    return find_median_of_medians(medians)


def linear_time_select(arr, k):
    # 找到中位数的中位数
    median_of_medians = find_median_of_medians(arr)

    # 将数组划分为三个部分
    less = [x for x in arr if x < median_of_medians]
    equal = [x for x in arr if x == median_of_medians]
    greater = [x for x in arr if x > median_of_medians]

    # 根据划分后的数组长度选择下一步操作
    if k <= len(less):
        # 在较小的部分递归查找第 k 小元素
        return linear_time_select(less, k)
    elif k <= len(less) + len(equal):
        # 第 k 小元素等于中位数的中位数
        return median_of_medians
    else:
        # 在较大的部分递归查找第 k 小元素
        return linear_time_select(greater, k - len(less) - len(equal))


arr = [3, 1, 5, 2, 4, 9, 7, 8, 6]
k = 5

res = linear_time_select(arr, k)

print(f'第 {k} 小的元素为 {res}')
5 小的元素为 5

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1654735.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为数据之道第一部分导读

目录 导读 第一部分 序 第1章 数据驱动的企业数字化转型 非数字原生企业的数字化转型挑战 业态特征&#xff1a;产业链条长、多业态并存 运营环境&#xff1a;数据交互和共享风险高 IT建设过程&#xff1a;数据复杂、历史包袱重 数据质量&#xff1a;数据可信和一致化…

ICME2024 | 基于半监督对比学习的表现力语音合成

人类的语音极富表现力&#xff0c;不仅包括语调和重读&#xff0c;还包括风格和情感等多种元素。表现力语音合成的目标是要精准捕捉并再现这些元素。先前表现力语音合成方面的研究通常将表现力视为单一维度&#xff0c;如风格或情感。但实际上&#xff0c;风格可以随着文本和场…

【SDN:逻辑上集中的控制平面,路由选择算法,LS路由工作过程,距离矢量路由选择(distance vector routing)】

文章目录 SDN&#xff1a;逻辑上集中的控制平面SDN的主要思路SDN控制平面和数据平面分离的优势SDN 架构: 数据平面交换机 路由选择算法路由(route)的概念最优化原则(optimality principle)路由的原则路由算法的分类LS路由工作过程&#xff08;相当于一个上帝&#xff09;链路状…

YoloV8改进策略:BackBone改进DCNv4

摘要 涨点效果:在我自己的数据集上,mAP50 由0.986涨到了0.993,mAP50-95由0.737涨到0.77,涨点明显! DCNv4是可变形卷积的第四版,速度和v3相比有了大幅度的提升,但是环境搭建有一定的难度,对新手不太友好。如果在使用过程遇到编译的问题,请严格按照我写的环境配置。 Y…

CSDN上是不是有机器人点赞和收藏?

我在CSDN上写作&#xff0c;主要是本来是记录学习工作中的一些知识点&#xff0c;看得人不多本来就能预想到的。 但是今天发现五一写的一篇博客&#xff0c;出现了很奇怪的阅读、点赞、收藏数。只有2个人阅读&#xff0c;但是有8个点赞&#xff0c;还有5个收藏。 我不禁怀疑CS…

二叉树的前序、中序、后序遍历的C++实现

二叉树的前序、中序、后序 遍历属于深度优先搜索方式&#xff0c;本文使用递归法实现前序、中序、后序的遍历方法&#xff0c;代码如下&#xff1a; #include <iostream> #include <vector>struct TreeNode{int val;TreeNode* left;TreeNode* right;TreeNode(int …

【JAVA进阶篇教学】第十篇:Java中线程安全、锁讲解

博主打算从0-1讲解下java进阶篇教学&#xff0c;今天教学第十篇&#xff1a;Java中线程安全、锁讲解。 当涉及到多线程编程时&#xff0c;保证线程安全是至关重要的。线程安全意味着在多个线程访问共享资源时&#xff0c;不会发生数据错乱或不一致的情况。为了实现线程安全&am…

【Linux】常用基本指令

目录 食用说明 用户管理 whoami/who clear tree 目录结构和路径 pwd ls 文件 隐藏文件 常用选项 cd 家目录、根目录、绝对路径和相对路径 touch 常用选项 mkdir rmdir/rm man cp mv cat nano echo 输出重定向 > 输入重定向 < more/less head/…

comfyui安装deforum启动不了,多半是ffmpeg的问题

如果报错中出现imageio 和 ffmpeg 的字样&#xff0c;去装requirement也没啥用 这里最好到cmd中&#xff0c;进入comfyui的python环境&#xff0c;运行以下两句&#xff1a; import imageio imageio.plugins.ffmpeg.download() 图例&#xff1a; 如果节点不报错了&#xff0…

嵌入式引脚工作模式

一.引脚工作模式的基本概念 引脚的工作模式通常包括输入模式、输出模式和双向模式&#xff1a; 输入模式&#xff1a;引脚设置为输入模式时&#xff0c;可以接收外部信号或触发器的信号。这种模式通常用于读取传感器数据、接收外部设备的信号等。 输出模式&#xff1a;引脚设…

Lora基础炼丹学习笔记

1、收集数据集 20-30张人物各个角度、各个姿势的图片 2、图片预处理 裁剪 打标签 裁剪必须也要512 * 512 &#xff0c;因为sd1.5就是用这个尺寸训练的&#xff0c;可以使用后期处理 打标可以勾选这个&#xff0c;Deepbooru对二次元画风更友好 打标也可以使用wb14-tagger的…

openssl 生成证书步骤

本地测试RSA非对称加密功能时&#xff0c;需要用到签名证书。本文记录作者使用openssl本地生成证书的步骤&#xff0c;并没有深入研究openssl&#xff0c;难免会有错误&#xff0c;欢迎指出&#xff01;&#xff01;&#xff01; 生成证书标准流程&#xff1a; 1、生成私钥&am…

关于ssrf

首先&#xff0c;先介绍一下ssrf。ssrf即服务器端请求伪造&#xff0c;是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下&#xff0c;SSRF攻击的目标是从外网无法访问的内部系统。而且因为请求是由服务端发起的&#xff0c;所以服务端能请求到与自身相连而与…

计算机网络——应用层协议(2:http协议)

在这篇文章中自定义应用层协议&#xff0c;我曾介绍了应用层协议中需要我们开发人员自行制定应用层协议&#xff0c;而应用层协议又离不开结构化字段以及序列化和反序列化还有报头的封装。而在今天&#xff0c;我们有一种应用层协议是我们几乎人人都接触过的协议&#xff0c;它…

暗区突围国际服pc端海外版新手前期如何赚钱 暗区突围新手教学

暗区突围国际服pc端海外版新手前期如何赚钱 暗区突围新手教学 暗区突围是一款极为惊险的射击游戏&#xff0c;让玩家充分感受紧张激烈的战斗以及获取财富的过程。但是有许多新手玩家是不会在游戏里赚钱的&#xff0c;也会在赚钱过程中遇到很多问题&#xff0c;我将在这篇文章…

PGP加密技术:保护信息安全的利器

随着数字化时代的到来&#xff0c;个人和企业对信息安全的需求日益增长。PGP&#xff08;Pretty Good Privacy&#xff09;加密技术作为一项强大的加密工具&#xff0c;为保护敏感数据提供了一种有效的方法。本文将探讨PGP加密技术的基本原理、应用场景以及其在现代信息安全中的…

IDEA - java.lang.OutOfMemoryError: Java heap space / insufficient memory

IDEA 第一次运行项目时&#xff0c;会报如题错误&#xff0c;解决办法是&#xff1a; 将图示部分由默认的 700 改为 2048。

PPT弹簧画法

1. 插入两个圆 2. 使用Lvyhtools的形状-位置分布-圆形阵列 注意&#xff1a;阵列中心要点击文字后才能选择 3. 删除中心的圆&#xff0c;使用Onekey10的原位复制&#xff0c;可以多次&#xff1b; 4. 右击图像选择设置形状格式-线条&#xff08;无线条&#xff09; 5. 找到第二…

云HIS源码,基于云计算的医院临床信息系统(有应用案列)

云HIS全套商业源码&#xff0c;基于云计算的医院临床信息系统 提供预约挂号、门急诊收费、门诊医生站、护士工作站、药房药库管理、电子病历、住院医生站、住院护士工作站、住院登记结算、出院管理、病案管理、医药价格管理、财务管理、统计查询、会员管理等业务及管理功能。 …

PCIe下一代线缆标准CopprLink发布

作为业界广泛采用的高速串行点对点互联标准&#xff0c;PCIe自诞生以来历经多次迭代升级&#xff0c;现已成为CPU、GPU、FPGA、SSD等计算设备间不可或缺的互连桥梁。PCIe 7.0标准更是将数据传输速率提升至令人惊叹的32 GB/s&#xff08;每通道&#xff09;。 然而&#xff0c;面…