数据结构与算法笔记【暂存】【20230724】

第一部分

// 讲师:y总
// 限时的笔试、面试、考试、机试、比赛都是考验记忆力的,很少是当场想出来的
// 这种限时应试的学霸往往具备的两种能力是:记忆力和自制力
// 所以代码要“背”下来


#include <iostream>
using namespace std;



// --------单链表---------

const int N = 10010;

// head 表示头结点的下标
// e[i] 表示节点i的值
// ne[i] 表示节点i的next指针是多少
// idx 存储当前可用存储空间的地址
int head, e[N], ne[N], idx;

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

// 将x插到头节点
void add_to_head(int x)
{
    e[idx] = x;
    ne[idx] = head;
    head = idx;
    idx++;
}

// 将x插到下标是k的点后面
void add(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;

    while(m--)
    {
        int k, x;
        char op;

        init();

        cin >> op;
        if (op == 'H')
        {
            cin >> x;
            add_to_head(x);
        }
        else if(op == 'D')
        {
            cin >> k;
            if(!k) head = ne[head];
            remove(k - 1);
        }
        else
        {
            cin >> k >> x;
            add(k -1, x);
        }

    }

    for(int i = head; i != -1; i = ne[i]) cout << e[i] << ' ';
    cout << endl;

    return 0;
}



// --------双链表---------

const int N = 100010;

int m;
int e[N], l[N], r[N], idx;

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

// 在下标是k的点的右边,插入x
void aad(int k, int x)
{
    e[idx] = x;
    r[idx] = r[k];
    l[idx] = k;
    l[r[k]] = idx;
    r[k] = idx;
}

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


--------栈:后进先出---------

const int N = 100010;

int stk[N], tt = 0; // tt表示栈顶下标


// 插入
stk[ ++ tt] = x;

// 弹出
tt --;

// 判断栈是否为空
if(tt > 0) not empty;
else empty;

// 栈顶
stk[tt];



// --------队列:先进先出---------

const int N = 100010;

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

// 插入
q[ ++ tt] = x;

// 弹出
hh ++;

// 判断队列是否为空
if (hh <= tt) not empty;
else empty;

// 取出队头元素
q[hh]



// --------单调栈---------
// 暴力解法
for(i = 0; i<n; i++){
    for (j = i-1; j >= 0; j--){
        if (a[i] > a[j]){
            cout < a[j] << ' ';
            break;
        }
    }
    if(j==-1)cout << -1 << ' ';
}


// 单调栈

#include <cstdio>

const int N = 100010;

int n;
int stk[N], tt;

int main(){

    // 提升读取速度
    ios::sync_with_stdio(false);

    // 用scanf和printf替代cin和cout可以提升十倍左右的速度,但是如果是大数据量建议使用后者
    // 或者使用下面的函数
    cin.tie(0); 

    // cin >> n;
    scanf("%d", &n);

    for (int i = 0; i<n; i++)
    {
        int x;
        // cin >> x;
        scanf("%d", &x);
        while(tt && stk[tt] >= x) tt--;
        if (tt) printf("%d ", stk[tt]); // cout << stk[tt] << ' ';
        else printf("-1 "); // cout << -1 << ' ';

        stk[ ++ tt] = x;
    }

    return 0;
}




// --------两遍输出滑动窗口的最小值和最大值---------
// 利用单调队列优化


const int N = 100010;

int n, k;
int a[N], q[N];

int main(){
    scanf('%d%d', &n, &k);
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);

    // 单调递增队列
    int hh = 0, tt = -1;
    for (int i = 0; i<n; i++)
    {
        // 判断队头是否已经滑出窗口
        if(hh <= tt && i - k +1 > q[hh]) hh++;  // 用if不用while是因为窗口每次只滑动一格
        while(hh <= tt && a[q[tt]] >= a[i]) tt--;
        q[ ++ tt] = i;
        if(i >= k-1)printf("%d", &a[q[hh]]);
    }

    puts(""); // 回车

    // 单调递减队列
    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]]);
    }
    puts("");

    return 0;
}



// --------KMP---------

// 暴力算法
S[N], p[M] // S是比较长的字符串,p是比较短的串
for(int i=1; i<=n; i++)
{
    bool flag = true;
    for(int j=1; j<=m; j++)
        if(S[i] != p[j])
        {
            flag = false;
            break;
        }
}

