【分治策略】查询中位数最接近点对

news2024/11/28 13:29:01

查询中位数

给定线性序集中n个元素和一个整数k 【k=(n+1)/2】,要求找出这n个元素中第k小的元素,即找中位数。线性序列没有排序,没有重复值。

已知快速排序划分时一个划分基准数的位置在确定后,在之后排序中是不会变的。利用此特性,以下算法模仿快速排序,但只对划分出的子数组之一进行处理,时间复杂度为O(n),比排序完查找更快。

如果n=0或1,不需要找(唯一一个数据就是要找的)

如果当前基准数不是所求的,在相应的子串中找(相当于快排中划分好了的三段)


查询中位数将k设为n/2。以下可以查询第k小的任何一个数。

由于使用分治策略,这里的k是在子串中相对的第k小(k是相对left和right的位置),但是划分函数返回的下标mid是绝对位置,所以,可以用一个变量(j)存储mid在子串中的相对位置。

SelectK每一次递归时left和right也会发生变化,相应的k也要注意改变(k-j)。

int SelectK(int* nums, int left, int right, int k)
{
    if (left == right&&k==1)//剩下一个元素找里面第一小的元素
        return nums[left];
    int mid = Partition(nums, left, right);
    int j = mid + 1 - left;//j是相对在子串中的位置(第j个)
    if (k <= j)return SelectK(nums, left, mid, k);
    else return SelectK(nums, mid + 1, right, k-j);
}
int SelectKMin(int* nums, int n, int k)
{
    if (nullptr == nums || n < 1 || k<1 || k>n)
        return -1;
    return SelectK(nums, 0, n - 1, k);
}

划分函数

同快排的划分

int Partition(int*nums,int left,int right)
{
    int tmp = nums[left];
    while (left < right)
    {
        while (left<right && nums[right]>tmp)right--;
        if(left<right)nums[left] = nums[right];
        while (left < right && nums[left] < tmp)left++;
        if (left < right)nums[right] = nums[left];
    }
    nums[left] = tmp;
    return left;
}

测试

int main()
{
    int a[] = { 5,3,6,7,9,8,4,2,1,0 };
    int n = sizeof(a) / sizeof(a[0]);
    int k = 0;
    for (k = 1; k <= n; k++)
    {
        int kmin = SelectKMin(a, n, k);
        printf("k:%d   kmin:%d\n", k, kmin);
    }
}

一维最接近点对

给定一维线上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对的距离最小。如果有多于一对只找1对作为解。

如果暴力求解每一对之间的距离需要O(n^2)太慢了。将每个点的位置存在数组中,利用分治法:

将数组划分后产生两个子集合,差值最小有三个部位可能产生:

当集合中元素个数<2时,无法计算差值,此时应返回INT_MAX

设左边集合为S1,最小差为d1;右边集合为S2,最小差d2;S2中最小值q和S1最大值p相减得的差,三个数相比最小的值即为最接近点对的差值。

为了将数组平分减少计算次数,需要找中位数并用其作为划分基准。

主要代码:

int CpairNum(int* nums, int left, int right)
{
    if ((right - left) < 1)return INT_MAX;//少于两个数没有差值
    int m = (right - left + 1) / 2;//当前数组中位数的位置(left~right)
    int pos = left + m - 1;//绝对位置(0~n-1)
    SelectK(nums, left, right, m);//找中位数的值,然后划分成左右两个数组
    int d1 = CpairNum(nums, left,pos);//S1继续递归
    int d2 = CpairNum(nums,pos+1 ,right );//S2继续递归
    int p = MaxS1(nums, left ,pos);//S1中最大的元素
    int q = MinS2(nums,pos+1, right);//S2中最小的元素
    return Min3(d1, d2, q - p);//对比找到最小元素
}
int Cpair(int* nums, int n)
{
    if (n < 2 || nums == nullptr)return INT_MAX;
    return CpairNum(nums, 0, n - 1);
}

其余代码:

