看到腾讯的这个面试题,这个题使用sed或awk 估计效率会更高,但我忍不住想PHP解答一下
思路是 先建索引文件(优化效率),之后传参 分解参数,找相应的索引文件(记录行号和单词号)
题:
我们碰到了大麻烦,一个新来的传教士惹恼了上帝,上帝很愤怒,要求我们把圣经(bbe.txt)背熟,直至他说哪个单词,我们就要飞快的回答出这个单词在第几行第几个单词位置。听说你是个优秀的程序员,那么髟助我们完成这个不可能的任务吧。
要求如下:
1)/myworks/example/bbe.txt,98版本英文圣经一本
2)输入部分要求如下:php ./example.php [单词]
3)输出部分如下:[单词] 1,2 2,4 5,6 表示:此单词在1行2列(第二个单词),2行4列...
说明:
1)此文本4MB之巨...
2)单词的含义:由英文字母(大小写),数字(0-9)组成的串
3)提供给你的机器OS为ubuntu 9.10,内存只有1G,而且,很不幸的,其中700M用来做了别的
4)上机考试不允许上网,但我装了man文档以及读取CHM以及PDF的阅读器,在电脑的桌面的CHM文件夹中,有相应的PHP参考手册
5)算法复杂度要求不能大于O(N^2)(就是N的平方)
6)什么?PHP低效且用起来不顺手,好的,你可以用别的语言来实现。但注意:提供给你的机器上只有python 2.4/perl 5.8/gcc[g++] 4.1
解题:
bbe.txt文件咱们没有 想像成是 空格 隔开的算了
hello123 hello tim jason
woaini1 tianjianxiong333 hh aaa
/* 此文件用于根据bbe.txt文件对所有单词创建索引,相当于一次预处理 */
ini_set('display_errors','on');
set_time_limit(0);
$file = file($src); // 数组
foreach($file as $i => &$ls){
$a = explode(" ",$ls);
$len = count($a);
if ($len > 0){
for($j=0;$i<$len;$j++){
$data = "此单词".$a[$j]."在".($i+1)."行,".($j+1)."列";
$key = md5(trim(strtolower($a[$j])));
file_put_contents($key,$data);
}
}
//echo $i.". > ".$ls.'<br />';
}
example.php:
#!/usr/local/bin/php -q
<?php
set_time_limit(0);
$getkey=empty($argv[1]) ? $_REQUEST['k'] : $argv[1];
$arr = explode(",",$getkey);
$len = count($arr);
if($len > 0){
for($i=0;$i<$len;$i++){
echo getKey($arr[$i])."\n";
}
}
functuion getKey($key){
$str = "没有找到此单词[".$key."]";
if($key){
$fc = md5($key);
$str = file_get_contents($fc));
}
return $str;
}
?>
记得把 example.php 755 一下
别人的方法:
1、使用ascii码,判断字符所在范围
2、只要扫描一遍字符即可,复杂度为O(N)
3、利用了php string{$i} 的特性,取字符串内任一字符
4、todo:改为fgetc版本,可以完全不需要使用以上php特性
5、字符串匹配算法:http://wendell07.blog.hexun.com/14112681_d.html,目前看来最快的方法:Sunday,由于本题是单词匹配,问题更简单,只要找到头尾……
$word = $argv[1];
$lines = 0;
$handle = @fopen("bbe.txt", "r");
if ($handle) {
while (!feof($handle)) {
$line = fgets($handle, 4096);
$local = local_word($line, $word);
$lines++;
if( !empty($local) ){
echo "$lines,".implode(' ',$local)."\n";
}
}
fclose($handle);
}
function local_word($line, $word){
$local = array();
$local_length = 1;
$word_length = strlen($word);
for($i = 0; ( $char = $line{$i} ) !== ''; $i++ ){
// 单词最后一个字符必定不是符号,且必有一个符号结尾,此计为一个新词
if( !is_symbel( $line{ $i-1 } ) && is_symbel($char) ){
$local_length++;
}
if( $char === $word[0] && // 如果第一个字符相同
is_symbel( $line{ $i-1 } ) && // 且为单词开始
is_symbel( $line{ $i+$word_length }) // 单词结尾应该为符号
){
// 进入验证单词模式,一个一个字符比对
for($j = 1; ($w_char = $word{$j}) !== ''; $j++ ){
// 遇到单词字符不匹配
if( $w_char != $line{ $i+$j } ){
$i += $j;
break;
}
// 如果单词比对完全正确
if( $j == ($word_length-1) ){
//echo "$line_length, $word_length\n";
$local[] = $local_length;
}
}
}
}
return $local;
}
function is_symbel($char){
$asc = ord($char);
return !( (48 <= $asc && $asc <= 57) ||
(65 <= $asc && $asc <= 90) ||
(97 <= $asc && $asc <= 122) );
}
原文地址:
http://www.xiaot.net/post/HaoQiGuaiDeFenJieQi.html
来自 小田 的博客