在平时找工作的时候,或多或少会遇到一些算法问题,很多都是比较经典或者网上已经流传很久的。只是我们没有接触过,所以不知道怎么解决。

  在这儿,我自己总结一些我遇到的一些经典算法,给自己增加一点记忆,也给需要的朋友看到学习一下。

1. 倒水问题

如题:一个容量为5升的杯子和一个容量为3升的杯子,水不限使用,要求精确得到4升水。

  这类题一般会有两种出题方式:

  A.简答

    这儿先给出简答的答案:其实结果又很多种,这儿给出倒水次数最少的一种。

    

  B.编程实现

    解法也比较多,我首先想到的DFS(深度优先)搜索,每次我们有6种选择,只要不断的尝试下去,总可以搜索完所有的状态,找到一个解。也可以用宽度优先搜索(BFS)。

  程序代码后续补上。

  后续也有其他版本的倒水问题,如:有三个容器,分别为20升,13升,7升。20升的容器装满水,要使20升和13升的容器里分别装10水,如何做到?

    简答的步骤和前面类似:

    

2.猴子选大王问题

题目:

n只猴子围坐成一个圈,按顺时针方向从1到n编号。
然后从1号猴子开始沿顺时针方向从1开始报数,报到m的猴子出局,再从刚出局猴子的下一个位置重新开始报数,
如此重复,直至剩下一个猴子,它就是大王。

设计并编写程序,实现如下功能:
(1)   要求由用户输入开始时的猴子数$n、报数的最后一个数$m。
(2)   给出当选猴王的初始编号。

这个题直接想到的就是循环链表实现,或者数组实现。

下面直接贴出代码:

 解法1:

 <?php
$arr = array('1','2','3','4','5','6','7');//示例数组
echo '<pre>The King is :<br/>';
print_r(king($arr,11));
function king($arr,$count){
$i = 1;//从1开始
while(count($arr) > 1){
if($i%$count == 0){//用求余,计算数到的位,如果求余为0,所数到的位消除,压出数组中
unset($arr[$i-1]);
}else{//数到的位不是结束,把这一位放到数组末尾,并消掉这个位
array_push($arr,$arr[$i-1]);
unset($arr[$i-1]);
}
$i++;//转移到下一个数组元素
15   }
return $arr;
}

这种实现方式是使用数组,如果当前数不是选中的,则将其移到数组最后。算法复杂度较高,当数据量较大时,处理效率低。

解法2:

 /**
*
* @param int $n
* 开始时的猴子数量
* @param int $m
* 报道的最后一个数
* (报到这个数的猴子被淘汰,然后下一个猴子重新从①开始报数)
* @return int 猴子的初始编号
*/
function monkeySelectKing($n, $m)
{
// 猴子的初始数量不能小于2
if ($n < 2) {
return false;
} $arr = range(1, $n);
// 将猴子分到一个数组里, 数组的值对应猴子的初始编号
$unsetNum = 0;
// 定义一个变量,记录猴子的报数 for ($i = 2; $i <= $n * $m; $i ++)
// 总的循环次数不知道怎么计算,
{
// 不过因为循环中设置了return,所以$m*$len效率还可以
foreach ($arr as $k => $v) {
$unsetNum ++; // 每到一个猴子, 猴子报数+1 // 当猴子的报数等于淘汰的数字时:淘汰猴子(删除数组元素)
// 报数归0(下一个猴子从1开始数)
if ($unsetNum == $m) {
// echo "<pre>";//打开注释,可以看到具体的淘汰过程
// print_r($arr);
unset($arr[$k]);
// 淘汰猴子
$unsetNum = 0;
// 报数归零
if (count($arr) == 1)
// 判断数组的长度, 如果只剩一个猴子, 返回它的值
{
return reset($arr);
}
}
}
}
} var_dump(monkeySelectKing(100, 2));

这种算法实现的复杂度为O(nm);当nm比较大时,这个效率就比较低。

更简单的实现方式:也叫约瑟夫环的数学解法

原理

无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。我们注意到原问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程。因此如果要追求效率,就要打破常规,实施一点数学策略。
为了讨论方便,先把问题稍微改变一下,并不影响原意:

  问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。

  我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始):
      k  k+1  k+2  ... n-2, n-1, 0, 1, 2, ... k-2
  并且从k开始报0。

现在我们把他们的编号做一下转换:
k     --> 0
k+1   --> 1
k+2   --> 2
...
...
k-2   --> n-2
k-1   --> n-1

变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x'=(x+k)%n

如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的情况 ---- 这显然就是一个倒推问题!好了,思路出来了,下面写递推公式:

令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]

递推公式
f[1]=0;
f[i]=(f[i-1]+m)%i;  (i>1)

有了这个公式,我们要做的就是从1-n顺序算出f[i]的数值,最后结果是f[n]。因为实际生活中编号总是从1开始,我们输出f[n]+1

