首页 > 编程语言 >基础算法三

基础算法三

时间:2023-02-12 16:14:45浏览次数:45  
标签:idx int tt 基础 hh ++ 算法 节点

单链表

// head存储链表头,e[]存储节点的值,ne[]存储节点的next指针,idx表示当前用到了哪个节点
int head, e[N], ne[N], idx;

// 初始化

void init()
{
    head = -1;
    idx = 0;
}
// 在链表头插入一个数a

void insert(int a)
{
    e[idx] = a, ne[idx] = head, head = idx ++ ;
}
// 将头结点删除,需要保证头结点存在

void remove()
{
    head = ne[head];
}

双链表

// e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点
int e[N], l[N], r[N], idx;

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

// 在节点a的右边插入一个数x
void insert(int a, int x)
{
    e[idx] = x;
    l[idx] = a, r[idx] = r[a];
    l[r[a]] = idx, r[a] = idx ++ ;
}

// 删除节点a
void remove(int a)
{
    l[r[a]] = l[a];
    r[l[a]] = r[a];
}

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

// 向栈顶插入一个数
stk[ ++ tt] = x;

// 从栈顶弹出一个数
tt -- ;

// 栈顶的值
stk[tt];

// 判断栈是否为空
if (tt > 0)
{

}

队列

  1. 普通队列:
    // hh 表示队头,tt表示队尾
    int q[N], hh = 0, tt = -1;

// 向队尾插入一个数
q[ ++ tt] = x;

// 从队头弹出一个数
hh ++ ;

// 队头的值
q[hh];

// 判断队列是否为空
if (hh <= tt)
{

}

循环队列

// hh 表示队头,tt表示队尾的后一个位置
int q[N], hh = 0, tt = 0;

// 向队尾插入一个数
q[tt ++ ] = x;
if (tt == N) tt = 0;

// 从队头弹出一个数
hh ++ ;
if (hh == N) hh = 0;

// 队头的值
q[hh];

// 判断队列是否为空
if (hh != tt)
{

}

单调栈

常见模型:找出每个数左边离它最近的比它大/小的数
int tt = 0;
for (int i = 1; i <= n; i ++ )
{
while (tt && check(stk[tt], i)) tt -- ;
stk[ ++ tt] = i;
}

单调队列

常见模型:找出滑动窗口中的最大值/最小值
int hh = 0, tt = -1;
for (int i = 0; i < n; i ++ )
{
while (hh <= tt && check_out(q[hh])) hh ++ ; // 判断队头是否滑出窗口
while (hh <= tt && check(q[tt], i)) tt -- ;
q[ ++ tt] = i;
}

KMP

求Next数组:

// s[]是模式串,p[]是模板串, n是s的长度,m是p的长度
for (int i = 2, j = 0; i <= m; i ++ )
{
    while (j && p[i] != p[j + 1]) j = ne[j];
    if (p[i] == p[j + 1]) j ++ ;
    ne[i] = j;
}

// 匹配
for (int i = 1, j = 0; i <= n; i ++ )
{
    while (j && s[i] != p[j + 1]) j = ne[j];
    if (s[i] == p[j + 1]) j ++ ;
    if (j == m)
    {
        j = ne[j];
        // 匹配成功后的逻辑
    }
}

Trie树

int son[N][26], cnt[N], idx;
// 0号点既是根节点,又是空节点
// son[][]存储树中每个节点的子节点
// cnt[]存储以每个节点结尾的单词数量

// 插入一个字符串
void insert(char *str)
{
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
        int u = str[i] - 'a';
        if (!son[p][u]) son[p][u] = ++ idx;
        p = son[p][u];
    }
    cnt[p] ++ ;
}

// 查询字符串出现的次数
int query(char *str)
{
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
        int u = str[i] - 'a';
        if (!son[p][u]) return 0;
        p = son[p][u];
    }
    return cnt[p];
}

// h[N]存储堆中的值, h[1]是堆顶,x的左儿子是2x, 右儿子是2x + 1
// ph[k]存储第k个插入的点在堆中的位置
// hp[k]存储堆中下标是k的点是第几个插入的
int h[N], ph[N], hp[N], size;

