离散化

引自百度百科
离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。
通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。例如:
原数据:1,999,100000,15;处理后:1,3,4,2;
原数据:{100,200},{20,50000},{1,400};
处理后:{3,4},{2,6},{1,5};

离散化是程序设计中一个常用的技巧,它可以有效的降低时间复杂度。其基本思想就是在众多可能的情况中,只考虑需要用的值。离散化可以改进一个低效的算法,甚至实现根本不可能实现的算法。要掌握这个思想,必须从大量的题目中理解此方法的特点。例如,在建造线段树空间不够的情况下,可以考虑离散化。

数据的离散化

有些数据本身很大, 自身无法作为数组的下标保存对应的属性。如果这时只是需要这堆数据的相对属性, 那么可以对其进行离散化处理。当数据只与它们之间的相对大小有关,而与具体是多少无关时,可以进行离散化。
例 1:
91054 与 52143的逆序对个数相同。
例 2:
设有4个数: 1234567、123456789、12345678、123456
排序:123456<1234567<12345678<123456789
=>1<2<3<4
那么这4个数可以表示成:2、4、3、1
例 3:
比如给你n个数:98998988,32434234,433234556,32434234,8384733,……
让你统计其中每个数出现的次数,传统的做法有好几种,比如一遍一遍的扫过去,比对叠加,这样算法的效率是O(n2),效率低下;
再比如先排序,再统计连续的相同的个数,这里的效率已经有所提高了,不过假如上面的数据是一道线段树的题目给出的数据,那么建树需要的空间开销实在是太大了。
再改进一下,采用哈希的方法,开一个大于其中最大数的数组并初始化为零,O(n)扫一下,在该数字对应的下标的元素上+1,如果对于比较小的数字还好说,但是对于上面出现的数字直接采用哈希对空间的开销是十分大的也是没有必要的,所以这里用到了数据的离散化。
首先将数字排序:32434234,32434234,43324556,8384733,98998988
去重后给予其对应的索引: 0,0,1,2,3 (一一映射)
分别对应每个数,就可以简化很多操作,减少了很多不必要的资源开销。
除了对于较大整数需要使用离散化之外,对于一些需要使用整型数据结构,但给出的数据却是小数的也可以使用离散化,将其索引为整数就可以了。

那么可以总结出离散化的步骤:

1、排序

2、去重

3、索引
为了简化代码,我们采用STL算法离散化:

/*
用离散化之前先用 sort()排序,再用 unique() 进行去重
用 lower_bound() 或者 upper_bound() 进行二分查找位置
*/
int a[n], b[n], sub[n];
// a[n]是即将被离散化的数组,b[n]是a[n]的副本,sub用于排序去重后提供离散化后的值
sort(sub, sub + n);
int size = unique(sub, sub + n) - sub;
for(int i = 0; i < n; i++)a[i] = lower_bound(sub, sub + size, a[i]) - sub;//即a[i]为b[i]离散化后对应的值

1、unique()函数————返回值是去重之后的长度

unique() 的作用是“去掉”容器中相邻元素的重复元素(不一定要求数组有序),即去重
它会把重复的元素添加到容器末尾(所以数组大小并没有改变),而返回值是去重之后的尾地址
如果要删去重复元素,可以把尾巴删去即可(或者直接定义新的长度!)
例如:

sz=unique(b+1,b+n+1)-(b+1);//减去的(b+1) 及 a  是起始地址
sz=unique(a,a+n)-a;

2、二分查找——lower_bound()、upper_bonud()

/*
upper_bound(i) 返回的是键值为i的元素可以插入的最后一个位置(上界)
lowe_bound(i) 返回的是键值为i的元素可以插入的位置的第一个位置(下界)。
*/

怎么理解呢,举例:
在升序的set里面
set里没有元素i的时候,两个元素的返回值是一样的。
1 2 4 5 这个序列,upp(3)和low(3)都返回位置2(下标)

如果只有一个元素i,low返回那个元素的位置,而upp返回那个元素的位置的后一个位置。
1 2 4 5 这个序列upp(2)返回下标2而low(2)返回下标1

多个元素i,low返回那个元素的位置,upp返回那多个元素中的最后一个的后一个位置。
1 2 2 4 5 这个序列 upp(2)返回下标3的位置,low(2)返回下标1的位置。

!!!!!!!!!!!!!
特别注意:举例在一个升序的容器里,如果所有元素都大于i则,upp和low都返回begin。都小于i则返回end(越界了)。

最后再来一句,看是否好理解一些。

terator lower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素。
iterator upper_bound( const key_type &key ):返回一个迭代器,指向键值<=key的最后一个元素的后一个元素。
★降序排列的容器:
iterator lower_bound( const key_type &key ): 返回一个迭代器,指向键值<= key的第一个元素。
iterator upper_bound( const key_type &key ):返回一个迭代器,指向键值>=key的最后一个元素的后一个元素。
例如:

