ACWing学习day1:快排,归并,二分

排序

也可以直接用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)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值