//划分函数
int Partition(int* nums, int left, int right)
{
    int tmp = nums[left];
    while (left < right)
    {
        while (left<right && nums[right]>tmp)right--;
        if (left < right)nums[left] = nums[right];
        while (left < right && nums[left] < tmp)left++;
        if (left < right)nums[right] = nums[left];
    }
    nums[left] = tmp;
    return left;
}
//找第k小元素下标
int SelectK(int* nums, int left, int right, int k)
{
    if (left == right && k == 1)
        return nums[left];
    int mid = Partition(nums, left, right);
    int j = mid - left + 1;
    if (k == j)return nums[mid];
    if (k <j)return SelectK(nums, left, mid, k);
    else return SelectK(nums, mid + 1, right, k - j);
}
//S1里面最大的
int MaxS1(int*nums,int left ,int right)
{
    return nums[left];
}
//S2里面最大的
int  MinS2(int *nums,int left,int right)
{
    int min = INT_MAX;
    for (int i = left; i <= right; i++)
    {
        if (nums[i] < min)
        {
            min = nums[i];
        }
    }
    return min;
}
//三个最小差里面最小的
int Min(int a, int b)
{
    return a < b ? a : b;
}
int Min3(int a, int b, int c)
{
    return Min(a, Min(b, c));
}

排好序再计算的方法无法直接推广到二维的情形,而分治法求解可以。

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

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

相关文章

dataphin如何使用zip文件,离线安装python第三方包?

好久没写文章啦&#xff0c;快过年了啦&#xff0c;打工人要回家啦 背景介绍&#xff1a; 每次在dataphin里使用pandas的时候&#xff0c;都要pip install pandas。dataphin需要下载pandas安装包&#xff0c;比较费时。总而言之&#xff0c;这种方式慢。 所以我要在dataphin的…

【手写 Vue2.x 源码】第十四篇 - 生成 ast 语法树 - 模板解析

一&#xff0c;前言 上篇&#xff0c;主要介绍了生成 ast 语法树-正则说明部分&#xff0c;涉及以下几个点&#xff1a; 简要说明了 HTML模板的解析方式对模板解析相关正则说明和测试 本篇&#xff0c;生成 ast 语法树-代码实现 二&#xff0c;模板解析 模板解析的方式&…

22. 听说你想要用爬虫采集我的手机号?哎 ~ 我展示用的是图片

本篇博客我们实现图片渲染手机号码案例&#xff0c;用于防止爬虫直接采集文字信息。 爬虫训练场 本案例实现的效果如下所示 文章目录bootstrap5 实现名片样式卡片补充数据生成逻辑生成用户 5 个汉字的昵称调用头像 API&#xff0c;生成图片将手机号码生成图片bootstrap5 实现名…

菜鸡二次封装element中table表单

实现效果如下封装的table表单<template><el-table:span-method"arraySpanMethod":header-cell-style"rowClass":cell-style"cellStyle":data"tableData"style"width: 100%; height: 100%">//暂无数据展示<te…

汤姆斯的天堂梦(C++,Dijkstra)

题目描述 汤姆斯生活在一个等级为 000 的星球上。那里的环境极其恶劣&#xff0c;每天 121212 小时的工作和成堆的垃圾让人忍无可忍。他向往着等级为 NNN 的星球上天堂般的生活。 有一些航班将人从低等级的星球送上高一级的星球&#xff0c;有时需要向驾驶员支付一定金额的费…

【跟月影学可视化】学习笔记 41 篇(完结)

说明 【跟月影学可视化】专栏学习笔记。 个人学习笔记源码&#xff1a;https://github.com/kaimo313/visual-learning-demo 一共做了 162 个学习示例以及 41 篇博客学习笔记&#xff0c;要深入学习该课程请支持正版&#xff0c;个人笔记仅供参考。 笔记目录 【图形基础篇…

什么是无源相干定位系统?

无源定位&#xff08;Passive Localization&#xff09;不通过发射信号来探测目标的位置&#xff0c;而是接收目标的有意、无意辐射或反射信号来实现对侦察目标的探测、定位与追踪。接收的信号可以是目标直接辐射的信号&#xff0c;也可以是外辐射源照射到目标后反射或散射的信…

网站关键词怎么优化排名(网站关键词通常可以选择哪些词)

网站核心关键词的选取需要具备哪些条件 在对网站优化的过程中&#xff0c;肯定少不了对网站关键词的选取&#xff0c;关键词的选择又是网站优化中十分重要的一步&#xff0c;那么网站在选择关键词的过程中需要遵循哪些原则呢&#xff1f;关于这个问题老张带你了解一下。 1、首…

wav文件格式分析与详解

wav文件格式分析与详解WAV文件是在PC机平台上很常见的、最经典的多媒体音频文件,最早于1991年8月出现在Windows 3.1操作系统上,文件扩展名为WAV,是WaveFom的简写,也称为波形文件,可直接存储声音波形,还原的波形曲线十分逼真。WAV文件格式简称WAV格式是一种存储声音波形的数字音…

Wijmo 2022 v2 JavaScript UI Crack