bool cmp(int a,int b)
{return a<b;
}
int main()
{int a[10]={2,7,1,4,4,6};sort(a,a+6,cmp);        // 去重之前先排序int m=unique(a,a+6)-a; // 去重cout<<m<<endl;        // 输出去重之后的长度for(int i=0;i<m;i++)cout<<a[i]<<' '; // 输出去重之后的数cout<<endl;int tem=upper_bound(a,a+6,4)-a;//按从小到大 4 最多能插入数组 a 的哪个位置int p=lower_bound(a,a+6,4)-a;//按从小到大,4最少能插入数组 a  的哪个位置cout<<tem<<endl;cout<<p<<endl;
}输出
5
1 2 4 6 7
3
2

转载于:https://www.cnblogs.com/zcy19990813/p/9702745.html

离散化+unique()+二分查找相关推荐

  1. 二分查找(Binary Search)需要注意的问题,以及在数据库内核中的实现

    问题背景 今年的实习生招聘考试,我出了一道二分查找(Binary Search)的题目.题目大意如下: 给定一个升序排列的自然数数组,数组中包含重复数字,例如:[1,2,2,3,4,4,4,5,6,7 ...

  2. 算法图解/二分查找/简单查找/选择排序/递归算法/快速排序算法/

    大 O 表示法 大 O 表示法在讨论运行时间时,log 指的都是 log2 大 O 表示法指出了算法有多快,让你能够比较操作数,它指出了算法运行时间的增速,而并非以秒为单位的速度. 大 O 表示法指出 ...

  3. LeetCode简单题之二分查找

    题目 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1. 示例 1: 输入: n ...

  4. 二分查找模板全面总结

    二分查找 二分法的引入 情形1 1.X的平方根 2.搜索旋转排序数组 情形2 1.第一个错误的版本 2.寻找峰值 3.寻找旋转排序数组中的最小值 情形3 在排序数组中查找第一个和最后一个位置 当遇到查 ...

  5. 数据结构与算法(8-2)有序表查找(折半查找(二分查找)、插值查找)

    目录 一.折半查找(二分查找) 二.插值查找 总代码 一.折半查找(二分查找) 原理:一次次折半,不断向着查找值的位置靠近 . 适用场景:有序(必须) 流程:开始时,min标志首,max标志尾,med ...

  6. 二分查找算法的一点改进

    在计算机科学中,二分查找,是一种在有序数组中查找某一特定元素的搜索算法.这种搜索算法每一次比较都使搜索范围减半.第一篇二分查找的论文发表于1946年,然而第一个没有bug的二分查找算法却是在1962年 ...

  7. 二分法:二分查找(递归+非递归)实现

    二分查找又称折半查找,首先,假设表中元素是按升序排列,将 表中间位置的关键字与查找关键字比较: 如果两者相等,则查找成功; 否则利用中间位置将表分成前.后两个子表: 1)如果中间位置的关键字大于查找关 ...

  8. python数据结构与算法:二分查找

    二分查找:python 实现 def binary_seaech(alist,item):"""二分查找 递归实现"""n = len(al ...

  9. 【C++】C++11 STL算法(四):二分查找法(Binary search operations)、合并操作

    目录 一.lower_bound 1.原型: 2.说明: 3.官方demo 二.upper_bound 1.原型: 2.说明: 3.官方demo 三.binary_search 1.原型: 2.说明: ...

最新文章

  1. python 舍去小数_零基础小白Python入门必看——编程基础概念
  2. 如何对.NET远程处理框架相关知识简介
  3. virtualbox php mac,mac一体机通过Oracle VM VirtualBox装win8.1系统
  4. ibatis中使用List作为传入参数的使用方法及 CDATA使用
  5. ajax获得excel文件流在前端打开_主流前端技术讲解,面试必考!
  6. ie不兼容的几个js问题及解决办法
  7. rtrim()正确的理解啊
  8. 《码出高效:Java 开发手册》技术笔记
  9. 基于vue的手机阅读小说类webapp
  10. Chrome对应webdriver版本
  11. qq互联--qq登录例子 java版 源码_PHP版QQ互联OAuth示例代码分享
  12. 进位位判别法_判断加减法溢出时,可采用判断进位的方式,如果符号位的进位为C...
  13. STM32CubeIDE USB Audio声卡 WM8978 + I2S
  14. 适合全家一起看的温馨大电影-《熊出没之雪岭熊风》
  15. TscanCode代码扫描工具
  16. 助力无人船舶,开拓水上智能
  17. uni-app字符串数字转换
  18. 【十一】消息中间件选型分析——从Kafka与RabbitMQ的对比来看全局
  19. 想看懂资管行业?不清楚有哪些资管产品怎么行!
  20. ale.js 对比其他框架

热门文章

  1. Ajax单元测试傻瓜教程
  2. php+mysqli实现批量执行插入、更新及删除数据的方法
  3. CentOS下的账户管理
  4. Mikrotik RouterOS 日常问题解析 ROS 5.4下载
  5. Java线程:线程栈模型与线程的变量
  6. 利用vs.net快速开发windows服务(总结)
  7. 【正一专栏】钱都从哪里来的?
  8. autograd库测试笔记-(一个基于Numpy的自动求导库)
  9. 访问者模式用到了一种双分派的技术——静态分派和动态分派
  10. 单点效率测试工具:F8秒表