// 交换两个点,及其映射关系
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] < h[u / 2])
    {
        heap_swap(u, u / 2);
        u >>= 1;
    }
}

// O(n)建堆
for (int i = n / 2; i; i -- ) down(i);

一般哈希

拉链法

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

    // 向哈希表中插入一个数
    void insert(int x)
    {
        int k = (x % N + N) % 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 h[N];

    // 如果x在哈希表中,返回x的下标;如果x不在哈希表中,返回x应该插入的位置
    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;
    }

字符串哈希

核心思想:将字符串看成P进制数,P的经验值是131或13331,取这两个值的冲突概率低
小技巧:取模的数用2^64,这样直接用unsigned long long存储,溢出的结果就是取模的结果

typedef unsigned long long ULL;
ULL h[N], p[N]; // h[k]存储字符串前k个字母的哈希值, p[k]存储 P^k mod 2^64

// 初始化
p[0] = 1;
for (int i = 1; i <= n; i ++ )
{
    h[i] = h[i - 1] * P + str[i];
    p[i] = p[i - 1] * P;
}

// 计算子串 str[l ~ r] 的哈希值
ULL get(int l, int r)
{
    return h[r] - h[l - 1] * p[r - l + 1];
}

标签:idx,int,tt,基础,hh,++,算法,节点
From: https://www.cnblogs.com/zyzzzz/p/17113949.html

相关文章

  • LeetCode回溯算法
    回溯模板1privatevoidbacktrack("原始参数"){2//终止条件(递归必须要有终止条件)3if("终止条件"){4//一些逻辑操作(可有可无,视情况而定)......
  • 6.2RLE算法的机制
       由于半角字母中,1个字符是作为1个字节的数据被保存在文件中的,因此上述文件的大小就是17个字节。我们可以使用方式来压缩。   把文件内容用“数据x重复次数......
  • Linux基础命令-ls显示目录和文件的属性信息
    前言        ls命令是常需要用到的linux命令之一,熟悉其参数的搭配有利于操作上的便利,ls命令可以显示目录和文件的属性,一起来看下展开的属性有哪些。一、ls命令介绍......
  • Linux基础命令-cd切换目录
    前言        cd命令是一个频繁使用到的命令,熟悉其参数的搭配有利于操作上的便利,这个命令用于切换目录,一起了解看看。一、cd命令介绍    cd命令来自于英文词......
  • Linux基础命令-alias设置别名
    前言在前文当中也有多次提到alias这个命令,如果说频繁使用一个很长的命令,就可以把它定义一个别名,往往几十个字符的命令会变成几个字母而已,大大提高了工作效率。一、alias命令......
  • Python----基础知识测试
    一、单选题(每题2分)1、列标识符命名中,符合规范的是()A、1aB、forC、_123D、#_b2、下列标识符中,不是Python支持的数据类型的是()A、charB、intC、floatD、str3、下......
  • 代码随想录算法Day10 | 理论基础 232.用栈实现队列 225. 用队列实现栈
    理论基础栈是先进后出,队列是先进先出。如图所示。232.用栈实现队列题目链接:232.用栈实现队列-力扣(LeetCode)题目请你仅使用两个栈实现先入先出队列。队列应当支......
  • 【数据结构与算法】图论算法(C++实现)
    一些基本概念图一个图\(G=(V,E)\)由顶点集V和边集E组成。每一条边就是一副顶点对\((u,v)\),其中\(u,v\inV\)。顶点u和顶点v邻接当且仅当\((u,v)\inE\)......
  • 代码随想录算法训练营Day08 | 344.反转字符串,541. 反转字符串II, 剑指Offer 05.替换空
     344.反转字符串题目链接:344.反转字符串-力扣(LeetCode)题目编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组s的形式给出。不要给另外的数组分......
  • 【rust】rsut基础:模块的使用一、mod 关键字、mod.rs 文件的含义等
    本文内容这篇文章是实战性质的,也就是说原理部分较少,属于经验总结,rust对于模块的例子太少了。rust特性比较多(悲),本文的内容可能只是一部分,实现方式也不一定是这一种。关于......