| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> 双指针算法、位运算、离散化、区间合并 -> 正文阅读 |
|
[数据结构与算法]双指针算法、位运算、离散化、区间合并 |
双指针算法①指向两个序列 把两个有序序列合并??? ? 归并排序 ②指向一个序列 两个指针维护一个区间? 快速排序 如果用暴力做法,需要把 i,j 都从 0→n 循环一遍? O( n^2 ) 所有双指针算法的时间复杂度都是 O(n) 用两个指针扫描一个序列, 每一个指针在所有循环中总共移动的次数不超过 n,两个指针总共移动的次数不超过 2n? O( n ) 从中挖掘出某些性质,把 O( n^2 ) 的时间复杂度优化为 O( n ) ?
输入一个字符串,把其中的每个单词输出:输入字符串中的每个单词用空格隔开,输出的每个单词各占一行 假定字符串的开头没有空格,并且每两个单词之间只有一个空格
最大连续不重复子序列先枚举终点再枚举起点, check 从 j ~ i 条件是否满足,如果满足则更新答案,取 max(res,从 j 到 i 一共有多长) 红色是 i,绿色是 j,i 、j 具有单调性 注意不能直接去重,因为是连续的一段 (去重后可能就不连续了) 绿色指针最左能到什么位置,使得绿色指针和红色指针之间是没有重复数字的 数据很大、不开数组判重的方法:使用哈希表 先使用暴力做法,然后看数据有没有单调关系,有单调关系就利用单调关系把 O( n^2 ) 的复杂度变成 O(n) 1 2 2 3 5 中最长的不包含重复数字的子序列为 2 3 5 当 i 指向第一个数 1,j 指向 1,当 i 指向第二个数 2,j 还是指向 1(前两个没有重复数字),当 i 指向第三个数 2,j 只能指向同一个数字(当 i 指向第三个数的时候,j 不管是指向 1 还是 2 都有重复数字,因此 j 只能和 i 指向同一个位置) . . .? 随着红色指针往后移动,绿色指针一定也是往后移动的,不会往前移动→ 只枚举 i,j 每次看一下要不要往后走:check( j,i ),判断 j ~ i 之间有没有重复元素,如果有重复元素就把 j ++,直到 j 和 i 之间没有重复元素为止,最后得到以 i 为右端点,j 为左端点最远在什么地方,对于所有的 j 求出最大值就是答案 题目数据范围比较小:在 0~10w 范围内,可以考虑直接开一个数组 s[ N ],动态记录一下当前区间中每个数出现多少次 如果 i 往后移动一格,相当于在区间中加入了一个新的数 s[ a[ i ] ] ++ 如果 j 往后移动一格,就说明 [ j,i ] 区间中有一个数出去了 s[ a[ j ] ] - -,就可以动态统计区间中有多少个数 前一个 i 结束的时候,对应的 [ i,j ] 区间中是没有重复元素的,如果新加入的 i 导致区间中出现了重复的元素,那么 a[ i ] 就是重复的元素 check( aj ≠ ai) ? j 往后走的时候一定要把 a[ i ] 的值去掉一个才可以
位运算求一个整数 n 的二进制表示中第 k 位是几? k 的下标如图所示,个位是第 0 位,十位是第 1 位 . . . 10 的二进制表示:1010,右移 3 位就是把最高位移到个位
lowbit(x)数状数组的基本操作 返回的是一个二进制数,这个二进制数的最高一位 1,就是 x 的最后一位 1 一个整数的负数是原数的补码,补码 = 取反 + 1 统计 x 中 1 的个数→ 每次把 x 的最后一位 1 去掉,当 x = 0 的时候,里面就没有 1 了,减了多少次,就说明 x 中有多少个 1 二进制中 1 的个数?
?原码、反码、补码为什么计算机中的负数不直接用反码来表示,而是用补码来表示? 计算机底层实现是没有减法的,因此要用加法来做减法,负数的性质:x + ( - x ) = 0
离散化特指整数的离散化、保留顺序的离散化 给出一些数值,数值的范围比较大:0 ~ 10^9,个数比较少:10^5 个数 题目需要以这些数值为下标来进行求解,不能开一个 10^9 的数组,需要把给出的数值映射到从 0 开始的连续自然数 把 1 映射到 [ 0 ],把 3 映射到 [ 1 ],把 100 映射到 [ 2 ],把 2000 映射到 [ 3 ],把 50000 映射到 [ 4 ] 的过程就被称为离散化 注意:a 数组是有序的,离散化的过程就把 x 映射到下标,找 x 这个值在 a 数组中的下标可以用二分法 由于 a 数组可能有重复元素,需要去重 C++中erase函数的使用,可以用来删除内存擦除_dic56858的博客-CSDN博客 unique 函数 详解_生于忧患,死于安乐2017的博客-CSDN博客_unique函数
从 0 到数组 n - 1,二分法找 x 的位置
给出一个无限长的数轴,起初数轴上所有点上的数都是 0,现在有 n 个操作,每次选择一个下标,把下标上的数 x 加上 c,第一次把下标为 100 位置上加上 50,第二次把下标为 100 位置上加上 20. . . 操作之后有 n 次询问,每次询问 l 和 r 之间的所有数的和,假设要询问 - [ 1000 ] ~ [ 1000 ] 所有数的和:和为 70 示例: 有 3 次操作:第 1 次把下标为 1 的位置加上 2,第 2 次把下标为 3 的位置加上 6,第 3 次把下标为 7 的位置加上 5 有 3 次询问:第 1 次问 [ 1 ] ~ [ 3 ] 所有数的和:和为 8,第 2 次问 [ 4 ] ~ [ 6 ] 所有数的和:和为 0,第 3 次问 [ 7 ] ~ [ 8 ] 所有数的和:和为 5 如果数据的范围比较小,可以用前缀和算法:前缀和、差分_菜徐鸭的博客-CSDN博客 题目给出的数据范围比较大:- 10^9 ~ 10^9,但是涉及的数的个数很少、值域跨度很大但是里面的数很稀疏,只需要用到它们之间的相对关系,每次求所有数的和,其实只要求 L ~ R 之间所有数的和,与每个值的绝对大小无关,只与相对大小有关系,先把所有用到的、不同的数映射成从 1 开始的自然数,映射后的数据范围为 1 ~ 3 × 10^5,用前缀和的方式来解决这个问题 每次求一个区间和的时候,输入一个 L、输入一个 R,求下标 L ~ R 之间所有数的和,其实是想找到 x 在 L ~ R 之间的所有数 x1、x2、. . . xk 求和,只要在 L ~ R 之间就把之前加过的数加上:保序离散化的方式,把所有用到的下标映射到从 1 开始的自然数(需要求前缀和,从 1 开始映射) 每次想给 x 这个位置上的数加上 c,先找到 x 离散化之后的值是多少,在 x 离散化后的值的位置上加上 c 即可:假设 x 离散化后的值是 k,让 a[ k ] += c 即可 求某一个区间里面的所有数的和:求 L ~ R 之间所有数的和,先把 L 和 R 离散化到它们对应的下标的位置,L 离散化后是 kL,R 离散化后是 kR,求 a[ kL ] ~ a[ kR ] 之间的所有数的和即可 把数组上的每个值映射到它的下标,排序后,下标就是它映射的值 a 数组排序后:1、2、100、2000、30000,下标对应为 0、1、2、3、4,把 a 数组中的每个数映射成它的下标:1 映射成 0,2 映射成 1,100 映射成 2 插入操作总数为 n = 10 w、有一个坐标,查询操作总数为 m = 10 w、有两个坐标,离散化的数据规模为 n + 2m,所以开 30 w 个数组
实现 unique 函数 实现思路为双指针算法:把所有不重复的元素 (所有满足下面性质的数) 放到前 j 个位置 第一个指针 i 遍历所有的数,第二个指针 j 存当前存到了第几个不同的数,遍历的时候时刻保证 j ≤ i,从 0 ~ j - 1 存储的就是所有不同的元素 先排序,排序后,应该挑出什么样元素(每一段相同的第一个数满足的条件)?什么样的元素是不同的? 所有不同的元素一定满足以下性质,只需要把所有满足这些性质的数拿出来,就是所有不同的元素
区间合并区间合并的应用场景:给出很多的区间,如果两个区间之间有交集,就把它们合并成一个区间(把它们的并集当做新的区间) 题目输入 n 个区间,把这 n 个区间中所有 有交集的区间 进行合并,输出合并之后的区间个数 区间合并算法用于快速地把这 n 个区间中 有交集的区间 进行合并 边界问题:两个区间如果只有端点相交也可以合并 示例: 区间 1 ~ 区间 4、区间 7 ~ 区间 9 可以合并,最终合并之后可以得到 3 个没有任何交集的区间,输出 3 ? ①按照所有区间的左端点排序 ②扫描整个区间,扫描的过程中,把所有可能 有交集的区间 进行合并 每次维护一个当前的区间,当前区间的左端点为 st,当前区间的右端点为 ed,从前往后扫描的过程当中,假设当前已经扫描到了第 i 个区间,第 i 个区间和当前区间的关系有 3 种 (如图) ①在当前区间的内部 ②与当前区间有交集,但是不在内部 ③在当前区间的后面,没有交集 注意不会出现在当前区间左边的情况(由于是按照区间的左端点从小到大的顺序来扫描所有区间的,因此第 i 个区间的左端点,一定是在维护区间左端点的右边) 只会出现以上 3 种情况,如果出现任一情况,如何更新我们现在维护的区间? 对于第 1 种情况而言,更新后 st 和 ed 不变 对于第 2 种情况而言,更新 ed 的位置,把维护的区间变长 如果出现第 3 种情况说明:前面维护的区间和当前区间没有交集,而且是按照左端点从小到大的顺序来扫描所有区间,后面所有区间的左端点一定是在当前区间的后面,从当前区间开始,后面的所有区间和当前维护的区间没有任何交集 由于当前维护的区间已经不会与后面的区间有交集,就可以把维护的区间作为一组解,然后把维护的区间更新成第 i 个区间 ?
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 5:30:12- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |