0
点赞
收藏
分享

微信扫一扫

算法学习(5) 数据结构:用数组实现单链表/栈/队列/单调栈/单栈队列/KMP/kmp统计字串


1、数组模拟单链表

例题:826. 单链表

​​https://www.acwing.com/problem/content/828/​​算法学习(5) 数据结构:用数组实现单链表/栈/队列/单调栈/单栈队列/KMP/kmp统计字串_滑动窗口

输入样例:
10
H 9
I 1 1
D 1
D 0
H 6
I 3 6
I 4 5
I 4 5
I 3 4
D 6
输出样例:
6 4 6 5

#include<iostream>
using namespace std;

const int N = 100010;

// head 头结点下标,e[i]表示结点i的值
// ne[i]表示下一个结点的下标,idx表示当前已经用到了哪个点
int head, e[N], ne[N],idx=0;

//初始化
void init() {
head = -1;
idx = 0;
}

// 插入头节点 “H x”,表示向链表头插入一个数x。
void add_to_head(int x) {
e[idx] = x;
ne[idx] = head;
head = idx;
idx++;
}


// 插入指定结点后 “I k x”,表示在第k个输入的数后面插入一个数x(此操作中k均大于0)。
void insert(int k, int x) {
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx;
idx++;
}

// 删除k结点后一个点, “D k”,表示删除第k个输入的数后面的数(当k为0时,表示删除头结点)。
void remove(int k) {
ne[k] = ne[ne[k]];
}

int main() {
init();
int m;
cin >> m;
while (m--) {
char a;
int k, x;
cin >> a;
if (a == 'H') {
cin >> x;
add_to_head(x);
}
else if (a == 'I') {
cin >> k >> x;
insert(k-1, x);
}
else {
cin >> x;
if (!x)
head = ne[head];
remove(x-1);
}
}
for (int i = head; i != -1; i = ne[i])
cout << e[i] << " ";
}

例题:827. 双链表

算法学习(5) 数据结构:用数组实现单链表/栈/队列/单调栈/单栈队列/KMP/kmp统计字串_滑动窗口_02

数据范围
1≤M≤100000
所有操作保证合法。

输入样例:
10
R 7
D 1
L 3
IL 2 10
D 3
IL 2 7
L 8
R 9
IL 4 7
IR 2 2
输出样例:
8 7 7 3 2 9

#include<iostream>
using namespace std;

const int N = 100010;

// head 头结点下标,e[i]表示结点i的值
// ne[i]表示下一个结点的下标,idx表示当前已经用到了哪个点
int head, e[N], l[N],r[N],idx=0;

// 初始化
void init() {
// 0 表示左端点,1表示右端点
r[0] = 1, l[1] = 0;
idx = 2;
}

// 第k个点右边插入一个点
void IR(int k, int x) {
e[idx] = x;

r[idx] = r[k];
l[idx] = k;

l[r[k]] = idx;
r[k] = idx;
idx++;
}

// 第k个点左边插入一个点
void IL(int k, int x) {
e[idx] = x;

l[idx] = l[k];
r[idx] = k;

r[l[k]] = idx;
l[k] = idx;
idx++;
}

// 删除第k个结点
void remove(int k) {
r[l[k]] = r[k];
l[r[k]] = l[k];
}

// “L x”,表示在链表的最左端插入数x。
void L(int x) {
e[idx] = x;

l[idx] = 0;
r[idx] = r[0];

r[0] = idx;
l[r[idx]] = idx;

idx++;
}

//“R x”,表示在链表的最右端插入数x。
void R(int x) {
e[idx] = x;

r[idx] = 1;
l[idx] = l[1];

r[l[idx]] = idx;
l[1] = idx;

idx++;
}

int main() {
ios::sync_with_stdio(false);
init();
int m; cin >> m;
string opt;
int k, x;
while (m--) {
cin >> opt;
if(opt== "L"){
cin >> x;
L(x);
}
else if (opt == "R") {
cin >> x;
R(x);
}
else if (opt == "D") {
cin >> k;
remove(k+1);
}
else if (opt == "IL") {
cin >> k >> x;
IL(k+1, x);
}
else if (opt == "IR") {
cin >> k >> x;
IR(k+1, x);
}
}
for (int i = r[0]; i != 1; i = r[i]) {
cout << e[i] << " ";
}
}
/*
(1) “L x”,表示在链表的最左端插入数x。

(2) “R x”,表示在链表的最右端插入数x。

(3) “D k”,表示将第k个插入的数删除。

(4) “IL k x”,表示在第k个插入的数左侧插入一个数。

(5) “IR k x”,表示在第k个插入的数右侧插入一个数。

输入样例:
10
R 7
D 1
L 3
IL 2 10
D 3
IL 2 7
L 8
R 9
IL 4 7
IR 2 2
输出样例:
8 7 7 3 2 9
*/

2、数组模拟栈

#include<iostream>
using namespace std;
const int N = 10010;
int stk[N], stt=0;

//========= 栈 ==================

// 插入
void push(int x) {
stk[++stt] = x;
}

// 弹出
void pop() {
stt--;
}

//判断是否为空
bool isempty() {
return stt > 0;
}

//栈顶
int top() {
return stk[stt];
}

3、数组模拟队列

#include<iostream>
using namespace std;
const int N = 10010;

int q[N], hh, tt = -1;

// 插入
void push(int x) {
q[++tt] = x;
}
//弹出
void pop() {
hh++;
}
// 判断是否为空
bool isEmpty() {
return hh > tt;
}

int top() {
return q[hh];
}

4、单调栈

算法学习(5) 数据结构:用数组实现单链表/栈/队列/单调栈/单栈队列/KMP/kmp统计字串_滑动窗口_03

