关于腾讯的那道题截取字符串的题

题目是:
假设有"123<em>abc</em>456<em>def</em>789"这么一个字符串,写一个函数,可以传入一个字符串,和一个要截取的长度。返回截取后的结果。

要求:
1 <em>和</em>标记不得计算在长度之内。
2 截取后的字符串,要保留原有<em>标签,不过如果最后有一个标签没有闭合,则去掉其开始标签。

示例:
题中的字符串,要截取长度5,则返回的字符串应该为:123ab,要截取长度8,应返回123<em>abc</em>45。



我的做法大概思路是:
1 首先顺序读取字符串,并用一个resultstr变量来记录所有字符,当发现<标记时,开始将这个子字符串用tag变量记录下来。
2 如果发现tag变量形式为</w+>也就是html标签的开始标记),就将其入栈。用栈结构来存储这个标记。若遇到<///w+>(html标签的结束标记),就出栈。

3 否则如果是常规字符的话,长度计数器++。直到与传入的要截取长度相等。

4 最后判断栈是否为空,如果为空,直接返回截取后的字符串,否则,将栈中剩余元素一个个出栈,循环从截取后的字符串中查找栈顶标签元素最后一次出现的位置,返回索引,将这个标签替换为空。直到整个栈为空为止。最后返回处理后的字符串。



原题其实是没有考虑标签嵌套的情况的,我尽量的让程序可以处理嵌套标签,使其更健壮。并且尽量少的去用php的内置函数,因为那样可能会掩盖算法本身。如可以处理a1<p>b2<em>c3</em>d4</p>e5
这种形式的嵌套标签。但我发现如果标签是这种不规则形式a1<p>b2<em>c3d4</p>e5的话,程序就会出问题了。因为我只将取到的结束标记与栈顶的元素相比较,而没有去循环搜索整个栈。这里要改一下其实也可以。


不知大家还有没有其他思路,我感觉我这么做实在是太麻烦了,罗罗嗦嗦一大堆。这么多代码面试时拿笔写非得疯了不可。而且这个时间复杂度不理想,大概为O(n*(n2))。空间方面也占了很多多余的空间。我相信一定有很简单的办法。希望大家一起想想有什么更简单的方法没?


PHP code
   
   
<? php function mySubstr( $str , $length ){ $tagcnt = 0 ; $charcnt = 0 ; $tag = '' ; $maxlen = strlen ( $str ); $resultstr = '' ; $tagstack = array (); for ( $i = 0 ; $i < $length ; $i ++ ){ if ( $str [ $i ] == ' < ' ){ $resultstr .= $str [ $i ]; for ( $j = $i ; $str [ $j ] != ' > ' ; $j ++, $length ++ ){ $tag .= $str [ $j ]; } $tagcnt ++ ; $length ++ ; $tag .= ' > ' ; // 如果是开始标记,则入栈,如果是与之相对应的结束标记则出栈 if ( preg_match ( ' /<([^//]+)?>/i ' , $tag , $r ) ){ echo ' 入栈: ' , htmlspecialchars ( $r [ 1 ]) , ' <br /> ' ; array_push ( $tagstack , $r [ 1 ]); } elseif ( preg_match ( ' / ' . $tagstack [ count ( $tagstack ) - 1 ] . ' / ' , $tag ) ){ echo ' 出栈: ' , htmlspecialchars ( $tagstack [ count ( $tagstack ) - 1 ]) , ' <br /> ' ; array_pop ( $tagstack ); } $tag = '' ; continue ; } $charcnt ++ ; $resultstr .= $str [ $i ]; } echo ' <hr size=1>最后结果为: ' ; // 栈是空的直接返回 if ( empty ( $tagstack )){ return $resultstr ; } // 否则去掉没有结束标记的开始标记 else { while ( ! empty ( $tagstack )){ $tag = array_pop ( $tagstack ); $index = strrpos ( $resultstr , $tag ); for ( $i = $index - 1 ; $resultstr [ $i ] != ' > ' ; $i ++ ){ $resultstr [ $i ] = '' ; } $resultstr [ $i ++ ] = '' ; } return $resultstr ; } } $sttime = microtime ( true ); $stmem = memory_get_usage(); $str = " a1<body>b2<p>c3<em>d4</em>e5</p>f6</body>g7h8 " ; echo ' 处理结果为:<br/><hr size=1> ' , htmlspecialchars ( mySubstr( $str , 18 ) ) , ' <br /> ' ; echo " 内存使用情况: " , (memory_get_usage() - $stmem ) , ' <br /> ' ; echo " 算法运行时间(microtime): " , ( microtime ( true ) - $sttime ) , ' <br/> ' ;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值