• UVA


    /*
      1. Home键的作用是将光标定位到文首,End键的作用是将光标定位到文尾
      
      2. 在数组中频繁移动(尤其插入和删除)元素比较低效,如果可能尽量使用链表
      
      3. 虽然一般讲链表会讲到指针,但链表实现方式,并非一定需要指针,例如此题
    */
    
    /*
    
      ------------------心路历程分割线,可以直接跳过------------------
      还是第一次接触这种,不用指针来表示链表的表示方法,一开始想了很久很久,甚至用了许多笨方法
      
      比如自己举出几个例子,对于每个位置,分别列出i 对应的 next[i] cur last 的数据变化情况...
      
      但后来用excel举出一个例子,一个个填充对应数据时,却发现自己越写越乱,每次到最后,总是觉得前面好像哪里弄错了,但是一步一步后推回去找错,又比从头开始麻烦,于是又清空excel,一个个列出对应情况的3个数据,并找出它们的规律和变化关系
      
      这么死板地套了很久,套不出来就先去吃饭,路上走着走着,突然想到了 cur 和 last的实际意义,以及next[i]本身,和next[i]的每次更新,其实都是有规律可循的,于是赶紧吃个饭打开电脑记下来思路,免得待会又不明白了 T^T
      ------------------心路历程分割线,可以直接跳过------------------
      
      注意:!!!
      对我的代码而言,数组下标从1开始,因为输入时就是以s[1]作为起点的,毕竟是 scanf("%s", s + 1); 这样做的目的是---前面的s[0]可以单独保留,作为“头节点”,这样在将[]里的信息运用“头插法”插入时,表示就会比较方便了
      cur的含义:当前的序号,也就是循环到下一个位置时,下一个位置的前驱,在数组s中的下标(看上去有点绕,但不用指针的话,必然得牺牲一点通俗性的,多看几次还是能明白的),例如对 abc[test]def,当循环到 a时,i为1  cur = i = 1, cur既是当前走到的位置,又是走到的下一个位置,也就是b时,b的前驱字母a,在s中的下标
      
      last:
      注意在没遇到[ 或者是 ]之前,last 是和 cur同步移动的,但是遇到 [以后,last就一直停留在 [ 的前一个位置的对应下标。举个例子
      ...A[...]B...  假设A和B之间的,是这个串中遇到的第一个中括号对,在A之前,last和cur一直同步移动,且都是当时的i,遇到[之后,last就一直停留在A的位置的下标了
      可是保留A的下标又有什么用呢?
      当然有用啦!在遇到]以后,我们要更新]的下一个位置的前驱的下标(也就是B的下标,也就是循环到]时,当时的cur),所以遇到]时,所做的处理就是cur变为last了,毕竟B当然是接到A后面的,因为两个中括号只是代表 Home和End键被无意按下,并不出现在真实的文本中,而[]中括号对里面的内容,都被头插到头节点的后面了
      
      其实从这里也就可以理解,为什么遇到[时,将cur赋值0了,因为[后面的文本就是要移动到文本最前端的,当时的cur代表[的下一个元素的前驱(头结点)在s数组中的下表(0),自然就是 cur = 0的处理了
      
      至于既不是[也不是]的普通内容,那就是每次遇到一个新位置,将其前一个位置的后继next[i]接到自己的后继上(next[i] = next[cur]),再将自己作为前一个位置的后继(next[cur] = i),再为其下一个位置预备好位置前驱,(即移动光标,使cur = i,含义是,循环走到下一个位置时,其前驱位置就是当前位置i了<当然,除非被中括号破坏了>),以及last是为了停在[的前一个位置,所以在此之前,除了出现[和]的情况以外,last总是和cur同步移动,总是同一个值
      
      总结:
      一道比较值得回味的题,如果深入想想,多举几个例子,比如多对括号以]结束整个串,多对中括号,以普通字母结束整个串,等等
      
      以及,这个不用指针来表示链表的方式,真的很神奇啊!而且也很值得琢磨研究,越想越觉得有意思,越想越觉得自己好像有些小细节还有些懵懵懂懂,真的很值得重看!!
    */



    #include <cstdio>
    #include <cstring>
    const int maxn = 1e5 + 5;
    int last, cur, next[maxn]; //next[i]存放:i后面接着的数,在s中的下标
    //cur表示光标位置,当前光标位于 s[cur]的右边
    //last表示显示屏的最后一个字符是s[last] 
    char s[maxn];
    
    int main()
    {
    	while (scanf("%s", s + 1) == 1)
    	{
    		memset(next, 0, sizeof(next));
    		int n = strlen(s + 1); //输入保存在s[1], s[2], s[3]......
    		last =  cur = 0;
    		next[0] = 0;
    		
    		for (int i = 1; i <= n; i++)
    		{
    			char ch = s[i];
    			switch(ch)
    			{
    				case '[': cur = 0; break;
    				case ']': cur = last; break;
    				default:
    					next[i] = next[cur]; //将前一个字符的后缀序号,置为当前字符的后缀序号
    					next[cur] = i; //前一个字符的后缀,变为当前元素的序号
    					if (cur == last) last = i; //更新“最后一个字符”的标号
    					cur = i; //移动光标 
    					break;
    			}
    		}
    		
    		for (int i = next[0]; i != 0; i = next[i])
    		printf("%c", s[i]);
    		printf("
    ");
    		
    	}
    	return 0;
     } 

  • 相关阅读:
    一套完整的javascript面试题
    遇到的java.lang.NoClassDefFoundError解决了
    Win7下启动Internet信息服务(IIS)管理器
    我的第一个专业博客
    “用NetBeans打开项目时项目名变成红色”问题解决
    Struts2框架实现计算器功能
    MyEclipse移动包到另一个项目时出现错误:Resource is out of sync with the file system.
    制作Javascript弹出窗口技巧九则
    windows 的鼠标事件(Event)
    Javascript使用cookie
  • 原文地址:https://www.cnblogs.com/mofushaohua/p/7789407.html
Copyright © 2020-2023  润新知