PHP算法实战-面试题(1)

二分查找

基本思想:
 
    假设数据是按升序排序的,对于给定值x,从序列的中间位置开始比较,如果当前位置值等于x,则查找成功;若x小于当前位置值,则在数列的前半段中查找;若x大于当前位置值则在数列的后半段中继续查找,直到找到为止。(数据量大的时候使用)

<?php
  //二分查找
  function bin_search($arr,$low,$high,$k)
  {
    if($low <= $high)
    {
      $mid = intval(($low + $high)/2);
      if($arr[$mid] == $k)
      {
        return $mid;
      }
      else if($k < $arr[$mid])
      {
        return bin_search($arr,$low,$mid-1,$k);
      }
      else
      {
        return bin_search($arr,$mid+1,$high,$k);
      }
    }
    return -1;
  }
 
  $arr = array(1,2,3,4,5,6,7,8,9,10);
 
  print(bin_search($arr,0,9,3));
?>

顺序查找

基本思想:
 
从数组的第一个元素开始一个一个向下查找,如果有和目标一致的元素,查找成功;如果到最后一个元素仍没有目标元素,则查找失败。

<?php
  //顺序查找
  function seq_search($arr,$n,$k)
  {
    $array[$n] = $k;
    for($i = 0;$i < $n; $i++)
    {
      if($arr[$i] == $k)
      {
        break;
      }
    }
 
    if($i < $n)
    {
      return $i;
    }
    else
    {
      return -1;
    }
  }
?>

简化增强版本

function  seq_sch($array, $k){   
    $y = $m = 'no'; 
    foreach($array as $i => $v){
        if($v == $k){  
            if($i == 'no'){$m = 'yes'}//防止key = no
            $y = $i; 
            break;   
        }   
    }   
    if ($y != 'no' || $m == 'yes'){   
        return  $y;   
    }else{   
        return -1;   
    }   
}   

此方法适用于所有一维数组

PHP奇异算法

<?php
function test(){
 $a=1;
 $b=&$a;
 echo (++$a)+(++$a);
}
test();

PHP7以下的版本返回的是 6,PHP7版本返回5 ,还真的算奇异,个人底层算法差,认为是PHP7以下版本的BUG

 

线性表的删除(数组中实现)

function delete_array_element($array , $i){  
    $len = count($array);   
    for ($j=$i; $j<$len; $j++){  
            $array[$j] = $array [$j+1];  
    }  
    array_pop ($array);  
    return $array ;  
}  

字符串长度

function strlen ($str){  
    if ($str == '' ) return 0;  
    $count =  0;  
    while (1){  
        if ($str[$count] != NULL){  
            $count++;  
            continue;  
        }else{  
            break;  
        }  
    }  
    return $count;  
} 
  • while (1) 其中1代表一个常量表达式,他永远不会等于0。所以,循环会一直执行下去。除非你设置break等类似的跳出循环语句循环才会中止

  • $str[count] php是弱类型语言 使用下标可以读取到相应位置对应参数

