排序
也可以直接用sort(q,q+n) #include<algorithm>
一.快速排序------分治(找的是一个数来分)
L x r
|----------------------------------------|
1.确定分界点:左边界q[l],中间点q[(l+r)/2],右边界q[r],或随机点
2.调整区间:使得分开后的区间<=x的在左半边,>=x的数在右半边
3.递归处理左右两段 完成排序。
方法思想:数据结构快排,为了方便每次都把指针往中间移动一位,所以一开始把两边的指针都放在两边后的后一位,以便移动。
相关函数: swap(a,b) 交换a,b的值。代码:
#include<iostream>
using namespace std;
const int N=1e6+10;
int n;
int q[N];
void quick_sort (int q[],int l,int r){
if(l>=r) return; //判断边界是否正确
/* 此处有个位运算>>1相当于除2,<<相当于*2 */
int x=q[(l + r>>1],i=l-1,j=r+1; //取分界点,之所以把l往左移一位,把r网右移一位 是为了在每次判断前都移动方便,i++和j--
while(i<j){
do i ++; while(q[i]<x); //判断是否小于并移动指针
do j --; while(q[j]>x); //判断是否大于并移动指针
if(i < j) swap(q[i],q[j]); //只要两指针没相遇之前,经过两次do while两遍都找到了不符合的数,就进行交换
}
quick_sort(q,l,j);
quick_sort(q,j+1,r);
}
int main(){
cin>>n;
for(int i=0;i<n;i++) cin>>q[i];
quick_sort(q,0,n-1);
for(int i=0;i<n;i++){
cout<<q[i]<<" ";
}
return 0;
}
二.归并排序 -----分治nlogn;(用位置分)
1.确定分界点mid=(l+r)/2
2.递归排序left和right
3.归并 把两个有序数列合并成一个 O(n)
代码:
#include<iostream>
using namespace std;
const int N=100010;
int n;
int q[N],tmp[N];
void merge_sort(int q[],int l,int r){
if(l>=r) return;
int mid=l+r >> 1;
// 排序
merge_sort(q,l,mid),merge_sort(q,mid+1,r);
// 归并
int k=0,i=l,j=mid+1;
while(i<=mid&&j<=r)
if(q[i]<=q[j]) tmp[k++] = q[i++];
else tmp[k++] =q[j++];
while(i<=mid) tmp[k++]=q[i++];
while(j<=r) tmp[k++]=q[j++];
for(i=l,j=0;i<=r;i++,j++) q[i]=tmp[j];
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
cin>>q[i];
}
merge_sort(q,0,n-1);
for(int i=0;i<n;i++)
printf("%d ",q[i]);
return 0;
}
整数二分查找
有单调性的一定可以二分,可以二分的题目不一定必须有单调性
二分查找
有单调性一定能用二分,能用二分的不一定有单调性
查找划分边界问题(有序 ,或者一般说最多或者最少)
找两个满足或者不满足的边界:
1.是二分红色模板的边界点(左边找右边界)
//区间[l,r] 被划分成[l,mid]和[mid+1,r]时使用:
Int bsearch(int l,int r)
{
While(l<r)
{
Int mid=l+r+1>>1; //防止l=r时(mid=l+r)进入死循环
If(check(mid)) l=mid;
Else r=mid-1;
}
Return l;
}
2.是二分绿模板的边界点(右边找左边界)
//区间[l,r] 被划分成[l,mid]和[mid+1,r]时使用:
Int bsearch(int l,int r)
{
While(l<r)
{
Int mid=l+r>>1;
If(check(mid)) r=mid;
Else l=mid+1;
}
Return l;
}
Mid=l+r+1/2就是怕r=l-1时出现死循环
问题:(此问题分成两个边界就可以,一个是大于等于x找到左边界,另一个是小于等于x找到右边界)
找到mid
然后通过循环判断不断找
给定一个按照升序排列的长度为 nn 的整数数组,以及 qq 个查询。
对于每个查询,返回一个元素 kk 的起始位置和终止位置(位置从 00 开始计数)。
如果数组中不存在该元素,则返回 -1 -1。
输入格式
第一行包含整数 nn 和 qq,表示数组长度和询问个数。
第二行包含 nn 个整数(均在 1∼100001∼10000 范围内),表示完整数组。
接下来 qq 行,每行包含一个整数 kk,表示一个询问元素。
输出格式
共 qq 行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回 -1 -1。
数据范围
1≤n≤1000001≤n≤100000
1≤q≤100001≤q≤10000
1≤k≤100001≤k≤10000
输入样例:
6 3
1 2 2 3 3 4
3
4
5
输出样例:
3 4
5 5-1 -1
方法1:
#include <iostream>
using namespace std;
const int N=100010;
int n,m ,mid;
int q[N];
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>q[i];
while(m--)
{
int x;
cin>>x;
int l=0,r=n-1;
while(l<r)
{
int mid = l + r >> 1;
if(q[mid]>=x) r=mid;
else l=mid+1;
}
if(q[l]!=x) cout<<"-1 -1"<<endl;
else
{
cout<<l<<' ';
int l=0,r=n-1;
while(l<r)
{
int mid=l+r+1>>1;
if(q[mid]<=x) l = mid;
else r=mid-1;
}
cout<<l<<endl;
}
}
return 0;
}
方法2:
浮点数二分
如果让保留x位小数,就让11行是1e-(x+2)