这里写目录标题
- 排序
- 快速排序
- 主要思想
- 解法
- 其它细节
- 归并
- 主要思想
- 解法
- STL - sort
- 总结时间效率
- 二分
- 整数二分
- 主要思想
- 解法
- 举例:
- 起始位置
- 结束位置
- 浮点数二分
- 解法
- 二级目录
- 一级目录
- 二级目录
- 二级目录
- 二级目录
- 一级目录
- 二级目录
- 二级目录
- 二级目录
- 一级目录
- 二级目录
- 二级目录
- 二级目录
排序
快速排序
主要思想
解法
1、暴力
开辟新数组 遍历之后 将小的放在一个数组里 大的放在一个数组里 最后将两个数组合并到总数组里
2、双指针
i在左边 j在右边 二者同时向中间移动 但i的值大于等于x时 就停下 j的值小于等于x时 就停下 两个都停下之后 交换两个的值 之后 两者再次同时向中间移动 然后继续这个过程 直到i到了j的右边(或者说j 到了i 的左边)
模板:
main函数中 第一次调用模板时 传入 0 n-1(也就是两个边界的下标)因为是向函数传入左右边界值以供使用 参数就是 l r
模版就是那个quick_sort函数
第一行是判断边界 如果里面没有数 或者只有一个数 那么直接return
之后选定left为分界点 之后初始化i 和 j的位置
然后在while循环里 进行do … while 循环
第一个do i++;while (q[i]<x)意思是只要q[i]<x 那么就会一直在这一行执行 也就是i会一直++
第二个就是 只要满足 q[j]>x 那么就会让j–
之后再判断(i<j)交换 i j 所指向的数据 因为只有上面两个do … while跳出 才能到if 所以这里是指 i j 都停下了 进行if判断并交换 符合解题逻辑
最后递归 依次递归左边区间以及右边区间 以 j 为分界点
quick_sort(q,l,j);
quick_sort(q,j+1,r);
(注意 当递归时传入j时 (例如第一个递归的第三个参数)上面的int x后面必须是q【l】 一定不可以是r)
其它细节
这个表示一百万 100 0000 + 10
所以一百万就是 1e6
+10 是因为预留一些空间 防止越界
根据题目的数据范围 来定义数组的大小
归并
主要思想
首先是两个有序的序列数组 从小到大排列 之后两个指针依次指向两个数组的最小值 也就是最左端 然后比较两个指针的值 将较小值放入res数组 然后谁放入了res 谁的指针后移一位 之后 再次比较 直到某个指针到了最后 那么进行完这次比较之后 将另一个没有比完的数组 依次接在res的最后
当两个数相同时 一般是让第一个序列的指针所指的数放入res
快排以及归并的时间复杂度 都是n*log n
解法
模板:
首先传入q 0 n-1 也就是数组 左边界 右边界
之后在merge_sort函数里面
第一行 判断边界
之后确定分界点 使用 l + r / 2 可以写成 l + r >> 1 这样更快一些
紧接着就分成两个数组 递归调用 以mid为分界点 l mid 以及 mid+1 r
之后 开始合并 首先要定义一个k 用来记录tmp数组的下标 之后i指向l j指向mid+1 也就是都指向两个数组的第一个位置
while循环:当i j 都没出去最后时 循环继续 if 选出较小值 放入临时数组tmp
当第一个循环结束 进入第二个循环 这时 已经有其中一个数组比较完了 所以 就判断是谁还有值 将剩下的值拼接到tmp数组后面即可
最终for循环 将tmp数组的数赋值回q数组 因为最后输出的是q数组 如果不想赋值 直接该输出函数是tmp即可
STL - sort
#include
传入两个指针 指向第一个元素以及最后一个元素 用数组名代替首元素指着 之后q+n指向了最后一个元素
总结时间效率
快速排序 归并排序 STL-sort 三者时间差不多
二分
整数二分
主要思想
图中两个指针所指的点 可以认为是两个目标点 左边是红色区间边界点 右边是黄色区间的边界点
假如要找红色的那个点 那么就是第一种情况 首先让mid = r + l >> 1
之后 看mid是否满足在红色区间 如果在 那么目标值红点在mid右边 所以mid左边可以丢掉 但是mid不能丢掉 因为mid在有效区间内 所以 L = mid
如果mid不满足在红色区间 那么目标值在mid左边 并且mid在绿色区间 不可能取到目标值 所以直接丢掉mid右边以及mid r=mid-1
然后这个就是下面“解法一栏”的第二个模板 看到 L=mid的更新 就回过头把mid改成 r+l +1 >> 1
假如要找绿色区间边界点 简称绿点 也就是把绿点当做目标值 首先让mid= r + l >> 1
之后 看mid是否满足绿色区间 如果满足 那么目标值在mid左边 那么 更新r=mid
else mid在红色区间 目标值在mid右边 更新 l = mid +1
解法
模板:
思考过程
首先 先写mid = l + r >> 1
之后写check()函数 或者直接判断也可以 总之要有一个判断mid在目标值左还是右
之后看满足第一种情况还是第二种
如果是更新了 l=mid 那么回过头来修改mid 在mid的分子上 + 1
如果是更新了 r=mid 那么就无需修改mid
举例:
这里让找每个查询元素的起始位置以及终止位置 那么 我们这里只看某一个查询元素即可
起始位置
首先来找起始位置:
对于一个x 假设我们定性质为 >=x
这样就符合找绿点的情况
最外层while是指m个查询 所以循环体里就是一个查询的代码
目标值用一个变量表示 因为一般都是程序来输入目标值 我们来查找
首先 初始化 l 和 r 的位置 分别是 0 n-1
之后while(l<r)循环条件是l<r 因为当l = r时 就是要找的值
在小循环里 首先定义mid
之后因为要查询绿点 所以 q[mid] >= x
如果为真 那么 r = mid
else l = mid + 1
结束位置
之后找右边坐标 可以理解为右边界
这里插播一下无解的情况 如果最后的结果不是x (如果不是 那么q【l】的值就是>x的第一个值 ) 那么就是无解 直接返回无解的值
这里就是找红点的情况
首先check就是q【mid】<=x 更新 l = mid
else r = mid - 1
这里看到更新的是 l = mid
所以回去修改mid = r + l + 1 >> 1
最后输出 l 其实输出 l 还是 r 都一样 因为 循环最后跳出的条件就是 l = r
浮点数二分
解法
这里无需考虑边界问题 当设定的条件是 mid在目标值右边 更新r = mid
否则 更新 l = mid
循环条件:
如果要求输出六位小数 那么循环条件是 r - l > 1e-8
如果要求输出四位小数 那么循环条件是 r - l > 1e-6