Google中国2014校园招聘笔试Round B China New Grad Test Problem E. Ignore all my comments

Problem

Good programmers write fabulous comments. Igor is a programmer and he likes the old C-style comments in /* ... */ blocks. For him, it would be ideal if he could use this style as a uniform comment format for all programming languages or even documents, for example Python, Haskell or HTML/XML documents.

Making this happen doesn't seem too difficult to Igor. What he will need is a comment pre-processor that removes all the comment blocks in /*, followed by comment text, and by another */. Then the processed text can be handed over to the compiler/document renderer to which it belongs—whatever it is.

Igor's pre-processor isn't quite that simple, though. Here are some cool things it does:

  • The comments the pre-processor reads can be nested the same way brackets are nested in most programming languages. It's possible to have comments inside comments. For example, the following code block has an outer level of comments that should be removed by the comment pre-processor. The block contains two inner comments.
    printf("Hello /* a comment /* a comment inside comment */ 
            inside /* another comment inside comment */ 
            string */ world");
    
    After the pre-process step, it becomes:
    printf("Hello  world");
    
  • Igor recognizes comments can appear anywhere in the text, including inside a string"/*...*/", a constant number 12/*...*/34 or even in a character escape \/*...*/n

    Or more formally:

    text:
      text-piece
      text-piece remaining-text
    text-piece:
      char-sequence-without-/*
      empty-string
    remaining-text:
      comment-block text
    
    comment-block:
      /* comment-content */
    comment-content:
      comment-piece
      comment-piece remaining-comment
    comment-piece:
      char-sequence-without-/*-or-*/
      empty-string
    remaining-comment:
      comment-block comment-content
    
    char:
      letters
      digits
      punctuations
      whitespaces
    

    Our pre-processor, given a text, removes all comment-block instances as specified.

    Notes

  • Igor only needs to remove the comment in one pass. He doesn't remove additional comment blocks created as a result of the removal of any comment block. For example:
    //*no recursion*/* file header */
    should generate:
    /* file header */
  • The * character in any /* or /*cannot be re-used in another /* or */. For example the following does NOT form a proper comment block
    /*/
    

    Input

    A text document with comment blocks in /* and */. The input file is valid. It follows the specification of text in the problem statement. The input file always terminates with a newline symbol.

    Output

    We only have one test case for this problem. First we need to output the following line.

    Case #1:
    
    Then, print the document with all comments removed, in the way specified in the problem statements. Don't remove any spaces or empty lines outside comments.

    Limits

    The input program contains only:

  • Letters: a-z, A-Z,
  • Digits: 0-9
  • Punctuation: ~ ! @ # % ^ & * ( ) - + = : ; " ' < > , . ? | / \ { } [ ] _
  • Whitespace characters: space, newline

    Small dataset

    The small input contains a program of less than 2k bytes.

    Large dataset

    The large input contains a program of less than 100k bytes.

    Sample


    Input 
     
     
    //*no recursion*/* file header
    ***********/************
    * Sample input program *
    **********/*************
    */
    int spawn_workers(int worker_count) {
      /* The block below is supposed to spawn 100 workers.
         But it creates many more.
         Commented until I figure out why.
      for (int i = 0; i < worker_count; ++i) {
        if(!fork()) {
          /* This is the worker. Start working. */
          do_work();
        }
      }
      */
      return 0; /* successfully spawned 100 workers */
    }
    
    int main() {
      printf("Hello /*a comment inside string*/ world");
      int worker_count = 0/*octal number*/144;
      if (spawn_workers(worker_count) != 0) {
        exit(-1);
      }
      return 0;
    }
    
    


    Output 
     
    Case #1:
    /* file header
    ************************
    */
    int spawn_workers(int worker_count) {
      
      return 0; 
    }
    
    int main() {
      printf("Hello  world");
      int worker_count = 0144;
      if (spawn_workers(worker_count) != 0) {
        exit(-1);
      }
      return 0;
    }
    

    类型:字符串  难度:2

    题意:给一段文本(多行),文本中包含/* ... */的注释段,要求把注释内容去掉,输出结果。但是这个注释和一般的略有不同,有两个特点:

    (1)能够嵌套,类似括号的用法

    (2)可能出现在文本任何地方,如"/*...*/",12/*...*/34

    还有两点要注意的是:
    (1)去掉注释文本后形成的/*或*/不算注释,如

    //*no recursion*/* file header */

    去掉注释后为:

    /* file header */

    (2)注释中的*只能被一个/*或*/所用,如/*/不是合法的注释

     

    分析:题目本身看似难度不大,但是通过率很低,归根结底还是细节问题较多(其实总体看google的笔试,都不是需要很难的算法才能解出的,考察的都是细节的把握)

    基本思路:

    (1)遍历文本,用一个栈nest存储/*的位置,遇到/*则入栈,遇到*/则将nest顶端的/*出栈

    (2)用另一个栈del记录互不包含重叠的最外层/*..*/对的位置,即当nest出栈后,栈为空,证明最后出栈的是最外层的/*...*/,将它们的位置入del栈

    (3)遍历结束后,del内位置对依次出栈,删除对应范围的文本(先删后边的保证前面的位置下标不变,这也是用栈del的原因)

    两个细节:

    (1)遍历时先找'/',再找前一个是不是'*',即找*/,因为要先和前面的/*匹配。再找后一个是不是'*'

    (2)注意标记用过的'*',防止/*/情况中'*'被前一个'/'用完又被后一个'/'用。

     

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<vector>
    using namespace std;
    
    typedef struct
    {
    	int l,r;
    }range;
    
    int main()
    {
    	freopen("E-large-practice.in","r",stdin);
    	freopen("E-large-practice.out","w",stdout);
    	
    	string tmp,text;
    	while(getline(cin,tmp,'\n')) 
    	{
    		text+=tmp;
    		text+="\n";
    	}
    	
    	vector<int> nest;
    	vector<range> del;
    	nest.clear();
    	del.clear();
    	
    	int pos = -1;
    	for(int i=0; i<text.size(); i++)
    	{
    		if(text[i]=='/')
    		{
    			if(i>0 && text[i-1]=='*' && !nest.empty() && pos!=(i-1))
    			{
    				int left = nest.back();
    				nest.pop_back();
    				if(nest.empty())
    				{
    					range tn;
    					tn.l = left;
    					tn.r = i;
    					del.push_back(tn);
    				}
    			}
    			else if(i<text.size()-1 && text[i+1]=='*')
    			{
    				nest.push_back(i);
    				pos = i+1;
    			}
    		}
    	} 
    	
    	while(!del.empty())
    	{
    		range td = del.back();
    		text.erase(td.l,td.r-td.l+1);
    		del.pop_back();
    	}
    	
    	cout<<"Case #1:\n"<<text;
    }


     

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值