最后得出的解法就是:

 /**
* 约瑟夫环的数学解法
*/
function yuesefu($n,$m) {
$r=0;
for($i=2; $i<=$n; $i++) { $r=($r+$m)%$i;
}
return $r+1;
}
print_r(yuesefu(100,2));

有关约瑟夫环的数学解法来自于:http://www.cppblog.com/Victordu/archive/2008/02/22/43082.html

经典算法mark的更多相关文章

  1. Java中的经典算法之冒泡排序(Bubble Sort)

    Java中的经典算法之冒泡排序(Bubble Sort) 神话丿小王子的博客主页 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一 ...

  2. Atitit 图像处理30大经典算法attilax总结

    Atitit 图像处理30大经典算法attilax总结 1. 识别模糊图片算法2 2. 相似度识别算法(ahash,phash,dhash)2 3. 分辨率太小图片2 4. 横条薯条广告2 5. 图像 ...

  3. Java中的经典算法之选择排序(SelectionSort)

    Java中的经典算法之选择排序(SelectionSort) 神话丿小王子的博客主页 a) 原理:每一趟从待排序的记录中选出最小的元素,顺序放在已排好序的序列最后,直到全部记录排序完毕.也就是:每一趟 ...

  4. JS的十大经典算法排序

    引子 有句话怎么说来着: 雷锋推倒雷峰塔,Java implements JavaScript. 当年,想凭借抱Java大腿火一把而不惜把自己名字给改了的JavaScript(原名LiveScript ...

  5. PHP经典算法

    php经典算法 .冒泡算法,排序算法,由于在排序过程中总是小数往前放,大数往后放,相当于气泡往上升,所以称作冒泡排序 $array = array(a,f,c,b,e,h,j,i,g); functi ...

  6. JAVA经典算法40题及解答

    JAVA经典算法40题 [程序1]   题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第四个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 1.程序分 ...

  7. (转)白话经典算法系列之八 MoreWindows白话经典算法之七大排序总结篇

    在我的博客对冒泡排序,直接插入排序,直接选择排序,希尔排序,归并排序,快速排序和堆排序这七种常用的排序方法进行了详细的讲解,并做成了电子书以供大家下载.下载地址为:http://download.cs ...

  8. Java经典算法四十例编程详解+程序实例

    JAVA经典算法40例 [程序1]   题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第四个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?   1.程 ...

  9. 机器学习经典算法详解及Python实现--基于SMO的SVM分类器

    原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector  ...

随机推荐

  1. Hibernate 之 HQL

    通过对Hibernate框架的学习,已经慢慢的对Hibernate有了进一步的了解,接下来我们要说的是HibernateQusery Language(HQL),如果你正在学习SSH框架,那SQL对你 ...

  2. GEO,IGSO,MEO,LEO

    GEO(Geosynchronous Eearth Orbit):地球静止轨道卫星 IGSO(Inclined Geosynchronous Satellite Orbit):倾斜轨道同步卫星 地球同 ...

  3. YTU 2412: 帮警长数一数【循环、分支简单综合】

    2412: 帮警长数一数[循环.分支简单综合] 时间限制: 1 Sec  内存限制: 64 MB 提交: 323  解决: 169 题目描述 黑猫警长在犯罪现场发现了一些血迹,现已经委托检验机构确定了 ...

  4. java 泛型的理解与应用

    为什么使用泛型? 举个例子: public class GenericTest { public static void main(String[] args) { List list = new A ...

  5. java web框架收集

    一.前端框架: 1.vue.js 2.angular.js 二.后端框架: 1.struts2 2.springmwc 三.数据库映射框架: 1.hibernate 2.mybatis 四.数据库: ...

  6. 搭建CARDBOARD+ANDROID+unity3d的VR开发环境

    一.下载最新unity3d(u3d官网) 二.下载最新cardboardsdkforunity(https://github.com/googlesamples/cardboard-unity) 三. ...

  7. 金融事业部QA培训体系

    此文已由作者夏君授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 引言     总结2015,放眼2016,纵观整个互联网圈,人才依然是业务成功的第一要素,在网易,我想也是这样 ...

  8. 大神是怎样用函数式JavaScript计算数组平均值的

    译者按: 有时候一个算法的直观.简洁.高效是需要作出取舍的. 原文: FUNCTIONAL JAVASCRIPT: FIVE WAYS TO CALCULATE AN AVERAGE WITH ARR ...

  9. 洛谷P4141消失之物(背包经典题)——Chemist

    题目地址:https://www.luogu.org/problemnew/show/P4141 分析:这题当然可以直接暴力枚举去掉哪一个物品,然后每次暴力跑一遍背包,时间复杂度为O(m*n^2),显 ...

  10. 面试杂谈:面试程序员时都应该考察些什么?<转>

    一般来说,一线成熟企业技术岗位的典型招聘流程分为以下几个步骤: 初筛:一般由直接领导的技术经理或HR进行,重点考察教育和工作经历 一面:一般由可能直接与之共事的工程师进行,重点考察基础和工作能力 二面 ...