算法笔记3.双指针,位运算,离散化,区间合并

双指针

思想

双指针并不必须要两个指针,也可以是两个索引(比如int数组的索引)。双指针主要用于减少时间复杂度(我更愿意称为减少不必要的循环次数)。

像我们之前的归并排序就用到了双指针。用了两个索引指向要归并的两个数组的顶端。

一般不是两个指针指两个序列,就是两个指针指向一个序列。

代码

for(i = 0, j = 0; i < n; i++)
{
    while(j < i && check(i, j)) j++;
    //剩下的具体问题具体分析
}

//上面这个可以说是模板也可以说不是,我感觉这个应该没什么固定写法
//只要注意好双指针的更新和边界就行了

位运算

简介

位运算就是将一个数转换为二进制后对二进制位进行计算。其中有一个lowbit问题,意思是要得到一个数的二进制形态的最后一位1。

怎么算

运算就是(x & -x),这个式子相当于是取x的反,加上1后再&一下x。

取反后,原本二进制数中最后一个1的位置就变成了0,这个位置之后的就都从0变成1了。

然后再加上1,然后就开始进位,这个位置之后的就还是0,这个位置的值就又从0变1。

然后再进行一次&操作,这个位置之前的因为取反了跟原二进制数不一样,所以全为0。这个位置因为进位了还是1,跟之前的1&了以后还是1,这个位置后面的取反加1前和取反加1后全是0,所以&了以后还是0.就只剩下我们要找的位置是1了

这个lowbit也可以用来辅助别的问题,比如求二进制数有几个1之类的。

离散化

思想

此处离散化特指整数的离散化。一般是把一个一堆数量级差别很大的值,存入一个数组中,然后通过数组的索引来进行找值和运算。这样可以避免经过太多没有意义的数(比如for循环的时候,如果两个数差距过大并且这两个数之间的值没有什么意义)

一般离散化不会改变数据的相对大小。

(比如我有一堆数据,分别是1,200,50万,100亿。这一堆数据离散化后分别对应的下标就是0,1,2,3)

怎么化

一般会用STL算法离散化,STL就是先从小到大排序,然后去掉重复元素。这样得到一个数组,数组的索引就是离散化后的值。

区间合并

简介

有的时候我们会遇到那种给我们一堆区间,然后要求我们合并区间(就是将区间中有内容重复的合并成一个大区间,可以理解成是将有交集的变成并集)

怎么并

假设我们区间A,B,C……是判断要不要合并的区间,如果是则合并。

我们首先将所有区间以左端点从小到大排序,我们首先以第一个区间为基准,假设第二个区间的左端点小于等于第一个区间的右端点,那就是可以合并。那么我们将这两个区间合并,然后作为第一个区间继续判断下一个区间。假如下一个区间的左端大于第一个区间的右端点,说明不能合并。我们将第一个区间放到答案里面,然后以下一个区间为基准。

这样我们只需要遍历一次所有区间就可以了

代码

void merge(vector<PII> &segs) //PII是指 {10,10} 这样子的数据
{
    vector<PII> res; //用来存储结果的

    //这个默认是先以第一个数排序,然后以第二个数作为第二优先级排序
    sort(segs.begin(), segs.end()); 
    int st = -2e9, ed = -2e9;
    for (auto seg : segs)
    {
        if (ed < seg.first)
        {
            if (st != -2e9) res.push_back({ st , ed });
            st = seg.first, ed = seg.second;
        }
        else
            ed = max(ed, seg.second);
    }

    if (st != -2e9) res.push_back({ st,ed });
    segs = res;
}
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值