• 面试--算法题


    1、红蓝颜料桶问题

    【题目】

    如果你有两个桶,一个装的是红色的颜料,另一个装的是蓝色的颜料。你从蓝色颜料桶里舀一杯,倒入红色颜料桶,搅拌均匀,再从红色颜料桶里舀一杯倒入蓝颜料桶,也是搅拌均匀。

    两个桶中红蓝颜料的比例哪个更高?通过算术的方式来证明这一点。

    【答案】

    蓝桶的 蓝红比例  和 红桶的  红蓝比例,是一样的。

    【计算过程】

    假设桶的容量大小为L,一勺子的容量大小为X

    第一步操作: 

    蓝桶:L-X

    红桶: L+X

    备注:红桶中,混合均匀,所以红蓝颜料的比例:L:X

    第二步操作:

    红桶:红蓝颜料的比例不变,因为是均匀的。比例还是L:X

    蓝桶: 

    蓝色:L-X +   (X/(L+X))*X  = ((L-X)*(L+X)+X*X)/(L+X)

    红色: (L/(L+X))*X=(XL)/(L+X)

    所以 蓝红 比例,底都乘以 (L+X):

    蓝:L*L-X*X +X*X = L*L

    红:L*X

    所以 蓝桶的蓝红比例是:L:X  和红桶的红蓝比例是一样的

    【注意】:(x+y)(x-y) 平方差 =x²-y²

    2、一个类,实现一个数组的循环队列,写出入队列、出队列、是否为空和获取长度的方法

     1 class loopArray
     2 {
     3   private $size = 100;
     4   private $arr = [];
     5 
     6   public function __construct(int $size)
     7   {
     8     if ($size  > 1) {
     9       $this->size = $size;
    10     }
    11   }
    12 
    13   //入队列
    14   public function push(string $data)
    15   {
    16     if (count($this->arr) == $this->size) {
    17       return false;
    18     } else {
    19       $this->arr[] = $data;
    20       return true;
    21     }
    22   }
    23 
    24   // 出队列
    25   public function pull()
    26   {
    27     if (empty($this->arr)) {
    28       return false;
    29     } else {
    30         return array_shift($this->arr);
    31     }
    32   }
    33 
    34   // 是否为空  true:为空  false:不为空
    35   public function isEmpty()
    36   {
    37     return empty($this->arr); 
    38   }
    39 
    40   // 获取长度
    41   public function getSize()
    42   {
    43     return count($this->arr);
    44   }
    45 }

    3、RGB字母排序问题

    RGB排序,一个字符串,里面只有三种字符R G B,所有的R都在G的前面,所有的G都在B的前面。

    将给定字符串按照此规律排序。要求不允许用辅助空间(如果要使用辅助空间,不能是整个数组那么长的空间复制一遍),复杂度控制在O(N)。

     【难度分析】本道题难在如何控制时间复杂度和空间复杂度, 空间负责度的话,就是不能传值,传地址会减少空间的复制。

    因为这种题目的局限性,3个字母,而且是RGB降序,所以冒泡算法是个不错的算法。但是如果不用冒泡算法,怎么处理?下面给出答案。

    参考:

    https://blog.csdn.net/weixin_44124500/article/details/85039699

    https://blog.csdn.net/brucehb/article/details/12363085

    感觉上面2篇文章的算法可能有点问题,感觉啦,也可能我自己没看懂,下面是我自己的算法,测试过是没问题的

     1 <?php
     2 
     3 function deal(array &$arr)
     4 {
     5         $len = count($arr);
     6         $i = -1;
     7         while ($i<$len && $arr[$i+1] == 'R'){
     8                 $i++;
     9         }
    10         $j = $len;
    11         while ($j>0 && $arr[$j-1] == 'B'){
    12                 $j--;
    13         }
    14 
    15         $p = $i+1;
    16         while ($p < $j) {
    17                 if ($arr[$p] == 'R') {
    18                         $i++;
    19                         // 交换值
    20                         if ($arr[$i] != $arr[$p]) {
    21                                 $temp = $arr[$i];
    22                                 $arr[$i] = $arr[$p];
    23                                 $arr[$p] = $temp;
    24                         } else {
    25                                 $p++;
    26                         }
    27                 } else if ($arr[$p] == 'B') {
    28                         $j--;
    29                         // 交换值
    30                         if ($arr[$j] != $arr[$p]) {
    31                                 $temp = $arr[$j];
    32                                 $arr[$j] = $arr[$p];
    33                                 $arr[$p] = $temp;
    34                         } 
    35                 } else {
    36                         $p++;
    37                 }
    38         }
    39 }
    40 
    41 $arr = 'GBBRRGGBBRBGRBGBBRRGGGGBGGGGRRRRBBGGRRR';
    42 $arr = str_split($arr);
    43 //print_r($arr);
    44 deal($arr);
    45 //print_r($arr);
    46 print_r(implode('',$arr));
    47 echo PHP_EOL;

    输出结果:RRRRRRRRRRRRRGGGGGGGGGGGGGGGBBBBBBBBBBB

    【思路】

    设置3个“指针”,i和j、p,对php的数组来说,就是对应的数组下标。

    i是指向-1,如果左起第一个字符是R,那么往后找第一个非R处停止。

    举例,如果字符串是“RRRGB。。。”那么i的初始值是2,p的初始值是3

    如果字符串“GBR。。。。”,非R字母开头的,那么i的初始值是-1,p的初始值是0

    同理来设置j的初始值,要么是n,要么是右起第一个非B的字符

    举例,如果字符串“。。。。GBBB”, 假设字符串长度100,那么j的初始值就是97

    如果字符串“。。。。G”,非B字符结尾,那么j的初始值就是100。

    p是i的下一位,p本身的值不可能是R,因为p是i+1, i+1非R字符

    往下就是如果$p对应的数组元素值是 G 则p++,指向下一个数组元素

    如果是$arr[$p] == 'B'则跟$j--的元素交换,如果$j--的元素值和$p对应的数组元素值相同,则继续$j--,直到$arr[$j]跟 $arr[$p]不同,前提是$p < $j

    如果是$arr[$p] == 'R',则跟$i ++ 后的数组元素值交换,如果$arr[$i] == $arr[$p] 则不交换,$p++

     4、斐波那契数列的优化算法

    斐波那契数列:1、1、2、3、5、8、13、21。。。规律就是从第三个数开始的每一个数等于前面2个数之和。

     一般来说,递归的算法:

    1 <?php
    2 function fibonacci(int $n) {
    3   if($n <= 2) {
    4        return 1;
    5   }
    6   return fibonacci($n-2) + fibonacci($n-1);
    7 }

    上面的算法,用到了2层递归,所以效率上并不是最优的,有没有更优的办法?

    【思路】用空间换时间,

    参考:https://blog.csdn.net/u010183728/article/details/81238401

    https://blog.csdn.net/weixin_40170902/article/details/80835750  动态规划

     1 <?php
     2 function fibonacci(int $n) {
     3   if($n <= 2) {
     4        return 1;
     5   }
     6   $f = 0;
     7   $g = 1;
     8   $result = 0;
     9   for($i = 1; $i < $n; $i++) {
    10     $result = $f + $g;
    11     $f = $g;
    12     $g = $result;
    13   }
    14   return $result;
    15 }

    以$n = 3来解析下上面的算法的执行过程:

    1)当$i=1时, $result = 0+1 = 1 ; $f = 1; $g=1;

    2)  当$i=2时,$result = 1+1 = 2;

    3)  当$i=3时,for循环没有执行,所以,最终$result的值就是2

     【总结】空间换时间,$f 和 $g保存 前面的2个数的值, $result = 前面2个数之和。

  • 相关阅读:
    [Everyday Mathematics]20150208
    [Everyday Mathematics]20150207
    [Everyday Mathematics]20150206
    数学基本技艺100题
    这天,白云酒楼里来了两位客人
    [Everyday Mathematics]20150205
    [Everyday Mathematics]20150204
    数学书籍阅读
    国科金发计〔2014〕86号
    [Everyday Mathematics]20150203
  • 原文地址:https://www.cnblogs.com/guangye/p/11965913.html
Copyright © 2020-2023  润新知