Description:

有2n个硬币和一个天平,其中有一个质量是m+1, 另一个硬币质量为m-1, 其余的硬币质量都是m。

要求:O(lgn)时间找出两枚假币

注意: n不一定是2的幂次方

算法1:O(n)算法

将2n个硬币分成n组(每组2个)进行称量:

结果只有两种: 1. 仅有一组出现天平不平衡: 一定就是 两个假币

2. 出现两组天平不平衡: 这四个硬币中必定存在两个假币。将重的硬币称量,轻的两个硬币称量得到结果。

算法2: O(lgn)算法 分治

首先假设n是2的幂次方(如果不是,则可以加入新的真币,使得硬币数目是2的幂次方)

第一步: 对所有的硬币编号, 从0到2n-1

第二步: 由于2n是2的幂次方,假设2n的二进制表示有lgn位

for i=0, lgn;

根据二进制表示第i位是否为0,或1

将 2n个硬币分成两个数目为n的集合,放到天平的两边;

if 天平不平衡, break;

end for;

注意: 由于两个假币的编号不同,所以它们的二进制表示必定某一位不同,不妨设为第k位

第三步: 我们得到了两堆数目都是n的硬币集合, 注意此时两个假币已经分开

用O(lgn)的分治算法在两堆硬币中分别求出假币

如果n不是2的幂次方,注入真币,使得数目为2的幂次方。

下面证明注入的真币数目一定不超过2n

假设 2^k < 2n < 2^(k+1)

加入的真币数目= 2^(k+1) - 2n < 2^(k+1) - 2^k = 2^k < 2n

结论, 加入硬币后,总硬币数不超过4n,所以复杂度仍旧是O(lgn)



算法三: 并不需要通过加硬币, 也能O(lgn)找出假币

n不是2的幂次方的问题在于: 根据2进制数某一位1,0分成2堆硬币,可能出现数目不等的情况。

第1位: 该二进制位为1的堆 和 为0的堆 数目至多相差1(编号是奇数和偶数的硬币数至多相差1个)

             做法: 从多的那堆中 丢掉 编号最大的硬币!!!

                        1. 因为丢了以后,

                                     天平若平衡:则丢掉的一定是真币。

                                      反之,则不能确定。

                             这样最终我们得到3堆硬币,两堆就是天平上不平衡的两堆,第三堆就是算法过程中被我们丢掉的一堆。两枚假币必定在三堆硬币中,而且已经被分开。O(lgn)找出3堆硬币中各自的假币(注意,虽然有一堆没有假币,但是算法还是会得到一个结果,当然它是真币)。

然后 3枚硬币天平称两次,最重的和最轻的就是假币

                        2. 为什么丢编号最大的硬币呢? 其实为了保证下一步时 两堆硬币数同样具有最多相差1的性质

因此,可以像算法2一样,用 O(lgn)时间把 两枚假币 分开。。再用O(lgn)找出假币即可。。。

PS: 多谢女朋友的指点,忽然想到这个算法原来可以不用“加硬币”的方法,也可解决。。

算法题----称硬币: 2n(并不要求n是2的幂次方)个硬币,有两个硬币重量为m+1, m-1, 其余都是m 分治 O(lgn)找出假币的更多相关文章

  1. 笔试算法题(18):常数时间删除节点 & 找到仅出现一次的两个数字

    出题:给定链表的头指针和一个节点指针,要求在O(1)的时间复杂度下删除该节点 分析: 如果需要删除的节点为A,其前序节点为A-,其后续节点为A+,所以删除A之后,需要使得A-的下一个节点就是A+,常规 ...

  2. 两个有序数组长度分别为m,n,最多m+n次查找找出相同的数

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  3. 一个整型数组里除了一个数字之外,其他的数字都出现了两次。要求时间复杂度是O(n),空间复杂度是O(1),如何找出数组中只出现一次的数字

    思路分析:任何一个数字异或它自己都等于0,根据这一特性,如果从头到尾依次异或数组中的每一个数字,因为那些出现两次的数字全部在异或中抵消掉了,所以最终的结果刚好是那些只出现一次的数字. 代码如下: #i ...

  4. fcc的中级算法题

    核心提示:这是网上开源编程学习项目FCC的javascript中级编程题(Intermediate Algorithm Scripting(50 hours)),一共20题.建议时间是50个小时,对于 ...

  5. leetcode算法题整理

    一.线性表,如数组,单链表,双向链表 线性表.数组 U1.有序数组去重,返回新数组长度 A = [1,1,2] -> [1,2] 返回2   分析:其实一般数组的问题都可以用两个指针解决,一个指 ...

  6. LeetCode算法题-Power of Four(Java实现-六种解法)

    这是悦乐书的第205次更新,第216篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第72题(顺位题号是342).给定一个整数(带符号的32位),写一个函数来检查它是否为4 ...

  7. LeetCode算法题-Power Of Three(Java实现-七种解法)

    这是悦乐书的第204次更新,第215篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第71题(顺位题号是326).给定一个整数,写一个函数来确定它是否为3的幂.例如: 输入 ...

  8. FCC上的javascript算法题之中级篇

    FCC中的javascript中级算法题解答 中级算法的题目中用到了很多js的知识点,比如迭代,闭包,以及对json数据的使用等等,现在将自己中级算法的解答思路整理出来供大家参考讨论.欢迎大家提出新的 ...

  9. [PHP] 算法-找出两个链表的第一个公共结点的PHP实现

    输入两个链表,找出它们的第一个公共结点 1.两个单链表,有公共结点,那么必然,尾部公用 2.找出链表1的长度,找出链表2的长度,长的链表减去短的链表得出一个n值 3.长的链表先走n步,两个链表再同时移 ...

随机推荐

  1. 【Linux】rpm -qa 和 rpm -q

    查询一个包是否被安装 # rpm -q < rpm package name>列出所有被安装的rpm package # rpm -qae.g. rpm -qa|grep "pc ...

  2. C# winform程序怎么打包成安装项目(图解)

    1:新建安装部署项目 打开VS,点击新建项目,选择:其他项目类型->安装与部署->安装向导(安装项目也一样),然后点击确定.(详细见下图) 此主题相关图片如下: 2:安装向导 关闭后打开安 ...

  3. 整理的一些模版LCS(连续和非连续)

    对于连续的最大串,我们称之为子串....非连续的称之为公共序列.. 代码: 非连续连续 int LCS(char a[],char b[],char sav[]){ int lena=strlen(a ...

  4. hashtable 实现

    #include <stdlib.h> #include <stdio.h> #include <string.h> typedef struct _hashnod ...

  5. 《精通javascript》几个简单的函数

    转载http://www.cnblogs.com/jikey/archive/2011/07/25/2116696.html /** * 隐藏元素 * @param {String} elem */f ...

  6. JS禁止右键

    function cancelMouse(){return false;}document.oncontextmenu = cancelMouse;

  7. Java 集合系列 01 总体框架

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  8. 7月13日微软MVP社区夏日巡讲北京站活动现场图集

    1.活动签到 2.活动准备工作,到场同学很多. 3.讲师讲桌 全体合影,由于我在楼下签到所以里面没有我:(  

  9. Oracle 中的 decode

    含义解释:decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) 该函数的含义如下:IF 条件=值1 THEN RETURN(翻译值1)ELSIF 条件=值2 THEN R ...

  10. POJ 3249 拓扑排序+DP

    貌似是道水题.TLE了几次.把所有的输入输出改成scanf 和 printf ,有吧队列改成了数组模拟.然后就AC 了.2333333.... Description: MR.DOG 在找工作的过程中 ...