Wijmo 2022 v2 采集 by Ω578867473 添加对 Angular 14 和 React 18 的支持以及对 FlexGrid 和 FlexChart 的改进。特征 Angular 14 支持——您今天就可以开始将 Angular 14 应用程序与 Wijmo 结合使用。Wijmo 提供了大量快速、灵活的 Angular 组件&#xff0c;每个组件都有丰富…

【学Vue就跟玩一样】组件-非单文件组件的使用

一&#xff0c;什么是组件实现应用中局部功能代和资源的集合&#xff08;简单来说就是将html&#xff0c;js&#xff0c;css&#xff0c;资源整合起来的一个小盒子&#xff09;理解&#xff1a;用来实现局部(特定)功能效果的代码集合为什么&#xff1a;一个界面的功能很复杂作用…

SD卡损坏了怎么办?sd卡恢复,80%的用户都试过这些方法

SD卡作为一种外部存储设备&#xff0c;多用在数据相机、监控、手机、无人机等设备中&#xff0c;可以帮我们保存很多数据。 但是SD卡也跟其他设备一样&#xff0c;容易发生数据丢失的情况。如果SD卡损坏了&#xff0c;或者我们把里面的数据误删或者格式化&#xff0c;sd卡恢复…

MySQL--什么情况下不建议使用join查询

关于join 当需要查询两个表的交集、并集等数据时&#xff0c;除了嵌套子查询的方式外&#xff0c;还可以使用join的方式提升性能。对于MySQL的join语句&#xff0c;需要两个最基础的“角色”&#xff1a;主表即驱动表&#xff0c;关联表即驱动表。join描述的就是驱动表与被驱动…

云服务器怎样搭建静态网站?

先买好域名和云服务器&#xff0c;然后把云服务器的ip地址和域名解析到一起。 然后登陆云服务器&#xff0c;安装Nginx 我的软件环境是 CentOS 1、安装 Nginx 在 CentOS 上&#xff0c;可直接使用 yum 来安装 Nginx&#xff08;安装时间稍微有点长&#xff0c;安装过程中代码会…

Linux应用编程---10.信号量

Linux应用编程—10.信号量 ​ 信号量用于任务间的同步!简单来理解&#xff0c;信号量是一个被内核维护的整数&#xff0c;这个整数一般是“大于等于零”的&#xff0c;我们对这个信号量的操作一般为&#xff1a;将信号量设置一个值、发布(加上一个信号量)、消耗(减去一个信号量…

LINUX提权之计划任务提权篇

前言 今天给大家带来的是计划任务提权&#xff0c;说起定时任务对于linux很熟悉的小伙伴一定不会陌生&#xff0c;但你有没有想过可以通过定时任务来进行权限提升的操作&#xff0c;本文会根据该知识点进行展开&#xff0c;同时给大家介绍一个用于探测漏洞的工具使用方法&…

线程通信:生产者消费者问题

问题 1.生产者&#xff08;Producer&#xff09;将产品给店员&#xff08;Clerk&#xff09;&#xff0c;而消费者&#xff08;Customer&#xff09;从店员处取走产品&#xff0c;店员一次只能持有固定数量的产品&#xff08;比如&#xff1a;20&#xff09; &#xff0c;如果生…

实验 1 MATLAB 图像处理基础

一、实验目的1. 熟悉启动和退出 MATLAB 的方法。2. 熟悉 MATLAB 命令窗口的组成。3. 掌握 MATLAB 基本绘图函数和图像处理函数的使用。4. 掌握图像内插和灰度图像的集合运算。二、实验例题1. 求下列表达式的值(1) (2) 答&#xff1a;(1)y1exp(2)/2*sin(35*pi/180)y1 2.1191(2)方…

索尼数字人研究:画质超逼真,面部表情与身体动作保持协调

近年来&#xff0c;3D动捕、数字虚拟人等技术受到越来越多关注&#xff0c;它不仅可以应用于电影场景&#xff0c;游戏、社交等领域也开始采用。相比于过去高成本、高门槛的全身动捕技术&#xff0c;现在制作基于动捕的虚拟人越来越容易&#xff0c;不需要过高的成本或是专业技…

Linux 可加载内核模块剖析

Linux 就是通常所说的单内核&#xff08;monolithic kernel&#xff09;&#xff0c;即操作系统的大部分功能都被称为内核&#xff0c;并在特权模式下运行。 它与微型内核不同&#xff0c;后者只把基本的功能&#xff08;进程间通信 [IPC]、调度、基本的输入/输出 [I/O] 和内存…