https://www.acwing.com/activity/content/punch_the_clock/11/
单链表
数组实现链表
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
// head 表示头结点的下标
// e[i] 表示节点i的值
// ne[i] 表示节点i的next指针是多少
// idx 存储当前已经用到了哪个点
int head, e[N], ne[N], idx;
// 初始化
void init(){
head = -1;
idx = 1;
}
// 将x插到头结点
void add_to_head(int x){
e[idx] = x;
ne[idx] = head;
head = idx;
idx++;
}
// 将x插到下标是k的点后面
void insert(int k, int x){
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx;
idx++;
}
// 将下标是k的点后面的点删掉
void remove(int k){
ne[k] = ne[ne[k]];
}
int main(){
int m;
cin >> m;
init();
while(m--){
char oper;
int k, x;
cin >> oper;
if(oper == 'H'){
cin >> x;
add_to_head(x);
}else if(oper == 'D'){
cin >> k;
if(k == 0) head = ne[head];
else remove(k);
}else{
cin >> k >> x;
insert(k, x);
}
}
for(int i = head; i != -1; i = ne[i]){
cout << e[i] << " ";
}
return 0;
}双链表
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int m, k, x;
string oper;
int e[N], l[N], r[N], idx;
//在右边插入
void insert(int k, int x){
e[idx] = x;
l[idx] = k;
r[idx] = r[k];
l[r[k]] = idx;
r[k] = idx;
idx++;
}
void remove(int k){
r[l[k]] = r[k];
l[r[k]] = l[k];
}
int main(){
cin >> m;
// 0是左端点,1是右端点
r[0] = 1, l[1] = 0, idx = 2;
while(m--){
cin >> oper;
if(oper == "L"){
cin >> x;
insert(0, x);
}else if(oper == "R"){
cin >> x;
insert(l[1], x);
}else if(oper == "D"){
cin >> k;
remove(k + 1);
}else if(oper == "IL"){
cin >> k >> x;
insert(l[k + 1], x);
}else{
cin >> k >> x;
insert(k + 1, x);
}
}
for(int i = r[0]; i != 1; i = r[i]){
cout << e[i] << " ";
}
cout << endl;
return 0;
}模拟栈
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int e[N], ne[N], idx;
//在尾部插入
void push(int x){
e[idx] = x;
idx++;
}
void pop(){
idx--;
}
int get_top(){
return e[idx - 1];
}
bool is_Empty(){
return idx <= 0;
}
int main(){
int m, x;
cin >> m;
string oper;
idx = 0;
while(m--){
cin >> oper;
if(oper == "push"){
cin >> x;
push(x);
}else if(oper == "pop"){
pop();
}else if(oper == "empty"){
if(is_Empty()) printf("YES\n");
else printf("NO\n");
}else{
cout << get_top() << endl;
}
}
}表达式求值
#include <bits/stdc++.h>
using namespace std;
stack<int> num;
stack<char> op;
void eval(){
int b = num.top(); num.pop();
int a = num.top(); num.pop();
char c = op.top(); op.pop();
int x;
if (c == '+') x = a + b;
else if (c == '-') x = a - b;
else if (c == '*') x = a * b;
else x = a / b;
num.push(x);
}
int main(){
unordered_map<char, int> pr{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
string s;
cin >> s;
int n = s.size();
for(int i = 0; i < n; i++){
auto c = s[i];
if(isdigit(c)){
int x = 0, j = i;
while(j < n && isdigit(s[j])){
x = x * 10 + s[j++] - '0';
}
num.push(x);
i = j - 1;
}else if(c == '('){
op.push(c);
}else if(c == ')'){
while(op.top() != '(') eval();
op.pop();
}else{
while(op.size() && op.top() != '(' && pr[c] <= pr[op.top()]) eval();
op.push(c);
}
}
while(op.size()) eval();
printf("%d\n", num.top());
}模拟队列
int head, e[N], idx;
//在尾部插入
void push(int x){
e[idx] = x;
idx++;
}
void pop(){
head++;
}
int get_top(){
return e[head];
}
bool is_Empty(){
return head >= idx;
}单调栈
int stk[N], tt;
int main(){
int n;
cin >> n;
tt = 0;
for(int i = 0; i < n; i++){
int x;
cin >> x;
while(tt && stk[tt] >= x) tt--;
if(tt) printf("%d ", stk[tt]);
else printf("-1 ");
stk[++tt] = x;
}
return 0;
}单调队列
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int a[N], q[N];
int main(){
int n, k;
cin >> n >> k;
int minn = INT_MIN, maxn = INT_MAX;
for(int i = 0; i < n; i++){
cin >> a[i];
}
int hh = 0, tt = -1;
for (int i = 0; i < n; i ++ ){
if(hh <= tt && i - k + 1 > q[hh]) hh++ ;
while (hh <= tt && a[q[tt]] >= a[i]) tt-- ;
q[++tt] = i;
if (i >= k - 1) printf("%d ", a[q[hh]]);
}
printf("\n");
hh = 0, tt = -1;
for (int i = 0; i < n; i ++ ){
if(hh <= tt && i - k + 1 > q[hh]) hh++ ;
while (hh <= tt && a[q[tt]] <= a[i]) tt-- ;
q[++tt] = i;
if (i >= k - 1) printf("%d ", a[q[hh]]);
}
return 0;
}KMP
时间复杂度O(n+m)
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100010, M = 1000010;
int n, m;
char s[M], p[N];
int nextt[N];
int main(){
cin >> n >> p + 1 >> m >> s + 1; //字符串从下标1开始
//计算next数组
for(int i = 2, j = 0; i <= n; i++){
while(j && p[i] != p[j + 1]) j = nextt[j];
if(p[i] == p[j + 1]) j++;
nextt[i] = j;
}
//KMP匹配过程
for(int i = 1, j = 0; i <= m; i++){
while(j && s[i] != p[j + 1]) j = nextt[j];
if(s[i] == p[j + 1]) j++;
if(j == n){
printf("%d ", i - n); //这里要求输出的下标从0开始计数
j = nextt[j];
}
}
return 0;
}
Trie
高效地存储和查找字符串集合的数据结构
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n;
string x;
char op;
int son[N][26], cnt[N], idx; //idx是节点序号,son[i][u]代表值为u的节点i的子节点 cnt[i]代表以节点i结尾的字符串个数
void insert(string x){
int p = 0;
for(int i = 0; i < x.size(); i++){
int u = x[i] - 'a';
if(!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
cnt[p]++;
}
int query(string x){
int p = 0;
for(int i = 0; i < x.size(); i++){
int u = x[i] - 'a';
if(!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
}
int main(){
cin >> n;
while(n--){
cin >> op >> x;
if(op == 'I'){
insert(x);
}else{
printf("%d\n", query(x));
}
}
return 0;
}最大异或树
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 3100010;
int n;
int a[N], son[M][2], idx; //idx是节点序号,son[i][u]代表值为u的节点i的子节点
void insert(int x){
int p = 0;
for(int i = 30; i >= 0; i--){
int &s = son[p][x >> i & 1]; //用 int & 是C++里的引用,和指针类似,定义的变量和赋值的变量指向同一块内存,一个改变,另一个也会改变。
if(!s) s = ++idx;
p = s;
}
}
int search(int x){
int p = 0, res = 0;
for(int i = 30; i >= 0; i--){
int u = x >> i & 1;
if(son[p][!u]) {
res += 1 << i;
p = son[p][!u];
}
else p = son[p][u];
}
return res;
}
int main(){
cin >> n;
for (int i = 0; i < n; i++){
scanf("%d", &a[i]);
insert(a[i]);
}
int res = 0;
for (int i = 0; i < n; i++) res = max(res, search(a[i]));
printf("%d\n", res);
return 0;
}并查集
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int p[N];
int find(int x){
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main(){
int n, m, a, b;
cin >> n >> m;
for(int i = 1; i <= n; i++) p[i] = i;
while(m--){
char op;
cin >> op >> a >> b;
if(op == 'M'){
p[find(a)] = find(b);
}else{
if(find(a) == find(b)) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}堆排序和模拟堆
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int h[N], cnt;
void down(int u){
int t = u;
if(u * 2 <= cnt && h[2 * u] < h[t]) t = 2 * u;
if(u * 2 + 1 <= cnt && h[2 * u + 1] < h[t]) t = 2 * u + 1;
if(t != u){
swap(h[t], h[u]);
down(t);
}
}
void up(int u){
while(u / 2 && h[u] < h[u / 2]){
heap_swap(u, u / 2);
u /= 2;
}
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> h[i];
cnt = n;
for(int i = n / 2; i; i--) down(i);
while(m--){
printf("%d ", h[1]);
h[1] = h[cnt];
cnt--;
down(1);
}
return 0;
}哈希表
- 哈希表的存储结构
- 开放寻址法
提问:“开放寻址法的那个memset填充h不应该是0x3f3f3f3f吗?为什么变成了0x3f?,还有奥,按照这个办法来说的话,当h数组满了的话,应该会陷入死循环把”
回答:①memset是按字节来初始化的,int中有四个字节,初始化成0x3f就是将每个字节都初始化成0x3f,所以每个int就是 0x3f3f3f3f。
②数组长度一般开到个数上限的2-3倍。 - 拉链法
- 开放寻址法
- 字符串哈希方式
开放寻址法,y总还讲了拉链法,代码也有,可以去看看。
#include <bits/stdc++.h>
using namespace std;
const int N = 200003, null = 0x3f3f3f3f;
int n, x;
int h[N];
int find(int x){
int t = (x % N + N) % N;
while(h[t] != null && h[t] != x){
t++;
if(t == N) t = 0;
}
return t;
}
int main(){
memset(h, 0x3f, sizeof(h));
cin >> n;
while(n--){
string op;
cin >> op >> x;
if(op == "I"){
h[find(x)] = x;
}else{
if (h[find(x)] == null) puts("No");
else puts("Yes");
}
}
return 0;
}字符串哈希
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N = 100010, P = 131;
int n, m;
char str[N];
ULL h[N], p[N];
int get(int l, int r){
return h[r] - h[l - 1] * p[r - l + 1];
}
int main(){
cin >> n >> m;
cin >> str + 1;
p[0] = 1;
for (int i = 1; i <= n; i ++ ){
h[i] = h[i - 1] * P + str[i];
p[i] = p[i - 1] * P;
}
while(m--){
int l1, r1, l2, r2;
cin >> l1 >> r1 >> l2 >> r2;
if (get(l1, r1) == get(l2, r2)) puts("Yes");
else puts("No");;
}
return 0;
}
京公网安备 11010502036488号