双指针
类别:
- 同向快慢指针
- 异常情况,慢指针才动
- 双向指针
- 视情况,左右指针动
最长无重复子串
int max(int a, int b){
if(a < b){
return b;
}else{
return a;
}
}
int lengthOfLongestSubstring(char* s) {
int count[300];
for(int i = 0; i < 300; i++){
count[i] = 0;
}
int l = 0;
// printf("%d", strlen(s));
int res = 0;
int len = strlen(s);
for(int i = 0; i < len; i++){
count[s[i] - ' ']++;
while(count[s[i] - ' '] > 1){
count[s[l] - ' ']--;
l++;
// printf("%d---\n", l);
}
// printf("%d\n", i - l + 1);
res = max(res, i - l + 1);
}
return res;
}
字符串字母异位词
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* findAnagrams(char* s, char* p, int* returnSize) {
//有返回,先定义
int lenS = strlen(s);
int* res = malloc(lenS * sizeof(int));
*returnSize = 0;
//字母异位词就是:找词频一样的
int cntP[26];
int cntS[26];
for(int i = 0; i < 26; i++){
cntP[i] = 0;
cntS[i] = 0;
}
//先统计p中的词频
int lenP = strlen(p);
for(int i = 0; i < lenP; i++){
cntP[p[i] - 'a']++;
}
for(int i = 0; i < 26; i++){
printf("%d ",cntP[i]);
}
//滑动窗口统计s中的
int l = 0;
for(int r = 0; r < lenS; r++){
cntS[s[r] - 'a']++;
if(r - l + 1 == lenP){
//现在窗口大小一致
bool flag = true;
for(int i = 0; i < 26; i++){
if(cntP[i] != cntS[i]) flag = false;
}
if(flag){
res[(*returnSize)++] = l;
}
}
// cntS[s[l] - 'a']--;
//只有窗口大小超过才需要减掉左边
if(r - l + 1 >= lenP){
cntS[s[l] - 'a']--;
l++;
}
}
return res;
}
最长不重复子序列
#include<stdio.h>
#include<stdlib.h>
#define N 100010
int cnt[N];//模拟哈希表,记录词频
int max(int a, int b){
if(a > b){
return a;
}else{
return b;
}
}
int main(){
int n;
scanf("%d", &n);
int* tmp = malloc((n + 1) * sizeof(int));
int x;
for(int i = 0; i < n; i++){
scanf("%d", &x);
tmp[i] = x;
}
int l = 0; int r = 0;
int res = 0;
for(; r < n; r++){
cnt[tmp[r] - 1]++;
while(l <= r && cnt[tmp[r] - 1] > 1){
cnt[tmp[l] - 1]--;
l++;
}
res = max(res, r - l + 1);
}
printf("%d", res);
return 0;
}
数组元素的目标和
#include<stdio.h>
#include<stdlib.h>
int main(){
int n, m, x;
scanf("%d %d %d", &n, &m, &x);
int* A = malloc((n + 1) * sizeof(int));
int* B = malloc((m + 1) * sizeof(int));
int tmp;
for(int i = 0; i < n; i++){
scanf("%d", &tmp);
A[i] = tmp;
}
for(int i = 0; i < m; i++){
scanf("%d", &tmp);
B[i] = tmp;
}
int l = 0; int r = m - 1;
int sum;
while(l < n && r >= 0){
sum = A[l] + B[r];
if(sum > x){
r--;
}else if(sum < x){
l++;
}else{
printf("%d %d", l , r);
break;
}
}
return 0;
}
判断子序列
#include<stdio.h>
#include<stdlib.h>
int main(){
int n, m;
scanf("%d %d", &n, &m);
int* a = malloc((n + 1) * sizeof(int));
int* b = malloc((m + 1) * sizeof(int));
int x;
for(int i = 0; i < n; i++){
scanf("%d", &x);
a[i] = x;
}
for(int i = 0; i < m; i++){
scanf("%d", &x);
b[i] = x;
}
int cnt = 0;
//b数组更长
for(int i = 0; i < m; i++){
if(cnt < n && b[i] == a[cnt]){
cnt++;
}
}
if(cnt == n){
printf("Yes");
}else{
printf("No");
}
return 0;
}
并查集
合并集合
#include<stdio.h>
#include<stdlib.h>
#define N 100010
int f[N];
int find(int a){
if(a != f[a]) f[a] = find(f[a]);
return f[a];
}
int main(){
int n, m;
scanf("%d %d", &n, &m);
//并查集初始化
for(int i = 1; i <= n; i++){
f[i] = i;
}
for(int i = 0; i < m; i++){
char op[2];
scanf("%s", op);
if(op[0] == 'M'){
int a, b;
scanf("%d %d", &a, &b);
int f1 = find(a);
int f2 = find(b);
if(f1 != f2){
f[f1] = f2;
}
}else{
int a, b;
scanf("%d %d", &a, &b);
if(find(a) != find(b)){
printf("No\n");
}else{
printf("Yes\n");
}
}
}
return 0;
}
连通块的数量
#include<stdio.h>
#define N 100010
int f[N];
int cnt[N];
int find(int a){
if(a != f[a]) f[a] = find(f[a]);
return f[a];
}
int main(){
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++){
f[i] = i;
cnt[i] = 1;
}
for(int i = 0; i < m; i++){
char op[3];
scanf("%s", op);
if(op[0] == 'C'){
int a, b;
scanf("%d %d", &a, &b);
int f1 = find(a);
int f2 = find(b);
if(f1 != f2){
cnt[f2] += cnt[f1];
f[f1] = f2;
}
}else if(op[0] == 'Q' && op[1] == '1'){
int a, b;
scanf("%d %d", &a, &b);
int f1 = find(a);
int f2 = find(b);
if(f1 != f2){
printf("No\n");
}else{
printf("Yes\n");
}
}else{
int a;
scanf("%d", &a);
printf("%d\n", cnt[find(a)]);
}
}
return 0;
}
Tire树
Trie字符串统计
#include<stdio.h>
#define N 200100
//模拟树
int t[N][26];
int idx;
//记录单词数
int cnt[N];
//记录每次的字符串
char str[N];
void insert(){
int p = 0; //表示根节点
for(int i = 0; str[i] != '\0'; i++){
//遍历整个字符串
int x = str[i] - 'a';
if(!t[p][x]) t[p][x] = ++idx;//节点不存在,创建
p = t[p][x];//让指针往下走,遍历完字符串
}
//到达最终的节点
cnt[p]++;//表示以此节点为结束的字符串个数
}
void query(){
int p = 0;
for(int i = 0; str[i] != '\0'; i++){
int x = str[i] - 'a';
// if(!t[p][x]) break;//不存在
if(!t[p][x]) {//不能break,否则还是会输出打印
printf("0\n");
return;
}
p = t[p][x];
}
//最终找到了
printf("%d\n", cnt[p]);
}
int main(){
int n;
scanf("%d", &n);
char op[2];
for(int i = 0; i < n; i++){
scanf("%s", op);
scanf("%s", str);
if(op[0] == 'I'){
insert();
}else{
query();
}
}
return 0;
}
异或最大值
//trie树不仅可以存字符串,还可以存二进制数
#include<stdio.h>
#define N 100010
int a[N];
//模拟树
int t[N * 32][2];
int idx;
int max(int a, int b){
if(a > b){
return a;
}else{
return b;
}
}
void insert(int a){
int p = 0;
for(int i = 31; i >= 0; i--){
//存二进制需要从高位开始
int x = a >> i & 1;
if(!t[p][x]) t[p][x] = ++idx;
p = t[p][x];
}
}
int query(int a){
int p = 0;
int res = 0;
for(int i = 31; i >= 0; i--){
int x = a >> i & 1;
if(t[p][!x]){
//要求异或值最大,所以每一次都需要找相反值
p = t[p][!x];
res += 1 << i;//有相反值,异或得1
}else{
p = t[p][x];//不存在相反之,异或得0
}
}
return res;
}
int main(){
int n;
scanf("%d", &n);
int x;
for(int i = 0; i < n; i++){
scanf("%d", &x);
a[i] = x;
insert(a[i]);
}
int res = 0;
//遍历每一个数的异或值,取最大
for(int i = 0; i < n; i++){
res = max(res, query(a[i]));
}
printf("%d", res);
return 0;
}
实现trie
#define N 100010
typedef struct {
int t[N][26];
bool flag[N];
int idx;
} Trie;
Trie* trieCreate() {
Trie* t = malloc(sizeof(Trie));
memset(t, 0, sizeof(Trie)); // 初始化所有值为 0
return t;
}
void trieInsert(Trie* obj, char* word) {
int p = 0;
for(int i = 0; word[i] != '\0'; i++){
int x = word[i] - 'a';
if(!(obj->t[p][x])) obj->t[p][x] = ++(obj->idx);
p = obj->t[p][x];
}
obj->flag[p] = true;
}
bool trieSearch(Trie* obj, char* word) {
int p = 0;
for(int i = 0; word[i] != '\0'; i++){
int x = word[i] - 'a';
if(!obj->t[p][x]) return false;
p = obj->t[p][x];
}
return obj->flag[p];
}
bool trieStartsWith(Trie* obj, char* prefix) {
int p = 0;
for(int i = 0; prefix[i] != '\0'; i++){
int x = prefix[i] - 'a';
if(!obj->t[p][x]) return false;
p = obj->t[p][x];
}
return true;
}
void trieFree(Trie* obj) {
free(obj);
}
/**
* Your Trie struct will be instantiated and called as such:
* Trie* obj = trieCreate();
* trieInsert(obj, word);
* bool param_2 = trieSearch(obj, word);
* bool param_3 = trieStartsWith(obj, prefix);
* trieFree(obj);
*/