临时抱佛脚之算法题模板

本文介绍了几种常见的IT技术,包括二分查找、深度优先搜索(DFS)、广度优先搜索(BFS)、动态规划、基本数据结构、优化方法(如前缀和、并查集、滑动窗口等)、位运算以及数论中的GCD和LCM,以及如何判断素数和求质因子的方法。
摘要由CSDN通过智能技术生成

1. 二分查找

int check(int m);
int l = 1, r = n;
while (l <= r)
{
        int mid = (r + l)/2;
        if (check(mid) > k)
        {
            r=mid-1;
        }
        else
        {
            l=mid+1;
        }
}
// 在一维区间上搜索时可以采用, 如 i in (1, n), i in 整数

2. DFS

int a[N], b[M], K, ans = 0;
bool found, bad, good, vis[N][M];
const int mov[2][4] = {1, 0, -1, 0, 0, 1, 0, -1};

void dfs(int x, int y, int k)
{
    if (x < 1 || y < 1 || x > n || y > m}
        return;
    if (bad || found)
        return;
    // 该点有效, 此处填写代码计算当前点
    {    }
    
    // 接下来决定停止搜索树还是继续搜索
    if (x == n && y == m && good)
    {
        found = true;
        ans = k;
        return;
    }
    for (int i = 0; i < 4; i++)
    {
        int xx = x + mv[0][i], y=y+mv[1][i];
        if (vis[xx][yy])
            continue;
        // 保存现场
        a[xx]--, b[yy]--, K--, vis[xx][yy]=true;
        dfs(xx, yy, k+1);
        a[xx]++, b[yy]++, K++, vis[xx][yy]=false;
        // 假装无事发生
    }
}

int main()
{
    found = false, vis[1][1]=true;
    dfs(1,1,1)    // 从(1,1)开始搜索, 路径长1
}

3. BFS

# include <queue>
typedef pair<int, int> PII;
queue<PII> q;
const int mov[2][4] = {1,0,-1,0,0,1,0,-1};
int n, m, ans;
bool found, good, bad, vis[N][M];
void bfs(int x, int y)
{
    while(!q.empty())
    {
        auto t = q.front();
        q.pop();
        
        for (int i = 0; i < 4; i++)
        {
            int xx = x + mov[0][i], yy=y+mov[1][i];
            if (xx < 1 || yy < 1 || x > n || y > m)
                continue;
            if (bad || vis[xx][yy])
                continue;
            // 当前点有效, 对当前点进行计算
            {    }

            vis[xx][yy] = true;
            q.push({xx,yy});
            // 接着走
        }
    }
}

4. 动态规划

#include <algorithm>
int dp[N][M], ans, dx;
// 初始化, 如
dp[1][1] = 1;
for (int i = 1; i <= len1; i++)
{
    for (int j = 1; j <= len2; j++)
    {
        // 转移方程, 如
        dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
        // 自顶向下的写法, 也可以写成递推:
        // dp[i+dx][j] = dp[i][j+dx] = dp[i][j];
    }
}
// 处理可以利用先前状态的问题, 减少重复搜索, 多项式复杂度

5. 简单数据结构

#include <cmath>
// 数组存储完全二叉树
int tree[N];
for (int i = 1; i <= n; i++)
{
    cin >> tree[i];
    int depth = ceil(log(i+1)/log(2));
}

void postOrder(int root)    // root表示序号, 简单的树其实就是给数组加上了父子信息
{
    if (tree[2*p])
        postOrder(2*p)        // 左
    if (tree[2*p+1])
        postOrder(2*p+1)      // 右
    cout << tree[p];
}
# include <vector> 
// 图的表示(邻接矩阵)
int n, m;
const int maxM;
vector <int> g[maxM];

for (int i = 1; i <= m; i++)    // m条边
{
    int x, y;
    cin >> x >> y;
    g[x].push_back(y);
    g[y].push_back(x);
}

6. 优化方法

6.1 前缀和

int s[N] = {0};

for (int i = 1; i <= n; i++)
{
    cin >> s[i];
    s[i] = s[i-1];
}
// s(i, j) = s[j] - s[i], 避免O(n2)双循环

6.2 并查集(dsu on tree)

