1.给定一个字符串。统计每个字符出现的次数。要求按照出现的次数从大到小排序。
解析:很简单很基础的题目。如果用库函数,可以很简洁:
<?php
function getCountOfStr($string){
$res = str_split($string);
$count = array_count_values($res);
arsort($count);
return $count;
}
$test_string = "abcdefabceeefffees123";
echo "<pre>";
print_r(getCountOfStr($test_string));
/*
* Array(
* [e] => 6
* [f] => 4
* [c] => 2
* [a] => 2
* [b] => 2
* [3] => 1
* [2] => 1
* [1] => 1
* [s] => 1
* [d] => 1
*)
**/
2.字符串的全排列组合问题。
做一个n位字母的组合功能,例如:给定字母a,b,c则所有非空的非重复组合形式为:{a},{b},{c},{a,b},{a,c},{b,c},{a,b,c}
目标
1.字母所有的非重复组合需要打印出来
3..字母组合要排除,abc(三个字母连续),cba(三个字母倒叙)的情况
解析:全排列和组合的问题已经做过很多次。这里不再做过多解释。
详细的解析见
【算法总结-排列组合与子集问题】排列组合与子集问题
3.isset ,empty,is_null的区别.下面的输出是?
<?php
$a = '';
$b = "";
$c = null;
$d = array();
$e = ' ';
$f = 0;
$g = "0";
var_dump( is_null($a));
var_dump( is_null($b));
var_dump( is_null($c));
var_dump( is_null($d));
var_dump( is_null($e));
var_dump( is_null($f));
var_dump( is_null($g));
var_dump( empty($a));
var_dump( empty($b));
var_dump( empty($c));
var_dump( empty($d));
var_dump( empty($e));
var_dump( empty($f));
var_dump( empty($g));
var_dump( isset($a));
var_dump( isset($b));
var_dump( isset($c));
var_dump( isset($d));
var_dump( isset($e));
var_dump( isset($f));
var_dump( isset($g));
解析:
isset():
is_null():
Returns TRUE
if var
isnull,FALSE
otherwise.也就是只有在变量等于null的时候返回true,其他的如空字符,0,”0“ 等都返回false;
empty():
执行结果:
bool(false)
bool(false)
bool(true) //is_null除了null返回true,其他的都返回false
bool(false)
bool(false)
bool(false)
bool(false)
bool(true)
bool(true)
bool(true)
bool(true)
bool(false)//empty只要是空,null,false等都返回true.空格串返回false.
bool(true)
bool(true)
bool(true)
bool(true)
bool(false) //isset检测null或则不存在的变量时返回false.其他的返回true.
bool(true)
bool(true)
bool(true)
bool(true)
4.编写函数,中文字符截取无乱码
中文字符串截取可以用mb_substr();
需要注意的是:中文的编码,GBK的编码格式下,一个中文占据两个字节,而在UTF-8编码下,一个汉字占据三个字节。如果不使用库函数截取中文。需要考虑到这一点。
更多解法可见:http://www.qudong.com/soft/program/php/jiqiaoyunyong/20090731/48210.html
5.用php数组实现无限分类,效率高,不使用数据库,不使用递归(简述论坛中无限分类的实现原理)
无限分类的大致原理是:对于每条元素设置一个唯一的id和一个父类的id. 如此循环下去,可以构成一个庞大的树形结构。用通俗的话说:就好比是文件系统:每个文件都有一个编号和一个父节点。文件夹下面可以新建文件夹。直到叶子节点(文件)。
假设原始数据的结构如下:
$data = array(
array('id'=>1,'pid'=>0,'name'=>'我是父节点'),
array('id'=>2,'pid'=>1,'name'=>'我是节点1'),
array('id'=>3,'pid'=>1,'name'=>'我是节点2'),
array('id'=>4,'pid'=>1,'name'=>'我是节点2'),
)
则实现无线分类就是基于原始数据的id和pid之间的关系。
<?php
function genTree($items,$id='id',$pid='pid',$son = 'children'){
$tree = array();
$tmpMap = array();
foreach ($items as $item) {
$tmpMap[$item[$id]] = $item;
}
foreach ($items as $key => $item) {
if (isset($tmpMap[$item[$pid]])) {
$tmpMap[$item[$pid]][$son][$key] = &$tmpMap[$key];
} else {
$tree[] = &$tmpMap[$item[$id]];
}
}
unset($tmpMap);
return $tree;
}
$items1 = array(
array('id' => 1, 'pid' => 0, 'name' => '一级' ),
array('id' => 11, 'pid' => 0, 'name' => '一级' ),
array('id' => 2, 'pid' => 1, 'name' => '二级' ),
array('id' => 10, 'pid' => 11, 'name' => '二级' ),
array('id' => 3, 'pid' => 1, 'name' => '二级' ),
array('id' => 12, 'pid' => 11, 'name' => '二级' ),
array('id' => 9, 'pid' => 1, 'name' => '二级' ),
array('id' => 14, 'pid' => 1, 'name' => '二级' ),
array('id' => 4, 'pid' => 9, 'name' => '三级' ),
array('id' => 6, 'pid' => 9, 'name' => '三级' ),
array('id' => 7, 'pid' => 4, 'name' => '四级' ),
array('id' => 8, 'pid' => 4, 'name' => '四级' ),
array('id' => 5, 'pid' => 4, 'name' => '四级' ),
array('id' => 13, 'pid' => 4, 'name' => '四级' ),
array('id' => 15, 'pid' => 8, 'name' => '五级' ),
array('id' => 16, 'pid' => 8, 'name' => '五级' ),
array('id' => 17, 'pid' => 8, 'name' => '五级' ),
array('id' => 18, 'pid' => 16, 'name' => '六级' ),
);
echo "<pre>";
echo "父节点:<br/>";
print_r(genTree($items1));
@xuzuning:
徐祖宁老大给的更加简洁一些:
<?php
header("Content-type:text/html;charSet=utf8");
/**
* 创建父节点树形数组
* 参数
* $ar 数组,邻接列表方式组织的数据
* $id 数组中作为主键的下标或关联键名
* $pid 数组中作为父键的下标或关联键名
* 返回 多维数组
**/
function find_parent($ar, $id='id', $pid='pid') {
foreach($ar as $v) $t[$v[$id]] = $v;
foreach ($t as $k => $item){
if( $item[$pid] ){
if( ! isset($t[$item[$pid]]['parent'][$item[$pid]]) )
$t[$item[$id]]['parent'][$item[$pid]] = &$t[$item[$pid]];
}
}
return $t;
}
/**
* 创建子节点树形数组
* 参数
* $ar 数组,邻接列表方式组织的数据
* $id 数组中作为主键的下标或关联键名
* $pid 数组中作为父键的下标或关联键名
* 返回 多维数组
**/
function find_child($ar, $id='id', $pid='pid') {
foreach($ar as $v) $t[$v[$id]] = $v;
foreach ($t as $k => $item){
if( $item[$pid] ) {
$t[$item[$pid]]['child'][$item[$id]] = &$t[$k];
}
}
return $t;
}
$data = array(
array('ID'=>1, 'PARENT'=>0, 'NAME'=>'祖父'),
array('ID'=>2, 'PARENT'=>1, 'NAME'=>'父亲'),
array('ID'=>3, 'PARENT'=>1, 'NAME'=>'叔伯'),
array('ID'=>4, 'PARENT'=>2, 'NAME'=>'自己'),
array('ID'=>5, 'PARENT'=>4, 'NAME'=>'儿子'),
);
$p = find_parent($data, 'ID', 'PARENT');
$c = find_child($data, 'ID', 'PARENT');
echo "<pre>";
echo "父节点:<br/>";
print_r($p);
echo "子节点:<br/>";
print_r($c);
6.classMap的编写
题目描述:给定一套系统,系统的目录结构如下:
controller
configs
model
view
www
编写一个classMap类或函数。实现如下功能:
对于controller,configs,model中的类文件做映射。映射的结果为 文件名前缀 ==>相对于www下classMap.php的路径。结果用数组的形式存入map.php中
例如:controller下有三个文件 AdController.php ,loginController.php,UserController.php,configs下有两个文件:SystemConfig.php,AdConfig.php
则最后映射的结果为(注意只map这三个目录controller,configs,model中的文件):
<?php
class MapConfig{
public static $configs = array(
'AdController' => '../controller/AdController.php',
'LoginController' => '../controller/LoginController.php',
'UserController' => '../controller/UserController.php',
'SystemConfig' => '../configs/SystemConfig.php',
'UserConfig' => '../configs/configs/UserConfig.php',
)
}
看似很简单的一个问题。其实其中考点不少。
目录相关函数,递归的使用(注意三个目录中可能还有其他目录)等。
思路。对于系统的目录,做相应的搜索,如果是文件且在这三个目录中的一个。就对文件位置坐相应映射。如果是目录,继续深层探测。
对于map的结果,可以先用数组保存。最后写入模板文件。
我们做的模板文件内容如下:
<?php
class MapConfig{
public static $config={{content}};
}
整体代码如下:
<?php
header('Content-Type: text/html; charset=UTF-8');
class ClassMap{
private $configFile = 'Map.php';
private $fileDir = array();
private $passName = array('.','..','view','www','.svn');
private $classPath = array();
public function __Construct($dir){
if(is_array($dir)){
$this->fileDir = $dir;
}else{
$this->fileDir = array($dir);
}
}
private function searchClass($parentPath){
$fd = opendir($parentPath);
while($path = readdir($fd)){
if(in_array($path,$this->passName))
continue;
if(is_dir($parentPath.$path))
$this->searchClass($parentPath.$path.'/');
else{
$temp_path = substr($path,0,strpos($path,'.'));
if(!isset($this->classPath[$temp_path])){
$relative_path = str_replace($this->root,"\"/..",$parentPath);
$this->classPath[$temp_path] = $relative_path.$path."\"";
}else{
echo "文件重复:".$parentPath.$path."<hr>\n";
}
}
}
}
public function doSearch(){
foreach($this->fileDir as $v){
$this->root = realpath(dirname(__FILE__).$v);
$this->searchClass(realpath(dirname(__FILE__).$v)."/");
}
$this->writeFile();
}
private function writeFile(){
$content = file_get_contents(dirname(__FILE__).'/Map.php.tpl');
$str = "array(\n";
foreach($this->classPath as $k => $v){
$str.=" '$k' => ".$v.",\n";
}
$str.=" )";
$content = str_replace('{{content}}',$str,$content);
file_put_contents(dirname(__FILE__).$this->configFile,$content);
}
}
$dir = "/../";
$map = new ClassMap($dir);
$map->doSearch();
?>
7. 在 HTML 语言中,页面头部的 meta 标记可以用来输出文件的编码
格式,以下是一个标准的 meta 语句
<META http-equiv=’Content-Type‘ content=’text/html; charset=gbk’>
请使用 PHP 语言写一个函数,把一个标准 HTML 页面中的类似 meta 标记中的 charset 部分值改为 big5
请注意:
(1) 需要处理完整的 html 页面,即不光此 meta 语句
(2) 忽略大小写
(3) ‘ 和 ” 在此处是可以互换的
(4) ‘Content-Type’ 两侧的引号是可以忽略的,但 ‘text/html; charset=gbk’ 两侧的不行
(5) 注意处理多余空格
解析:这里全面考察正则表达式匹配。
(1) 需要处理完整的 html 页面,即不光此 meta 语句 ==》 preg_replace()
(2) 忽略大小写 ==> i修饰符
(3) ‘ 和 ” 在此处是可以互换的 ==》多选结构 【“|‘】
(4) ‘Content-Type’ 两侧的引号是可以忽略的,但 ‘text/html; charset=gbk’ 两侧的不行 ==》可选结构 ’?
(5) 处理多余的空格 \s?表示0到多处空白
综合,我们得到的测试代码如下:(未经测试 :b )
<?php
function chgCharSet($url){
$string = getContent($url);
$patten = '/(<meta\shttp-equiv\s*=\s*([\'|"]?)Content-Type\2\s*content\s*=\s*([\'|"])text\/html\s*;\s*charset=)([\w]+)(\3\s*>)/i';
preg_replace($patten,"$1"."big5"."$5",$string);
}
function getContent($url){
return file_get_contents($url);
}
$url = "http://www.baidu.com";
echo chgCharSet($url);