数据结构——数组的妙用

分块算法(优雅的暴力)

1)分块算法一般将一列数划分为 根号n,同时用一个数组来记录每一个元素的归属块。后续处理都是尽量按照组为单位进行处理,进而节约时间开销。

下面只是展示初始化代码,区间查询和区间修改代码参见洛谷P3372线段树(分块)题目代码

void _init(int n){//先对分块进行初始化操作
    int q = sqrt(n);//q个分组
    for(int i = 1; i <= q; i++){//确定每一组的起始元素和结尾元素
        st[i] = n/q * (i-1) + 1;
        ed[i] = n/q * i;
    }
    ed[q] = n;//将最后一点纳入到最后一块中
    //确定每一组的大小
    for(int i = 1; i <= q; i++)
        size[i] = ed[i] - st[i] + 1;
    //确定每个元素的归属组
    for(int i = 1; i <= q; i++)
    for(int j = st[i]; j <= ed[i]; j++)
        bel[j] = i;//第j号元素属于第i组
    //保存每一个块的和在数组sum中
    for(int i = 1; i <= q; i++)
    for(int j = st[i]; j <= ed[i]; j++)
        sum[i] += a[j];
}

ST表(稀疏表)

1)ST表(Sparse Table,稀疏表)是一种简单的数据结构,主要用来解决RMQ(Range Maximum/Minimum Query,区间最大/最小值查询)问题。它主要应用倍增的思想,可以实现 [公式] 预处理、 [公式] 查询。

所谓RMQ问题,以最大值为例,是假如有一个数列 [公式] ,给你一个区间 [公式] ,要求 [公式] 。

ST表使用一个二维数组f,对于范围内的所有f[a][b],先算出并存储 [公式] (本文中的区间都是离散意义下的,只包含整数,所以此区间也可以写成[公式] ),这称为预处理。查询时,再利用这些子区间算出待求区间的最大值。

参考博客:https://zhuanlan.zhihu.com/p/105439034

2)代码:

int f[MAXN][21]; // 第二维的大小根据数据范围决定,不小于log(MAXN)
for (int i = 1; i <= n; ++i)
    f[i][0] = read(); // 读入数据
for (int i = 1; i <= 20; ++i)
    for (int j = 1; j + (1 << i) - 1 <= n; ++j)
        f[j][i] = max(f[j][i - 1], f[j + (1 << (i - 1))][i - 1]);

查询时可以利用倍增的思想进行处理,同时记得初始化_log2数组(log2的取下整数),节约算法时间开销。代码如下

//查询[l, r]上的最值
for(int i = 2; i <= n; i++) _log2[i] = _log[i/2] + 1;
int k = _log[r-l+1];//是不是感觉很简单,对!就是这么简单!
int ans = max(f[l][k], f[r-(1<<k)+1][k]);

请添加图片描述
3)用二维数组以及动态规划的思想,保存数组中的每个独立区间的最大值

链式前向星存储图(树)

1)本质就是用静态数组来模拟表示链表,思想就是邻接表的思想。

关键代码:(视频参考

变量解释

  • to :该条有向边的终点结点值
  • w :该有向边的权值
  • next:与该有向边同起点的邻接有向边的下标
  • tot:Edge内存池中还没被使用的下一个位置指示器(方便后续插入边的操作)
  • Head:每个节点的第一个临界点(下面图中的左边第一列)
struct E{
	int to, w, next;
}Edge[maxn];
int tot, Head[maxn];

在这里插入图片描述
2)插入边——头插法

inline void AddEdge(int u, int v, int w){
	//表示需要将一条从u到v的权值为w的有向边插入到Edge数组中
	Edge[tot].to = v;
	Edge[tot].w = w;
	//上面先初始化tot的内存空间,下面两行进行链接处理
	Edge[tot].next = Head[u];
	Head[u] = tot++;//头插法
}

3)补充:一般情况下还是可以采用邻接表的方式进行存储。在实际实现中一般使用c++中的vector数组进行表示

#include<vector>
using namespace std;
struct E{
	int to, w;
}Edge;
vector<Edge> G[maxn];

Z字搜索(特殊性质的矩阵搜索元素)

在这里插入图片描述

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        //考虑到矩阵中数字的特殊性,应该是可以想到这样处理的!!!
        //Z字查找(扩展思维)
        //更优化的,还可以用二分查找。
        int m = matrix.size(), n = matrix[0].size();
        int x = 0, y = n - 1;
        while (x < m && y >= 0) {
            if (matrix[x][y] == target) {
                return true;
            }
            if (matrix[x][y] > target) {
                --y;
            }
            else {
                ++x;
            }
        }
        return false;
    }
};

一种非常好用的以空格进行分割字符串的方式

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

int main() {
	istringstream str(" this is a    text ");
	string out;
	// 通过使用字符串输出流去滤掉字符串中多余的空格!
	while(str >> out) {
		cout << out << endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lingwu_hb

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值