位运算
求n的第k位数字
先把第k位移到最后一位 => n>>k
看 个位 是几 => x&1 (奇数=>1 ;偶数=>0;只保留当前数的最低位)
eg: n=10 => 1010
| k | n >> k(二进制) | n >> k & 1(结果) | 输出字符 |
|---|---|---|---|
| 3 | 1010 >> 3 = 0001 | 0001 & 1 = 1 | 1 |
| 2 | 1010 >> 2 = 0010 | 0010 & 1 = 0 | 0 |
| 1 | 1010 >> 1 = 0101 | 0101 & 1 = 1 | 1 |
| 0 | 1010 >> 0 = 1010 | 1010 & 1 = 0 | 0 |
#include<iostream>
using namespace std;
int main()
{
int n=10;
for(int k=3;k>=0;k--) cout<<(n>>k&1);
return 0;
}
二进制中1的个数
返回n的最后一位1:lowbit(n) = n & -n
-n = ~n+1 // n取反+1
x = 1010 ... 100 ... 0
~x = 0101 ... 011 ...0
~x+1 = 0101 ... 100 ... 0
x&(~x+1) = 0000 ... 100 ... 0
eg:
- x=1010 => lowbit(x) = 10
- x=10100 => lowbit(x) = 1000
#include<iostream>
using namespace std;
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); // 每次减去x的最后一位 1
res++;
}
cout<<res<<' ';
}
return 0;
}
双指针算法
常见问题分类:
(1) 对于一个序列,用两个指针维护一段区间
(2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作
结题模板:
for (int i = 0, j = 0; i < n; i ++ )
{
while (j < i && check(i, j)) j ++ ;
// 具体问题的逻辑
}
最长连续不重复子序列
#include <iostream>
using namespace std;
const int N = 100010;
int n;
int q[N], s[N];
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);
int res = 0;
for (int i = 0, j = 0; i < n; i ++ )
{
s[q[i]] ++ ;
while (j < i && s[q[i]] > 1)
{
s[q[j]] --;
j++;
}
res = max(res, i - j + 1);
}
cout << res << endl;
return 0;
}
数组元素的目标和
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n, m, x;
int a[N], b[N];
int main()
{
scanf("%d%d%d", &n, &m, &x);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
for (int i = 0; i < m; i ++ ) scanf("%d", &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;
}