int parent[N], items[N];
for (int i = 0; i < N; i++)
{
    parent[i] = i;    // 初始化, 祖宗 (目标)是自己, 自己可用
}

int find(int x)
{
    if (parent[x] != x)                 // 祖宗不是自身, 该点不可用, 向上寻找
        parent[x] = find(parent[x]);    // 每次查找进行路径压缩, 减少树的高度
    return parent[x];
}
int main()
{
    //
    for (int it : items)
    {
        it = find(it);
        // 更新祖宗(目标)节点, 如
        parent[it] = it + 1;
    }
}
// 复杂度近乎O(1), 因为大部分时候树的高度差是1

6.3 滑动窗口(同向双指针)

#include <algorithm>
int arr[N];
long s = 0, target, ans = N;
for (int l = 1, r = 1; r <= n; r++)     
{
    // 对子序列[l,r]操作, 以求和为例
    s += arr[r];
    while (s >= target)    // 收缩左边界, 而后延长右边界
    {
        ans = min(ans, r - l + 1);
    // 收缩左边界
        s -= arr[l++];
    }
    // 右动, 然后左动, 左边死了再动右边
}

// 另一种写法, 两个指针先都找好位置了再统计, 有点像前缀和
// 左右一起准备好, 然后找下一段
// 这种写法关注元素, 上一种更关注子序列整体
int t[M];
for (int i = 1, l = 1, r = 1; i <= m; i++)
{
    while (l <= n && arr[l] < t[i])
        l++;
    while (r <= n && arr[r] <= t[i] + target)
        r++;
    ans += r-l;
}
// r走一遍, l走一遍, 复杂度O(n2)变成O(2n)

6.4 对向双指针

#include <vector>
vector<pair<int, int>> ans;
int arr[N], Found = 0, target;
// 可能需要有序数组
// sort(arr, arr+n);
int l = 1, r = n;
while(!Found)
{
    // 计算左右两点, 如
    int s = arr[l] + arr[r];
    if (target)
        ans.push_back({l,r});
    else
        s > target ? r-- : l++;    // 根据条件移动右指针或左指针
}
// 双指针利用有序性, O(n2)变 O(n)

7. 位运算

// 按位 &与, |或, ^亦或, ~取反
int n, x, k;
x << n;         // 左移n位
x >> n;         // 右移n位
                // 逻辑右移
x|1;            // 最后一位变为1
(x|1)-1;        // 最后一位变为0
x^1;            // 最后一位取反

x|(1<<(k-1))    // 右数第k位变1
x& ~(1<<(k-1))  // 右数第k位变0
x^(1<<(k-1))    // 右数第k位取反
x&(1<<k -1)     // 取末k位数字
x>>(k-1) &1     // 取右数第k位数字

x&(x+1)         // 把右起连续的1变0, 前面的不变, 如010111->010000
x|(x+1)         // 把右起第一个0变1

void swap(int &a, int &b)
{
    a ^= b;
    b ^= a;
    a ^= b;
}
int change(int a)
{
    return ~a +1;
}
// 统计二进制1个数
int count(int x){
    int cnt = 0;
    while(x){
        cnt += x & 1;
        x = x >> 1;
    }
    return cnt;
}

8. 数论

8.1 gcd&lcm

int gcd(int a, int b)
{
    while (b != 0)
    {
        int t = b;
        b = a % b;
        a = temp;
    }
    return a;
}
int lcm (int a, int b)
{
    return (a*b) / gcd(a, b);
}

8.2 筛法判断素数

#include <vector>
vector <int> pms;
bool isPrime[N];
fill(isPrime + 1, isPrime + N + 1, true);
void isPm()
{
    for (int i = 2; i*i <=n; i++)
    {
        if (isPrime[i])
        {
            pms.push_back(i);
            for (int j = i*i; j <=n; j+=i)
                isPrime[j] = false;
        }
    }
}

8.3 求质因子

typedef vector<pair<int, int>> vpii;
vpii divide(int n)
{
    vpii res;
    for (int i= 2; i*i <= n; i++)
    {
        if (n%i==0)
        {
            int j = 0;
            while(n%i==0)
            {
                n/=i;
                j++;
            }
            res.push_back({i,j});
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值