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个数之和。