// KMP算法过程
const int N = 100010, M = 100010;

int n, m;
char p[N], s[M];  // p短字符串,s长字符串
int ne[N];  // ne表示next的意思,但是next在某些头文件定义过了,所以采用ne

int main()
{
    cin >> n >> p + 1 >> m >> s + 1; // p和s的下标从1开始

    // 求next的过程
    for(int i=2, j=0; i<=n; i++){
        while(j && p[i] != p[j+1]) j = ne[j];
        if(p[i] == p[j+1]) j++;
        ne[i] = j;
    }

    // kmp匹配过程
    for(int i=1, j=0; i<=m; i++)
    {
        while(j && s[i] !== p[j+1]) j=ne[j];
        if(s[i] == p[j+1]) j++;
        if(j == n)
        {
            printf("%d ", i - n + 1);  // 如果样例的下标是从0开始,则再减1就好
            j = ne[j];
        }

        return 0;
    }
}


// KMP的Python版,用于辅助理解

// def build_next(patt):
//     '''
//     计算 Next 数组
//     '''

//     next = [0]  # next 数组(初值元素一个0)
//     prefix_len = 0  # 当前共同前后缀的长度
//     i = 1
//     while i < len(patt):
//         if patt[prefix_len] == patt[i]
//             prefix_len += 1
//             next.append(prefix_len)
//             i += 1
//         else:
//             if prefix_len == 0:
//                 next.append(0)
//                 i += 1
//             else:
//                 prefix_len = next[prefix_len - 1]
//     return next

// def kmp_search(string, patt):
//     next = build_next(patt)

//     i = 0 # 主串中的指针
//     j = 0 # 子串中的指针
//     while i < len(string):   
//         if string[i] == patt[j]:  # 字符匹配,指针后移
//             i += 1
//             j += 1
//         elif j > 0:  # 字符失配,根据next跳过子串前面的一些字符
//             j = next[j-1]
//         else:  # 子串第一个字符就失配
//             i += 1

//         if j == len(patt):  # 匹配成功
//             return i - j


// over










第二部分



// -----------------Trie树/字典树----------------------

// Trie树:高效地存储和查找字符串集合的数据结构
// trie树限定字符的种类是较小的,比如这里是小写字母只有26个,所以不适合中文等情况

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 100010;

int son[N][26], cnt[N], idx; // 下标是0的节点,既是根节点,也是空节点
char str[N];

void insert(char str[])
{
    int p = 0;  // 根节点的编号
    for (int i = 0; str[i]; i++)
    {
        int j = str[i] - 'a';  // 字母映射,将a-z映射到0-25
        if(!son[p][j]) son[p][j] = ++ idx;
        p = son[p][j];
    }

    cnt[p] ++;  // 插入次数
}

int query(char str[])
{
    int p = 0;
    for (int i = 0; str[i]; i++)  // str最后一个字符默认\0
    {
        int j = str[i] - 'a';
        if(!son[p][j]) return 0;
        p = son[p][j];
    }

    return cnt[p];
}

int main()
{
    int n;  // n个操作
    scanf("%d", &n);
    while (n--)
    {
        char op[2];
        scanf("%s%s", op, str);
        if(op[0] == 'I') insert(str);
        else printf("%d\n", query(str));
    }

    return 0;
}



// -----------------并查集----------------------

// 1. 将两个集合合并
// 2. 询问两个元素是否在一个集合当中

// 基本原理:每个集合用一棵树来表示。树根的编号就是整个集合的编号,
// 每个节点存储它的父节点, p[x]表示x的父节点

// 问题1:如何判断树根:if(p[x] == x)
// 问题2:如何求x的集合编号:while(p[x]!=x) x=p[x];
// 问题3:如何合并两个集合:px是x的集合编号,py是y的集合编号。令p[x] = y

// 问题2的优化:路径压缩,按秩合并


#include <iostream>
#include <cstdio>
using namespace std;

const int N = 100010;

int n, m;
int p[N];

