今天做到了Tyvj上的初学者题库的Q1031,题目是机器翻译(2),地址是:http://www.tyvj.cn/Open_Problem_Show.aspx?id=1031
题目提示要用到循环队列,不清楚循环队列是什么东西,百度了一下,其百科定义为:
为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。
哦哦,原来也可以用数组来实现,和我想的一样,因为如果用类似链表那样的指向下一位的指针来实现的化,这里的在队列中搜索的速度可能就不尽如人意了。
循环是哪里在循环呢?其实关键就是一条语句而已:front = (front+1)%maxSize;
没错,就是它啦(front是指向队列头的一个下标,也可以逼格高一点,说成指针),一开始,毫无疑问,front为0,当队列满了以后,再往里面加元素的话,概念上要求将第一个元素先出队,然后再让新元素psuh进队!但如果只用一倍内存空间的话,又不采取一些特殊措施的话,每次这样做,就必须将每一个元素往左移动一位,空出最后一个出来,然后再填充进去,这样做是很不理智的。
而百度到的结果,大多是利用了运动的相对性,每个元素都向左移动一位,相当于队列头向右移动一位,所以只需要front++就好了,然后考虑到了自增之后可能超出应有的下标范围,所以就取一下模。
到了这里有人会问,那么新的元素怎么办?哈哈,这就要看队列尾指针(tail)的本领了!是这样的,每次队尾指针也要做与front类似的运算:tail = (tail+1)%maxSize;
然后把新元素放到这里,如此一来,再数组连续的内存空间上看,就变成了队尾元素的右边是队头元素!当front走到了数组的末端,再进一步的话,就变成了0,与此同时,tail也就变到了数组的末端位置,下面图示一下:
这样子想必是极好的,我自己再做题的时候想不到而已,,,刚才吃完饭回来想写博客的时候才想出来的,网上大多都写成了模板,如果有兴趣可以自己百度一下,我就不贴实现的代码了,下面是我自己关于这道题的解法,老规矩,先贴代码,再解释:
#include <stdio.h>
#include <set>
using namespace std;
int loop[2000001];
int beg, n, m;
set<int> haha;
/*
void show()
{
for(int i=beg; i<m+beg; ++i)
printf("%d ",loop[i]);
}
*/
int main()
{
int count, temp, pos;
count = pos = 0;
scanf("%d%d",&m,&n);
for(int i=0; i<n; ++i)
{
scanf("%d",&temp);
if(haha.find(temp) == haha.end())
{
if(pos >= m)
{
haha.erase(loop[beg]);
++beg;
}
haha.insert(temp);
loop[pos++] = temp;
++count;
}
//show();
//printf("%d\n",count);
}
printf("%d\n",count);
return 0;
}
先做几点解释:
1)注释部分是调试时候用到的,很方便又直观的打印自己想要检测的数据,个人觉得比用vs去监控好多了,随心所欲!又不用那么麻烦(因为小程序确实没必要那么高级)
2)由于这道题的输入很多,所以建议用scanf!
好了,其实这里我不止用了一倍空间,而是用了题目里的数据范围的极限!最多就是这样,所以我没用到循环这个概念,而是“伪循环”,说好听点,就是模拟了循环队列:
直线移动front和tail指针,而不用取模操作,这样看起来更直观一些,更像队列,下面图示一下:
(红色下划线部分为队列中的元素,可以看到,其他元素实际上没有被删除,只是对于队列不可见,相当于出队了!)
其实取不取模,本质都是头尾指针的移动,然后利用运动的相对性,实现循环。
然后我就兴高采烈的提交了,发现超时了!!!最多的有3350ms,一个测试案例就3秒多了,果然是线性查找元素有问题呀!
想了一下,就用了一个辅助的集合实例haha来辅助搜索的实现(这道题要求搜索队列中的元素,如果不存在,就入队,如果已存在,不做任何操作)。
毫无疑问,用标准库的set来查找的速度是极快的!提交后就ac了,最长用时720ms,整整缩小到了1/5。吊炸天的标准库,虽然空间用多了点,不过也好啦啦!哈哈!
最后,发一句感慨,写博客真的能够帮助自己整理思路,总结收获!就像这一次,我当时只想到了用足够多的空间来模拟,但是在写的时候却能够想到了更好的方法——取模!
加油!还是那句话,不够强大,都不好意思说自己是中大人!希望自己有一天能够自豪地跟别人说——我是中山大学的学生!