function substr($str, $start,  $length=NULL){  
    if ($str== '' || $start>strlen($str)) return;  
    if (($length!=NULL) && ($start>0) && ($length>strlen($str)-$start)) return;  
    if (($length!=NULL) && ($start<0) && ($length>strlen($str )+$start)) return;  
    if ($length == NULL) $length = (strlen($str) - $start);  

    if ($start < 0){  
            for ($i=(strlen($str)+$start); $i<(strlen ($str)+$start+$length ); $i++) {  
                 $substr .=  $str[$i];  
            }  
    }  
    if ($length > 0){  
            for ($i= $start; $i<($start+$length); $i++) {  
                  $substr .= $str[$i];  
            }  
    }  
    if ($length < 0){  
            for ($i =$start; $i<(strlen($str)+$length); $i++) {  
                   $substr .= $str[$i ];  
            }  
    }  
    return $substr;  

字符串翻转

function strrev($str){  
    if ($str == '') return 0 ;  
    for ($i=(strlen($str)- 1); $i>=0; $i --){  
            $rev_str .= $str[$i ];  
    }  
    return $rev_str;  
}  

字符串比较

function strcmp($s1, $s2){  
    if (strlen($s1) <  strlen($s2)) return -1 ;  
    if (strlen($s1) > strlen( $s2)) return 1;  
    for ($i=0; $i<strlen($s1); $i++){  
        if ($s1[$i] == $s2[$i]){  
            continue;  
        }else{  
            return false;  
        }  
    }  
    return  0;  
}  

查找字符串

function  strstr($str, $substr){  
    $m = strlen($str);  
    $n = strlen($substr);  
    if ($m < $n) return false ;  
    for($i=0; $i<=($m-$n+1); $i++){  
        $sub = substr($str, $i, $n);  
        if (strcmp($sub, $substr) ==  0)  return $i;  
    }  
    return false ;  
} 

strcmp(sub,sub,substr)字符串比较方法 如果想不用比较方法请增加for循环

字符串替换

function str_replace($substr, $newsubstr, $str){  
    $m = strlen($str);  
    $n = strlen($substr);  
    $x = strlen($newsubstr);  
    if (strchr($str, $substr) == false) return false;
    $str_new = $str  
    for ($i=0; $i<=($m-$n+1); $i++){  
        $i = strchr($str, $substr);  
        $str = str_delete($str_new, $i, $n);  
        $str = str_insert($str_new, $i, $newstr);  
    }  
    return $str_new;  
} 
  • strchr() 函数搜索字符串在另一字符串中的第一次出现。 
    该函数是 strstr() 函数的别名。

插入一段字符串

function str_insert($str, $i , $substr) {  
    for($j=0 ; $j<$i; $j++){  
            $startstr .= $str[$j];  
    }  
    for ($j=$i; $j <strlen($str); $j++){  
            $laststr .= $str[$j ];  
    }  
    $str = $startstr.$substr.$laststr;  
    return $str ;  
}  

删除一段字符串

function str_delete($str, $i, $j){  
    for ( $c=0; $c<$i; $c++){  
        $startstr .= $str [$c];  
    }  
    for ($c=( $i+$j); $c<strlen ($str); $c++){  
        $laststr .= $str[$c];  
    }  
    $str = $startstr.$laststr;  
    return $str;  
}

复制字符串

function strcpy($s1, $s2){  
    if (strlen($s1)==NULL || !isset($s2)) return;  
    for ($i=0; $i<strlen($s1); $i++){  
        $s2[] = $s1[$i];  
    }  
    return $s2;  
} 

连接字符串

function strcat($s1 ,$s2){  
    if (!isset($s1) || !isset( $s2)) return;  
    $newstr = $s1 ;  
    for($i=0; $i<strlen($s2); $i++){  
            $newstr .= $s2[$i];  
    }  
    return $newstr;  
} 

---------------------------------------------------------------------------------------------------------------------------------------------------------

字符集合:输入一个字符串,求出该字符串包含的字符集合,并按顺序排序(英文)

function set($str){
    //转化为数组
    $arr = str_split($str);
    //去除重复
    $arr = array_flip(array_flip($arr));
    //排序
    sort($arr);
    //返回字符串
    return implode('', $arr);
}

遍历文件夹

<?php  
  function my_scandir($dir)
  {
    $files = array();
    if($handle = opendir($dir))
    {
      while (($file = readdir($handle))!== false) 
      {
        if($file != '..' && $file != '.')
        {
          if(is_dir($dir."/".$file))
          {
            $files[$file]=my_scandir($dir."/".$file);
          }
          else
          {
            $files[] = $file;
          }
        }
      }
 
      closedir($handle);
      return $files;
    }
  }
 
  var_dump(my_scandir('../'));
?>

写一个函数,尽可能高效的从一个标准url中取出文件的扩展名

<?php
  function getExt($url)
  {
    $arr = parse_url($url);//parse_url解析一个 URL 并返回一个关联数组,包含在 URL 中出现的各种组成部分
    //'scheme' => string 'http' (length=4)
    //'host' => string 'www.sina.com.cn' (length=15)
    //'path' => string '/abc/de/fg.php' (length=14)
    //'query' => string 'id=1' (length=4)
    $file = basename($arr['path']);// basename函数返回路径中的文件名部分
    $ext = explode('.', $file);
    return $ext[count($ext)-1];
  }
  print(getExt('http://www.sina.com.cn/abc/de/fg.html.php?id=1'));
?>

实现中文字符串截取无乱码的方法

可使用mb_substr,但是需要确保在php.ini中加载了php_mbstring.dll,即确保“extension=php_mbstring.dll”这一行存在并且没有被注释掉,否则会出现未定义函 数的问题。

 

数据结构和算法

使对象可以像数组一样进行foreach循环,要求属性必须是私有。(Iterator模式的PHP5实现,写一类实现Iterator接口)(腾讯)
 

<?php
    class Test implements Iterator{
    private $item = array('id'=>1,'name'=>'php');
 
    public function rewind(){
        reset($this->item);
    }
 
    public function current(){
        return current($this->item);
    }
 
    public function key(){
        return key($this->item);
    }
 
    public function next(){
        return next($this->item);
    }
 
    public function valid(){
        return($this->current()!==false);
    }
}
    //测试
    $t=new Test;
    foreach($t as $k=>$v){
        echo$k,'--->',$v,'<br/>';
    }
?>

用PHP实现一个双向队列(腾讯)

<?php
    class Deque{
    private $queue=array();
    public function addFirst($item){
        return array_unshift($this->queue,$item);
    }
 
    public function addLast($item){
        return array_push($this->queue,$item);
    }
    public function removeFirst(){
        return array_shift($this->queue);
    }
 
    public function removeLast(){
        return array_pop($this->queue);
    }
}
?>

请使用冒泡排序法对以下一组数据进行排序10 2 36 14 10 25 23 85 99 45。

<?php
    // 冒泡排序
    function bubble_sort(&$arr){
        for ($i=0,$len=count($arr); $i < $len; $i++) {
            for ($j=1; $j < $len-$i; $j++) {
                if ($arr[$j-1] > $arr[$j]) {
                    $temp = $arr[$j-1];
                    $arr[$j-1] = $arr[$j];
                    $arr[$j] = $temp;
                }
            }
        }
    }
 
    // 测试
    $arr = array(10,2,36,14,10,25,23,85,99,45);
    bubble_sort($arr);
    print_r($arr);
?>

写出一种排序算法(要写出代码),并说出优化它的方法。(新浪)

<?php
    //快速排序
    function partition(&$arr,$low,$high){
        $pivotkey = $arr[$low];
        while($low<$high){
            while($low < $high && $arr[$high] >= $pivotkey){
                $high--;
            }
            $temp = $arr[$low];
            $arr[$low] = $arr[$high];
            $arr[$high] = $temp;
            while($low < $high && $arr[$low] <= $pivotkey){
                $low++;
            }
            $temp=$arr[$low];
            $arr[$low]=$arr[$high];
            $arr[$high]=$temp;
        }
        return$low;
    }
 
 
function quick_sort(&$arr,$low,$high){
    if($low < $high){
        $pivot = partition($arr,$low,$high);
        quick_sort($arr,$low,$pivot-1);
        quick_sort($arr,$pivot+1,$high);
    }
}
?>

关于猴子的面试题

一群猴子排成一圈,按1,2,...,n依次编号。然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去...,如此不停的进行下去,直到最后只剩下一只猴子为止,那只猴子就叫做大王。要求编程模拟此过程,输入m、n,输出最后那个大王的编号。(新浪)(小米)
 

<?php
    // 方案一,使用php来模拟这个过程
    function king($n,$m){
        $mokey = range(1, $n);
        $i = 0;
 
        while (count($mokey) >1) {
            $i += 1;
            $head = array_shift($mokey);//一个个出列最前面的猴子
            if ($i % $m !=0) {
                #如果不是m的倍数,则把猴子返回尾部,否则就抛掉,也就是出列
                array_push($mokey,$head);
            }
 
            // 剩下的最后一个就是大王了
            return $mokey[0];
        }
    }
    // 测试
    echo king(10,7);
 
    // 方案二,使用数学方法解决
    function josephus($n,$m){
        $r = 0;
        for ($i=2; $i <= $m ; $i++) {
            $r = ($r + $m) % $i;
        }
 
        return $r+1;
    }
    // 测试
    print_r(josephus(10,7));

    // 方案三
    function king($n, $m){
        $monkeys = range(1, $n);         //创建1到n数组
	    $i=0;
	    while (count($monkeys)>1) {	 //循环条件为猴子数量大于1
		   if(($i+1)%$m==0) {	 //$i为数组下标;$i+1为猴子标号
			   unset($monkeys[$i]);	//余数等于0表示正好第m个,删除,用unset删除保持下标关系
		   } else {
               //如果余数不等于0,则把数组下标为$i的放最后,形成一个圆形结构
			   array_push($monkeys,$monkeys[$i]);     
			 unset($monkeys[$i]);
		}
			$i++;//$i 循环+1,不断把猴子删除,或 push到数组 
	}
	return current($monkeys);	//猴子数量等于1时输出猴子标号,得出猴王
}
echo king(6,3);
?>

二维数组排序算法函数,能够具有通用性,可以调用php内置函数。

<?php
 
 
function array_sort($arr,$keys,$order=0){
    if(!is_array($arr)){
        return false;
    }
 
 
	//根据指定的字段和内层数组的下标组成新的一维数组
    $keysvalue=array();
    foreach($arr as $key => $val){
        $keysvalue[$key] = $val[$keys];
    }
	print_r($keysvalue);
 
 
	//对数组按照指定字段排序并保持索引关系
    if($order == 0){
        asort($keysvalue);
    }else{
        arsort($keysvalue);
    }
	print_r($keysvalue);
   
    $new_array=array();
	//按照排好序的下标,重新组合原二维数组
    foreach($keysvalue as $key => $val){
        $new_array[$key] = $arr[$key];
    }
    return $new_array;
}
    //测试
    $person=array(
        array('id'=>2,'name'=>'lhangsan','age'=>23),
        array('id'=>5,'name'=>'zisi','age'=>28),
        array('id'=>3,'name'=>'apple','age'=>17)
    );
    $result = array_sort($person,'name',0);
 
 
    print_r($result);
 
 
?>

顺序查找和二分查找(也叫做折半查找)算法,顺序查找必须考虑效率,对象可以是一个有序数组(小米)

<?php
    /**
     * 顺序查找
     * @param  array $arr 数组
     * @param   $k   要查找的元素
     * @return   mixed  成功返回数组下标,失败返回-1
     */
    function seq_sch($arr,$k){
        for ($i=0,$n = count($arr); $i < $n; $i++) {
            if ($arr[$i] == $k) {
                break;
            }
        }
        if($i < $n){
            return $i;
        }else{
            return -1;
        }
    }
 
    /**
     * 二分查找,要求数组已经排好顺序
     * @param  array $array 数组
     * @param  int $low   数组起始元素下标
     * @param  int $high  数组末尾元素下标
     * @param   $k     要查找的元素
     * @return mixed        成功时返回数组下标,失败返回-1
     */
    function bin_sch($array,$low,$high,$k){
        if ($low <= $high) {
            $mid = intval(($low + $high) / 2);
            if ($array[$mid] == $k) {
                return $mid;
            } elseif ($k < $array[$mid]) {
                return bin_sch($array,$low,$mid - 1,$k);
            } else{
                return bin_sch($array,$mid + 1,$high,$k);
            }
        }
        return -1;
    }
 
    // 测试:顺序查找
    $arr1 = array(9,15,34,76,25,5,47,55);
    echo seq_sch($arr1,47);//结果为6
 
    echo "<br />";
 
    // 测试:二分查找
    $arr2 = array(5,9,15,25,34,47,55,76);
    echo bin_sch($arr2,0,7,47);//结果为5
?>

洗牌算法

<?php
    $card_num = 54;//牌数
    function wash_card($card_num){
        $cards = $tmp = array();
        for($i = 0;$i < $card_num;$i++){
            $tmp[$i] = $i;
        }
 
        for($i = 0;$i < $card_num;$i++){
            $index = rand(0,$card_num-$i-1);
            $cards[$i] = $tmp[$index];
            unset($tmp[$index]);
            $tmp = array_values($tmp);
        }
        return $cards;
    }
    // 测试:
    print_r(wash_card($card_num));
?>

有一母牛,到4岁可生育,每年一头,所生均是一样的母牛,到15岁绝育,不再能生,20岁死亡,问n年后有多少头牛。

function niu($y){
	static $num= 1;					//定义静态变量;初始化牛的数量为1
	for ($i=1; $i <=$y ; $i++) { 	
		if($i>=4 && $i<15){	      //每年递增来算,4岁开始+1,15岁不能生育
		$num++;
			niu($y-$i);			    //递归方法计算小牛$num,小牛生长年数为$y-$i
		}else if($i==20){			
		$num--;	                         //20岁死亡减一
		}
	return $num;
}

 PHP实现斐波那契数列

/**
 * 斐波那契数列
 * @param $n
 * @return mixed
 */
function fbnq($n){
    $arr[1] = 1;
    $arr[2] = 1;
    for($i=3; $i<=$n; $i++){
        $arr[$i] = $arr[$i-1] + $arr[$i-2];
    }
    return $arr;
}
var_dump(array_values(fbnq(10)));die;

比较两个文件路径的相对

$b = '/a/b/c/d/e.php';
$a = '/a/b/f/g/j/h.php';
function diff($a, $b){
    $aArr = explode('/',$a);
    $bArr = explode('/',$b);
    $bCount = count($bArr);
    $k = 0;
    for($i=0;$i<$bCount;$i++){
        if($aArr[$i] != $bArr[$i]){
            $k = $i;
            break;
        }
    }
    //echo $k;die;
    //var_dump(array_fill(0, $bCount-$k, '..'));die;
    $result = array_merge(array_fill(1, $bCount-$k-1, '..'), array_slice($aArr,$k));
    return implode('/', $result);
}
var_dump(diff($a, $b));die;

杨辉三角

<?php
/* 默认输出十行,用T(值)的形式可改变输出行数 */
class T{
  private $num;
  public function __construct($var=10) {
    if ($var<3) die("值太小啦!");
    $this->num=$var;
  }
  public function display(){
    $n=$this->num;
    $arr=array();
  //$arr=array_fill(0,$n+1,array_fill(0,$n+1,0));
    $arr[1]=array_fill(0,3,0);
    $arr[1][1]=1;
    echo str_pad(" ",$n*12," ");
    printf("%3d",$arr[1][1]);
    echo "<br/>";
    for($i=2;$i<=$n;$i++){
      $arr[$i]=array_fill(0,($i+2),0);
      for($j=1;$j<=$i;$j++){
        if($j==1)
          echo str_pad(" ",($n+1-$i)*12," ");
        printf("%3d",$arr[$i][$j]=$arr[$i-1][$j-1]+$arr[$i-1][$j]);
        echo "  ";
      }
      echo"<br/>";
    }
  }
}
$yh=new T('3'); //$yh=new T(数量);
$yh->display();
?>

有个人想上一个n级的台阶,每次只能迈1级或者迈2级台阶,问:这个人有多少种方法可以把台阶走完?例如:总共3级台阶,可以先迈1级再迈2级,或者先迈2级再迈1级,或者迈3次1级总共3中方式

function jieti($num){	//实际上是斐波那契数列
		return $num<2?1:jieti($num-1)+jieti($num-2);
	}

请写一段PHP代码,确保多个进程同时写入同一个文件成功

<?php
    $fp = fopen("lock.txt","w+");
    if (flock($fp,LOCK_EX)) {
        //获得写锁,写数据
        fwrite($fp, "write something");
 
        // 解除锁定
        flock($fp, LOCK_UN);
    } else {
        echo "file is locking...";
    }
    fclose($fp);
?>

无限级分类

function tree($arr,$pid=0,$level=0){
        static $list = array();
        foreach ($arr as $v) {
            //如果是顶级分类,则将其存到$list中,并以此节点为根节点,遍历其子节点
            if ($v['pid'] == $pid) {
                $v['level'] = $level;
                $list[] = $v;
                tree($arr,$v['id'],$level+1);
            }
        }
        return $list;
    }

获取上个月第一天 和 最后一天

//获取上个月第一天
    date('Y-m-01',strtotime('-1 month'));
 
    //获取上个月最后一天
    date('Y-m-t',strtotime('-1 month'));

随机输入一个数字能查询到对应的数据区间

//把区间换成数组写法,用二分法查找区间
	function binsearch($x,$a){  
	    $c=count($a);  
	    $lower=0;  
	    $high=$c-1;  
	    while($lower<=$high){  
	        $middle=intval(($lower+$high)/2);  
        	if($a[$middle]>=$x){  
	            $high=$middle-1;
	        }elseif($a[$middle]<=$x ){  
	            $lower=$middle+1;
	        }   
	    }
 
	    return '在区间'.$a[$high].'到'.$a[$lower];  
	}
 
	$array  = ['1','50','100','150','200','250','300'];
	$a = '120';
	echo binsearch($a,$array);

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值