Memory Limit Exceeded(内存超限)
出现超内存时我们需要对自己的程序的空间复杂度进行优化,此处的空间复杂度是与时间复杂度相对应的。
空间复杂度:
空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度,记做S(n)=O(f(n))。比如直接插入排序的时间复杂度是O(n^2),空间复杂度是O(1) 。而一般的递归算法就要有O(n)的空间复杂度了,因为每次递归都要存储返回信息。一个算法的优劣主要从算法的执行时间和所需要占用的存储空间两个方面衡量。
类似于 [1] 时间复杂度的讨论,它也是问题规模n的函数。
一个算法在计算机存储器上所占用的存储空间,包括存储算法本身所占用的存储空间,算法的输入输出数据所占用的存储空间和算法在运行过程中临时占用的存储空间这三个方面。
存储算法本身所占用的存储空间:与算法书写的长短成正比,要压缩这方面的存储空间,就必须编写出较短的算法。
算法的输入输出数据所占用的存储空间:是由要解决的问题(问题规模)决定的,是通过参数表由调用函数传递而来的,它不随本算法的不同而改变。
算法在运行过程中临时占用的存储空间:随算法的不同而异。 (来自百度百科)
分析空间复杂度:
算法的空间复杂度一般也以数量级的形式给出。如当一个算法的空间复杂度为一个常量,即不随被处理数据量n的大小而改变时,可表示为O(1);当一个算法的空间复杂度与以2为底的n的对数成正比时,可表示为O(log2n);当一个算法的空间复杂度与n成线性比例关系时,可表示为O(n).若形参为数组,则只需要为它分配一个存储由实参传送来的一个地址指针的空间,即一个机器字长空间;若形参为引用方式,则也只需要为其分配存储一个地址的空间,用它来存储对应实参变量的地址,以便由系统自动引用实参变量。 (来自百度百科)
避免的方法:
只能是跟据题目所给出的数据范围,看一看数组开辟的能不能再小一些,或者更改算法以使用更小的内存。
其它莫名导致MLE的题:
1. 做字典树,AC自动机
把存树结点的数组,在init()初始化函数中一次性清零。MLE。。。
void init() //初始化
{
while(!qu.empty())
qu.pop();
mem(ne, 0); //所用数组一次性清零
mem(fail,0);
mem(vis,0);
mem(book,0);
tot=1;
}
void Insert(char *str,int y) //插入字符串
{
int ls=strlen(str);
int rt=0;
for(int i=0; i<ls; i++)
{
int x=str[i]; //把字符串的字符存入字典树
if(!ne[rt][x])
ne[rt][x]=tot++; //若这一字符没有在这一分支 ,节点数+1;
rt=ne[rt][x];
}
vis[rt]=y+1;
// printf("stateT_cnt==%d\n",stateT[rt].cnt);
}
要在建树的时候一个一个清零。。。 就是要保证只清零了要用的点; AC
void init() //初始化
{
while(!qu.empty())
qu.pop();
mem(ne[0], 0); //
fail[0]=-1;
tot=1;
}
void Insert(char *str,int y) //插入字符串
{
int ls=strlen(str);
int rt=0;
for(int i=0; i<ls; i++)
{
int x=str[i]; //把字符串的字符存入字典树
if(!ne[rt][x])
{
mem(ne[tot],0); //建树时清零,保证要用的数据点清零
fail[tot]=-1;
ne[rt][x]=tot++; //若这一字符没有在这一分支 ,节点数+1;
}
rt=ne[rt][x];
}
vis[rt]=y;
// printf("stateT_cnt==%d\n",stateT[rt].cnt);
}
2. 数学题 (Smith Numbers)
vector<int>ve; 在get_s函数里可以调用gt_n函数; 没调用get_n函数直接在get_s函数又写一遍,结果MLE
ll get_n(ll x)
{
ll ans=0;
while(x)
{
ans += x%10;
x/=10;
}
return ans;
}
ll get_s(ll x)
{
ll ans=0;
prime_decompose(x);
for(ll i=0;i<ve.size();i++)
{
// printf("ve%d ",ve[i]);
while(ve[i])
{
ans += ve[i]%10;
ve[i] /= 10;
}
}
return ans;
}
调用了的,AC
ll get_n(ll x)
{
ll ans=0;
while(x)
{
ans += x%10;
x/=10;
}
return ans;
}
ll get_s(ll x)
{
ll ans=0;
prime_decompose(x);
for(ll i=0;i<ve.size();i++)
{
ans+=get_n((ll)ve[i]); //直接调用
}
return ans;
}