int find(int x)  // 返回x的祖宗节点(集合编号/根节点) + 路径压缩
{
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main()
{
    scanf("%d%d", &n, &m); //n表示元素的数量,m表示操作的数量

    for (int i = 1; i <= n; i++) p[i] = i; // 初始化,每个元素都是一个集合,父节点指向自己

    while (m--){
        char op[2];
        int a, b;
        scanf("%s%d%d", &op, &a, &b);  // %s是读字符串,为什么不用%c读字符呢,因为前者可以过滤空格和回车

        if(op[0] == 'M') p[find(a)] = find(b);
        else{
            if(find(a) == find(b)) puts("Yes");
            else puts("No");
        }
    }

    return 0;
}


// 连同模块看作一个集合
#include <iostream>
#include <cstdio>
using namespace std;

const int N = 100010;

int n, m;
int p[N], size[N];

int find(int x)  // 返回x的祖宗节点(集合编号/根节点) + 路径压缩
{
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main()
{
    scanf("%d%d", &n, &m); //n表示元素的数量,m表示操作的数量

    for (int i = 1; i <= n; i++) // 初始化,每个元素都是一个集合,父节点指向自己
    {
         p[i] = i;
         size[i] = 1;
    }

    while (m--){
        char op[5];
        int a, b;
        scanf("%s", &op);  // %s是读字符串,为什么不用%c读字符呢,因为前者可以过滤空格和回车

        if(op[0] == 'M') 
        {
            scanf("%d%d", &a, &b);
            if (find(a) == find(b)) continue;
            size[find(b)] += size[find(a)];
            p[find(a)] = find(b);
        }   
        else if (op[1] == '1'){
            scanf("%d%d", &a, &b);
            if(find(a) == find(b)) puts("Yes");
            else puts("No");
        }
        else{
            scanf("%d", &a);
            printf("%d\n", size[find(a)]);
        }
    }

    return 0;
}


// -----------------堆----------------------

// size表示堆的大小,heap表示堆(一维数组)
// 1. 插入一个数
// 2. 求集合当中的最小值
// 3. 删除最小值
// 4. 删除任意一个元素
// 5. 修改任意一个元素

// 小根堆:父节点小于等于子节点
// 存储:用一维数组存储二叉树,1是根节点,x的左儿子是:2x,x的右儿子是2x+1
// STL的堆就是优先队列

// size表示堆的大小,heap表示堆(一维数组)
// 1. 插入一个数:           heap[++size] = x; up(size);
// 2. 求集合当中的最小值:    heap[1];
// 3. 删除最小值:           heap[1] = heap[size]; size--; down(1);
// 4. 删除任意一个元素:      heap[k] = heap[size]; size--; down(k); up(k)
// 5. 修改任意一个元素:      heap[k] = x; down(k); up(k);


// 堆排序
// 从小到大输出:先建立堆,每一步输出堆顶,然后将堆顶赋值最后一个节点,size--,执行down操作
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;

const int N = 100010;

int n, m;
int h[N], size; // h是heap

void down(int u)
{
    int t = u;
    if (u * 2 <= size && h[u * 2] < h[t]) t = u * 2;
    if (u * 2 + 1 <= size && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
    if (u != t){
        swap(h[u], h[t]);
        down(t);
    }
}

void up(int u)
{
    while (u / 2 && h[u / 2] > h[u])
    {
        swap(h[u / 2], h[u]);
        u /= 2;
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i=1; i<=n; i++) scanf("%d", &h[i]); // 不适宜从0开始,因为0*2还是0
    size = n;

    for (int i = n / 2; i; i--) down(i);  // 时间复杂度是O(n),从倒数第二层开始down,因为最后一层不用down

    while(m--){
        printf("%d", h[1]);
        h[1] = h[size];
        size --;
        down(1);
    }

    return 0;
}


// 构造堆,初始时为空,支持前面所说的前四种操作,第五种操作改成:修改第k个插入的数,输出当前集合的最小值

#include <iostream>
#include <string.h>
#include <algorithm>
#include <cstdio>
using namespace std;

const int N = 100010;

int n, m;
int h[N], ph[N], hp[N], size; 
// h是heap,ph[k]表示插入的第k个点是堆里的哪个点,hp[k]表示堆里的某个点是第几个插入的

void heap_swap(int a, int b)
{
    swap(ph[hp[a]], ph[hp[b]]);
    swap(hp[a], hp[b]);
    swap(h[a], h[b]);
}

void down(int u)
{
    int t = u;
    if (u * 2 <= size && h[u * 2] < h[t]) t = u * 2;
    if (u * 2 + 1 <= size && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
    if (u != t){
        heap_swap(u, t);
        down(t);
    }
}

void up(int u)
{
    while (u / 2 && h[u / 2] > h[u])
    {
        heap_swap(u / 2, u);
        u /= 2;
    }
}

int main()
{   
    int n, m=0;  // m表示值是第m个插入的
    scanf("%d", &n);
    while(n--)
    {
        char op[10];
        int k, x;

        scanf("%s", op);
        if (!strcmp(op, "I"))
        {
            scanf("%d", &x);
            size ++;
            m ++;
            ph[m] = size, hp[size] = m;
            h[size] = x;
            up(size);
        }
        else if (!strcmp(op, "PM")) printf("%d\n", h[1])
        else if (!strcmp(op, "DM"))
        {
            heap_swap(1, size);
            size --;
            down(1);
        }
        else if(!strcmp(op, "D"))
        {
            scanf("%d", &k);
            k = ph[k];
            heap_swap(k, size);
            size --;
            down(k), up(k);  // 至多执行一个
        }
        else
        {
            scanf("%d%d", &k, &x);
            k = ph[k];
            h[k] = x;
            down(k), up(k);
        }

    }

    return 0;
}

// over

第三部分



// ----------------哈希表-------------------

// 1. 存储结构
// 1.1 开放寻址法
// 1.2 拉链法
// 2. 字符串哈希方法

// 从10^-9到10^9映射到10^5
// 1)x mod 10^5 (取模的数尽量取成质数)
// 2)冲突

#include <iostream>
#include <cstring>  // 调用memset
using namespace std;


// 查找大于10万的质数,结果是100003
int main()
{
    for (int i = 100000; ; i++)
    {
        bool flag = true;
        for (int j=2; j*j<=i; j++)
        {
            if(i % j == 0)
            {
                flag = false;
                break;
            }
        }
        if(flag){
            cout << i << endl;
            break;
        }
    }
    return 0;
}


// 拉链法
const int N = 100003;

int h[N], e[N], ne[N], idx;

void insert(int x)
{
    int k = (x % N + N) % N;  // 取模操作,c++里负数取模仍是负数,需要+N变成正数
    e[idx] = x, ne[idx] = h[k], h[k] = idx ++;
}

bool find(int x)
{
    int k = (x % N + N) % N;
    for (int i = h[k]; i != -1; i = ne[i])
    {
        if (e[i] == x)
            return true;
    }
    return false;
}

int main()
{
    int n;
    scanf("%d", &n);

    memset(h, -1, sizeof h);  // 将所有“槽”清空,用-1表示

    while (n--)
    {
        char op[2];
        int x;
        scanf("%s%d", op, &x);

        if (*op == 'I') insert(x);
        else 
        {
            if (find(x)) puts("Yes");;
            else puts("No");
        }
    }

    return 0;
}


// 开放寻址法
// 开的数组一般是题目的两到三倍
// 故先找到大于20万的质数,结果是200003
int main()
{
    for (int i = 200000; ; i++)
    {
        bool flag = true;
        for (int j=2; j*j<=i; j++)
        {
            if(i % j == 0)
            {
                flag = false;
                break;
            }
        }
        if(flag){
            cout << i << endl;
            break;
        }
    }
    return 0;
}

// 开放寻址法的实现
const int N = 200003, null = 0x3f3f3f3f;

int h[N];

// 0x3f3f3f3f 输出 1061109567 ,是10^9级别的
// int a[1], memset(a, 0x3f, 4);
// memset 按照字节赋值,因此我们把 4 个 0011 1111 填充到 32 位的 int 上。但问题是,为什么不是 0x4f 或者 0x5f ?
// 首先 10^9 级别足够大,其次,也是最重要的,0x3f3f3f3f + 0x3f3f3f3f 等于 0x7e7e7e7e , 不会爆int 。
// 在很多算法中,我们需要进行诸如 dist[j] > dist[t] + w[t][j] 之类的判断,
// 如果两个大于 0x3f3f3f3f 的数相加,那么后果不堪设想。因为溢出并不会报错,算法逻辑复杂,我们往往很难定位真正的错误。
// int 对应 0x3f, float 对应 0x4f
// 参考:https://github.com/PiperLiu/ACMOI_Journey

void find(int x)
{
    int k = (x % N + N) % N;  
    while (h[k] != null && h[k] != x)
    {
        k ++;
        if (k == N) k = 0;
    }

    return k;
}

int main()
{
    int n;
    scanf("%d", &n);

    memset(h, 0x3f, sizeof h);  // 将所有“槽”清空,用null表示

    while (n--)
    {
        char op[2];
        int x;
        scanf("%s%d", op, &x);

        int k = find(x);
        if (*op == 'I') h[k] = x;
        else 
        {
            if (h[k] != null) puts("Yes");;
            else puts("No");
        }
    }
    return 0;
}


// 字符串前缀哈希法
// 1. 将字符串看作P进制,然后转化成10进制,再模上较小的值Q
// 2. 不许映射成0,从1开始
// 3. 假设不会发生冲突(即人品很好)
// 4. 经验:P取131或13331,Q取2^64,99.99%的可能不会发生冲突
// 5. L到R的子串的哈希值为:h[R] - h[L-1]*P^(R-L+1)
// 6. 用unsigned long long 表示 Q,即2^64,溢出相当于取模
// 7. 预处理:h(i) = h(i-1)*P + str[i],str[i]是多少都无所谓,只要保证不是0就行


// 给一个字符串,给定两个子串的区间[l1, r1], [l2, r2],判断两个子串是否相等
// O(1)时间
#include <iostream>
using namespace std;
type unsigned long long ULL;
const int N = 100010, P = 131;

int n, m;
char str[N];
ULL h[N], p[N];  // p[k]存放p^k

ULL get(int l, int r)
{
    return h[r] - h[l - r] * p[r - l + 1];
}

int main()
{
    scanf("%d%d%s", &n, &m, str + 1);
    
    p[0] = 1;
    for (int i=1; i<=n; i++)
    {
        p[i] = p[i-1] * P;
        h[i] = h[i-1] * P + std[i];
    }

    while (m--)
    {
        int l1, r1, l2, r2;
        scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
        if(get(l1, r1) == get(l2, r2)) puts("Yes");
        else puts("No");
    }

    return 0;
}


// ----------------STL模板------------------

/*

vector,变长数组,倍增的思想
    size()  返回vector里面元素的个数
    empty() 返回vector是不是空的
    clear() 清空
    front()/back()
    push_back()/pop_back()
    begin()/end()   begin是第一个元素的位置,end是最后一个元素的后一个位置
    []
    支持比较运算

pair<int, int>
    first,第一个元素
    second,第二个元素
    支持比较运算,以first为第一关键字,以second为第二关键字(字典序)

string,字符串,substr(),c_str()
    size()/length()
    empty()
    clear()

queue,队列
    size()
    empty()
    push()  向队尾插入一个元素
    front() 返回队头元素
    back()  返回队尾元素
    pop()   弹出队头元素

priority_queue,优先队列(堆),默认是大根堆
    size()
    empty()
    push()  插入一个元素
    top()   返回堆顶元素
    pop()   弹出堆顶元素
    定义小根堆的方式:priority_queue<int, vector<int>, greater<int>> heap;

stack,栈,
    size()
    empty()
    push()  向栈顶插入一个元素
    top()   返回栈顶元素
    pop()   弹出栈顶元素

deque,双端队列,可以随机访问,加强版的vector,但速度慢几倍
    size()
    empty()
    clear()
    front()
    back()
    push_back()/pop_back()
    push_front()/pop_front
    begin()/end()
    []

set,map,multiset,multimap。基于平衡二叉树(红黑树),动态维护有序序列
    size()
    empty()
    clear()
    begin()/end()   支持++和--操作,返回的是前驱和后继,时间复杂度是是O(logn)

    set/multiset
        insert()    插入一个数
        find()  查找一个数,如果不存在会返回end()迭代器
        count() 返回某一个数的个数
        erase()
            (1)输入是一个数x,删除所有x  时间复杂度O(k + logn)  k是x的个数
            (2)输入一个迭代器,删除这个迭代器
        lower_bound() / upper_bound()
            lower_bound(x)  返回大于等于x的最小的数的迭代器,如果不存在返回end
            upper_bound(x)  返回大于x的最小的数的迭代器
    
    map/multimap
        insert() 插入的是一个pair
        erase() 输入的参数是pair或者迭代器
        find()
        []  时间复杂度是是O(logn)
        lower_bound() / upper_bound()

unordered_set,unordered_map,unordered_multiset,unordered_multimap,基于哈希表实现
    和上面类似,但是增删改查的时间复杂度变成O(1)
    缺点是:不支持lower_bound() / upper_bound(),不支持迭代器的++和--

bitset,压位
    在数组情况下,bool需要一个字节,而bitset则只需要一个位,达到1/8的节省

    bitset<10000> s;
    ~, &, | , ^
    >>, <<  移位
    ==, !=
    []

    count() 返回有多少个1
    any()   判断是否至少有一个1
    none()  判断是否全为0
    set()   将所有位置变成1
    set(k, v)   将第k位变成v
    reset() 将所有位变成0
    flip()  等价于取反~
    flip(k) 将第k位取反


list,用的不多

*/

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <unordered_map>

using namespace std;

int main()
{

    // ------------vector-----------

    vector<int> a(10, 3);  // 定义长度为10的vector,每个值初始化为3,后者可省略
    for (auto x : a) cout << x << endl;

    vector<int> a[10];  // 定义vector数组,有10个vector

    vector<int> a;
    a.size();  // 返回vector里面元素的个数
    a.empty(); // 返回vector是不是空的
    // size和empty是所有STL容器都有的函数,时间复杂度为O(1)

    // 插入
    for (int i=0; i<10; i++) a.push_back(i);

    // 遍历1
    for (int i=0; i<a.size(); i++) cout << a[i] << ' ';
    cout << endl;
    // 遍历2
    for (vector<int>::iterator i = a.begin(); i!=a.end(); i++) cout << *i <<endl;
    cout << endl;
    // 或者
    for (auto i = a.begin(); i!=a.end(); i++) cout << *i <<endl;
    cout << endl;
    // 遍历3(又短又快)
    for (auto x : a) cout << x << ' ';
    cout << endl;

    // 支持字典序比较
    vector<int> a(4, 3), b(3, 4);
    if (a < b) puts("a < b");


    // ------------pair-----------

    pair<int, string> p;

    // 初始化方式
    p = make_pair(10, "yxc");
    p = {20, "abc"};

    // 如果是存储三个不同的属性,可以
    pair<int, pair<int, int>> p;



    // ------------string-----------

    string a = "yxc";

    a += "def";
    a += 'c';
    cout << a << endl;

    cout << a.substr(1, 2) << endl;  // 参1表示子串起点坐标,参2表示子串长度(溢出源串长度没关系,也可省略)

    printf("%s\n", a.c_str());  // 用printf的话,c_str()返回的是字符的起始位置


    // ------------queue-----------

    queue<int> q;

    // 没有clear函数怎么办
    q = queue<int>();


    // ------------priority_queue-----------
    // 需要#include <queue>

    priority_queue<int> heap;

    // 没有clear函数

    // 想要构造小根堆怎么办
    // 法1:直接插入负数(值的相反数)
    heap.push(-x);
    // 法2:直接定义小根堆
    priority_queue<int, vector<int>, greater<int>> heap;  // 这样就是小根堆,需要#include <vector>



    // ------------deque-----------
    // 需要#include <deque>



    // ------------set和multiset-----------
    // 需要#include <set>

    set<int> S;  // 没有重复元素
    multiset<int> MS;  // 可以有重复元素


    // ------------map-----------
    // 需要#include <map>

    map<string, int> a;
    a["yxc"] = 1;
    cout << a["yxc"] << endl;  // 可以像数组一样使用!


    // ------------unordered_map-----------
    // 需要#include <unordered_map>

    unordered_map<string, int> a;
    unordered_multimap<string, int> a;

    // ------------bitset-----------
    bitset<10000> s;  // 尖括号放的是个数
   

    return 0;
}



// over
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值