双指针与位运算

77 阅读3分钟

双指针运算,位运算

**双指针的算法一般会降低复杂度,进而提高效率

那么优势是什么呢? 他可以将时间复杂度由o(n*n) 降低为o(n) ** 进而提高效率

那么下面是一道题目

\799. 最长连续不重复子序

给定一个长度为 n 的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。

输入格式

第一行包含整数 n。

第二行包含 n 个整数(均在 0∼105 范围内),表示整数序列。

输出格式

共一行,包含一个整数,表示最长的不包含重复的数的连续区间的长度。

数据范围

1≤n≤105

输入样例:
5
1 2 2 3 5
输出样例:
3
#include<iostream>
using namespace std;

const int N = 1e5 + 10;

int n;
int a[N],s[N];

int main()
{
    int n;
    cin >> n;
    for(int i = 0;i<=n;i++)
    {
        cin >> a[i];
    }
    int res = 0;
    for(int i = 0,j=0;i<n;i++)
    {
        s[a[i]] ++;
        while(j < i && s[a[i]] > 1) s[a[j++]]--;
        res = max(res,i-j+1);
    }
    cout << res << endl;
    
    return 0;
}

双指针较为简单

#include<iostream>
using namespace std;

const int N = 1e5 + 10;
int a[N],b[N];

int main()
{
    int n,m,x;
    cin >> n >> m >> x;
    for(int i = 0;i<n;i++)
    {
        cin >> a[i];
    }
    for(int i = 0;i<m;i++)
    {
        cin >> b[i];
    }
    for(int i = 0,j = m-1;i<n;i++)
    {
        while(j >= 0 && a[i] + b[j] > x)   j--;
        if(j >= 0 && a[i] + b[j] == x) cout << i << ' ' << j << endl;
        
    }
    return 0;
}

这个是运用双指针计算数组元素的目标和

#include<iostream>
using namespace std;

const int N = 1e5 + 10;
int a[N],b[N];
int main()
{
    int n,m;
    cin >> n >> m;
    for(int i = 0;i<n;i++)   cin >> a[i];
    for(int i = 0;i<m;i++)   cin >> b[i];
    int j = 0;
    for(int i = 0;i<m;i++)
    {
        if(j < n && a[j] == b[i]) j++;
    }
    
    if(j == n)
    cout << "Yes" << endl;
    else cout << "No" << endl;
    return 0;
        
}

这个是判断子序列的编程方法

以上就是双指针运算了

下面就是重头戏,就是位数运算

想到双指针,就会想到lowbit(x)这个东西

那么什么是lowbit原理呢?

一下为lowbit 的含义:

表示取得整数x的二进制表示中,从右边往左的第一个1以及其后全部0所组成的那部分数值

及可以理解为 只保留x 的最右边的那个1 ,其余位全部清零。

实际上是 x & (-x):

• 在计算机中,负数以补码形式存储。若 x 的二进制是 bxxxx1000(其中 bxxxx 可以理解为前面的若干位),

则 -x 的二进制会是其反码加 1,即再一次把相同位置的最低位 1 提取出来。

• 与运算 x & (-x) 只保留了从右往左遇到的第一个 1 所在位置上的值,其余位全部变为 0。

好的,那么现在理解了什么是lowbit ,那就练习一道题目试一试叭!

假设我有一个数,我要求其二进制1的个数是多少

#include <iostream>
using namespace std;

// 函数:获取 x 的最低位 1 以及其后所有 0 组成的数值
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 不为 0 时,继续提取最低位 1
            x -= lowbit(x);
            res++;         // 每去掉一个最低位 1,就计数 +1
        }

        cout << res << ' ';
    }
    return 0;
}

不知道你们理解了没有,现在我举一个例子吧

比如我输入 31

那么 31 对应的二进制是 11111

现在逐层 去掉最低位 1

\1. lowbit(31) = 1,x = 31 - 1 = 30,res = 1

\2. lowbit(30) = 2,x = 30 - 2 = 28,res = 2

\3. lowbit(28) = 4,x = 28 - 4 = 24,res = 3

\4. lowbit(24) = 8,x = 24 - 8 = 16,res = 4

\5. lowbit(16) = 16,x = 16 - 16 = 0,res = 5

• 最终 res = 5

x & (-x). 这个地方着重理解,非常不错的一个点啊!!!