第一章 基础算法(三)(双指针、二进制、离散化)

一、双指针算法

1、运用某些性质 O(n^2)->O(n)

(一)将一段字符串的单词逐行输出
#include<bits/stdc++.h>
//找单词输出(默认开头没有空格,并单词之间只有一个空格)
using namespace std;
const int N=1e3+10;
int n;
int main()
{
   char s[N];
   gets(s);//字符串的输入方式
   n=strlen(s);
   for(int i=0;i<n;i++)
   {
       int j=i;
       while(j<n&&s[j]!=' ')j++;
       for(int k=i;k<j;k++)cout<<s[k];
       cout<<endl;
       i=j;//每个循环加加
       
   }

}


(二)求一个字符串的最长连续不重复子序列的长度

i作为子序列末尾进行枚举,每次找最左的j的位置。j不可能向前走,因为j向后走的原因就是这个子序列里面已经有重复元素了。

#include<bits/stdc++.h>
//799
using namespace std;
const int N=1e3+10;
int a[N];
int s[N];//用于保证当前的子序列中没有重复元素
int n;
int main()
{
   scanf("%d",&n);
   for(int i=0;i<n;i++)scanf("%d",&a[i]);
   int res=0;
   for(int i=0,j=0;i<n;i++)
   {
       s[a[i]]++;
       while(s[a[i]]>1)//只要出现重复元素,调整j,从左向右依次剖出元素
       {
           s[a[j]]--;
           j++;
       }
       res=max(res,i-j+1);
   }

   cout<<res<<endl;
   return 0;

}


二、二进制

(三)看某一个数字的二进制的第k位是什么
#include<bits/stdc++.h>
//看某一个数字的二进制的第k位是什么
using namespace std;
const int N=1e3+10;
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    cout<<(n>>k&1);
}

1、lowbit(x)返回最后一位1

 计算方式:x&-x即可得到

(四)应用:统计1的个数
#include<bits/stdc++.h>
//801 求给定数字的1的个数
using namespace std;
const int N=1e3+10;
int lowbit(int x)
{
    return x & -x;
}
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        int x;
        cin>>x;
        int res=0;
        while(x)x-=lowbit(x),res++;
        cout<<res<<endl;
    }
}

 三、离散化求区间和

1、值域跨度很大,很稀疏

#include<bits/stdc++.h>
//802 区间和
using namespace std;
const int N=3e5+10;
typedef pair<int,int>PII;
int n,m;
int a[N],s[N];
vector<int>alls;//所有下标和询问所需要的下标
vector<PII>add,query;//存储所有插入和询问
int find(int x)//找到某个下标在离散化的位置
{
    int l=0,r=alls.size()-1;
    while(l<r)
    {
        int mid=(l+r>>1);
        if(alls[mid]>=x)r=mid;
        else l=mid+1;
    }
    return r+1;//因为得到位置之后要在a上加加,又因为后面要求前缀和,所以得到的下标又加一
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        int x,c;
        cin>>x>>c;
        add.push_back({x,c});//保存插入的位置和数据
        alls.push_back(x);//保存插入的位置

    }
    for(int i=0;i<m;i++)
    {
        int l,r;
        cin>>l>>r;
        query.push_back({l,r});//保存询问
        alls.push_back(l);//保存询问下标,all里存储的是全部要用的下标
        alls.push_back(r);
    }
    //去重
    sort(alls.begin(),alls.end());//由于下标很稀疏,先进行排序
    alls.erase(unique(alls.begin(),alls.end()),alls.end());//去重
    //添加数字的时候
    for(auto item :add)
    {
        int x=find(item.first);
        a[x]+=item.second;
    }
    for(int i=1;i<=alls.size();i++)s[i]=s[i-1]+a[i];
    for (auto item:query)
    {
        int l=find(item.first),r=find(item.second);
        cout<<s[r]-s[l-1]<<endl;
    }
}

2、unique的实现:获取数组的所有不重复的元素

vecotr<int>::iterator unique(vector<int> a)
{
    int j=0;
    for(int i=0;i<a.size();i++)
        if(!i||a[i]!=a[i-1])
           a[j++]=a[i];
    return a.begin()+j;

}

四、区间合并

1、输入n个区间进行合并,得到最后的区间个数

#include<bits/stdc++.h>
//803 区间合并
using namespace std;
const int N=1e5+10;
typedef pair<int,int>PII;
int n;
void merge(vector<PII>segs)
{
    sort(segs.begin(),segs.end());
    int st=-2e9,ed=-2e9;//存
    vector<PII>res;
    for(auto item:segs)
    {
        if(item.first>ed)//比较
        {
            if(st!=-2e9)res.push_back({st,ed});
            st=item.first,ed=item.second;
        }
        else ed=max(ed,item.second);
    }
    if(st!=-2e9)res.push_back({st,ed});//不要落下最后一个
    segs=res;
}
vector<PII>segs;
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int l,r;
        cin>>l>>r;
        segs.push_back({l,r});
    }
    merge(segs);
    cout<<segs.size()<<endl;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值