思路:

最小值和最大值分开来做,两个for循环完全类似,都做以下四步:

解决队首已经出窗口的问题;
解决队尾与当前元素a[i]不满足单调性的问题;
将当前元素下标加入队尾;
如果满足条件则输出结果;
需要注意的细节:

上面四个步骤中一定要先3后4,因为有可能输出的正是新加入的那个元素;
队列中存的是原数组的下标,取值时要再套一层,a[q[]];
算最大值前注意将hh和tt重置;
此题用cout会超时,只能用printf;
hh从0开始,数组下标也要从0开始。

#include<iostream>
using namespace std;

const int N = 100010;
int stk[N], tt = 0;

int main() {
cin.tie(0); //通过tie(0)(0表示NULL)来解除cin与cout的绑定,进一步加快执行效率。
ios::sync_with_stdio(false);
int n; cin >> n;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
while (tt && stk[tt] >= x)
tt--;
if (tt)
cout << stk[tt] << ' ';
else
cout << -1 << ' ';
stk[++tt] = x;
}
}

​​关于ios::sync_with_stdio(false);和 cin.tie(0)加速c++输入输出流​​

5、单栈队列

​​https://www.acwing.com/problem/content/156/​​算法学习(5) 数据结构:用数组实现单链表/栈/队列/单调栈/单栈队列/KMP/kmp统计字串_滑动窗口_04

您的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。

输入格式
输入包含两行。

第一行包含两个整数n和k,分别代表数组长度和滑动窗口的长度。

第二行有n个整数,代表数组的具体数值。

同行数据之间用空格隔开。

输出格式
输出包含两个。

第一行输出,从左至右,每个位置滑动窗口中的最小值。

第二行输出,从左至右,每个位置滑动窗口中的最大值。

输入样例:
8 3
1 3 -1 -3 5 3 6 7
输出样例:
-1 -3 -3 -3 3 3
3 3 5 5 6 7

#include<iostream>
using namespace std;

const int N = 1e6+10;

/*
输出格式
输出包含两个。
第一行输出,从左至右,每个位置滑动窗口中的最小值。
第二行输出,从左至右,每个位置滑动窗口中的最大值。
输入样例:
8 3
1 3 -1 -3 5 3 6 7
输出样例:
-1 -3 -3 -3 3 3
3 3 5 5 6 7
*/
int n, k;

int a[N], q[N];// a是真实输入的数组,q是队列
int hh, tt = -1;//队头hh、队尾tt
int main() {
//cin >> n >> k;
scanf_s("%d%d", &n,&k);
for (int i = 0; i < n; i++)
scanf_s("%d", &a[i]);
// 求滑动窗口内最小
for (int i = 0; i < n; i++) {

// 判断队头是否滑出窗口,作用:维持滑动窗口的大小
//当队列不为空(hh <= tt) 且 当当前滑动窗口的大小(i - q[hh] + 1)>我们设定的
//滑动窗口的大小(k),队列弹出队列头元素以维持滑动窗口的大小
if (hh <= tt && i - k + 1 >q[hh]) hh++;

//当队列不为空(hh <= tt) 且 当队列队尾元素>=当前元素(a[i])时,那么队尾元素
//就一定不是当前窗口最小值,删去队尾元素,加入当前元素(q[ ++ tt] = i)
while (hh <= tt && a[q[tt]] >= a[i]) tt--; // 若队尾不单调,tt减1,队列中存的是原数组的下标,取值时要再套一层,a[q[]]
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--; // 若队尾不单调,tt减1

q[++tt] = i;

if (i >= k - 1) printf("%d ", a[q[hh]]);
}
}

6、字符串匹配算法–kMP

KMP字符串匹配算法1

KMP字符串匹配算法1(理论)链接:
​​​ https://www.bilibili.com/video/BV1Px411z7Yo/?spm_id_from=333.788.b_7265636f5f6c697374.5​​

KMP字符串匹配算法2

推荐博客学习:从头到尾彻底理解

例题:​​28. 实现 strStr()​​

算法学习(5) 数据结构:用数组实现单链表/栈/队列/单调栈/单栈队列/KMP/kmp统计字串_#include_05

#include<iostream>
#include<string>
using namespace std;
class Solution {
public:
int strStr(string haystack, string needle) {
int* Next = new int[needle.length()];
int res = kmpSearch(haystack, needle,Next);
delete []Next;
return res;
}
private:
void getNextVal(string p,int Next[]) {
int pLen = p.length();
Next[0] = -1;
int k = -1, j = 0;
while (j < pLen - 1) {
// p[k] 表示前缀,p[j]表示后缀
if (k == -1 || p[k] == p[j]) {
++j;
++k;
if (p[j] != p[k]) {
Next[j] = k;
}
else {
//因为不能出现p[j] = p[ next[j ]],所以当出现时需要继续递归,k = next[k] = next[next[k]]
Next[j] = Next[k];
}
}
else {
k = Next[k];
}
}
}
int kmpSearch(string s,string p,int Next[]) {
if (p.length() == 0) return 0;
getNextVal(p, Next);
int sLen = s.length(), pLen = p.length();
int i = 0, j = 0;
while (i < sLen && j < pLen) {
//①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++
if( -1 == j || s[i] == p[j]) {
i++;
j++;
}
else {
//②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]
//next[j]即为j所对应的next值
j = Next[j];
}
}
if (j == pLen)
return i - j;
else
return -1;
}
};

算法学习(5) 数据结构:用数组实现单链表/栈/队列/单调栈/单栈队列/KMP/kmp统计字串_滑动窗口_06


举报

相关推荐

0 条评论