AcWing with LeetCode

算法目录

      • 1.基础算法
        • 1.1 二分算法
        • 1.2 双指针算法
        • 1.3 前缀和与差分
        • 1.4 区间和并
        • 1.5 离散化
        • 1.6 位运算
        • 1.7 高精度加减乘除
      • 2.数据结构
        • 2.1 单链表
        • 2.2 双链表
        • 2.3 模拟栈
        • 2.4 模拟队列
        • 2.5 单调栈

1.基础算法

1.1 二分算法

算法模板:

bool check(int x) {/* ... */} // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

作者:yxc
链接:https://www.acwing.com/blog/content/277/
来源:AcWing

主要需要注意mid的定义时l+r>>1还是l+r+1>>1,记忆方法是当mid赋值给l时用l+r+1>>1,而当mid赋值给r时用l+r>>1。而mid赋值给l还是r看找的是一串相同数的左端点还是右端点。

  1. AcWing 789. 数的范围 *****

1.2 双指针算法

算法模板:

for (int i = 0, j = 0; i < n; i ++ )
{
    while (j < i && check(i, j)) j ++ ;

    // 具体问题的逻辑
}
常见问题分类:
    (1) 对于一个序列,用两个指针维护一段区间
    (2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作

一般for循环套一个while循环,时间复杂度是O(n+n)

  1. AcWing 799. 最长连续不重复子序列 *****
  2. AcWing 800. 数组元素的目标和 *****

1.3 前缀和与差分

算法模板:

一维前缀和

S[i] = a[1] + a[2] + ... a[i]
a[l] + ... + a[r] = S[r] - S[l - 1]

二维前缀和

S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]

一维差分

有a1,a2,a3....
构造b1,b2,b3...使得a1=b1,a2=b1+b2....
如此则称b数组是a数组的差分数组
给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c

二维差分

给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c
S[x2 + 1, y1] -= c
S[x1, y2 + 1] -= c
S[x2 + 1, y2 + 1] += c
  1. AcWing 795. 前缀和 ****
  2. AcWing 796. 子矩阵的和 ****
  3. AcWing 797. 差分*****
  4. AcWing 798. 差分矩阵 *****

1.4 区间和并

算法模板:

// 将所有存在交集的区间合并
void merge(vector<PII> &segs)
{
    vector<PII> res;

    sort(segs.begin(), segs.end());

    int st = -2e9, ed = -2e9;
    for (auto seg : segs)
        if (ed < seg.first)
        {
            if (st != -2e9) res.push_back({st, ed});
            st = seg.first, ed = seg.second;
        }
        else ed = max(ed, seg.second);

    if (st != -2e9) res.push_back({st, ed});

    segs = res;
}

作者:yxc
链接:https://www.acwing.com/blog/content/277/
来源:AcWing
  1. AcWing 803. 区间合并 *****

1.5 离散化

算法模板:

vector<int> alls; // 存储所有待离散化的值
sort(alls.begin(), alls.end()); // 将所有值排序
alls.erase(unique(alls.begin(), alls.end()), alls.end());   // 去掉重复元素

// 二分求出x对应的离散化的值
int find(int x) // 找到第一个大于等于x的位置
{
    int l = 0, r = alls.size() - 1;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (alls[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return r + 1; // 映射到1, 2, ...n
}

作者:yxc
链接:https://www.acwing.com/blog/content/277/
来源:AcWing
  1. AcWing 802. 区间和 ***

1.6 位运算

算法模板:

求n的第k位数字: n >> k & 1
返回n的最后一位1lowbit(n) = n & -n
  1. AcWing 801. 二进制中1的个数 ***

1.7 高精度加减乘除

2.数据结构

2.1 单链表

//静态链表
//head表示头结点下标
//e[i]表示结点i的值
//ne[i]代表结点i的next指针是多少
//idx存储当前用到了哪个店
int head, e[N], ne[N];

//初始化
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()
{
	ne[k] = ne[ne[k]]
}


1.AcWing 826. 单链表 ***

2.2 双链表

算法模板:

// 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];
}

作者:yxc
链接:https://www.acwing.com/blog/content/404/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1.AcWing 827. 双链表 ***

2.3 模拟栈

算法模板:

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

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

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

// 栈顶的值
stk[tt];

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

}

1.AcWing 828. 模拟栈 ***

2.4 模拟队列

算法模板:
1.普通队列

// hh 表示队头,tt表示队尾
int q[N], hh = 0, tt = -1;

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

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

// 队头的值
q[hh];

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

}

2.循环队列

// 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)
{

}

1.AcWing 829. 模拟队列 ***
2.

2.5 单调栈

算法模板:

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

1.AcWing 830. 单调栈 *****
2.P5788 【模板】单调栈 *****

你可能感兴趣的:(leetcode,acwing.算法基础课,leetcode,算法,c++)