快速排序里的学问:从猜数字开始 猜数字里的算法思想

我们先来玩一个猜数字游戏:

我心里默念一个1~64之间的数,你来猜(你只能问答案是“是”或“否”的问题)。为了保证不论在什么情况下都能以尽量少的次数猜中,你应该采取什么策略呢?

很显然,二分。先是猜是不是位于1~32之间,排除掉一半可能性,然后对区间继续二分。这种策略能够保证无论数字怎么跟你捉迷藏,都能在log2n次以内猜中。用算法的术语来说就是它的下界是最好的。(算法的下界 :一个问题的下界是用来解决该问题的任意算法所需要的最小时间复杂度。 )

我们再来回顾一下这个游戏所蕴含的本质:为什么这种策略具有最优下界?

答案也很简单,这个策略是平衡的。反之如果策略不是平衡的,比如问是不是在1~10之间,那么一旦发现不是在1~10之间的话就会剩下比N/2更多的可能性需要去考察了。

这种策略的本质可以概括成“让未知世界无机可乘”。它是没有“弱点的”,答案的任何一个分支都是等概率的。反之,一旦某个分支蕴含的可能性更多,当情况落到那个分支上的时候你就郁闷了。比如猜数字游戏最糟糕的策略就是一个一个的猜:是1吗?是2吗?… 因为这种猜法最差的情况下需要64次才能猜对,下界非常糟糕。二分搜索为什么好,就是因为它每次都将可能性排除一半并且无论如何都能排除一半(它是最糟情况下表现最好的)。

猜数字的时间复杂度

猜数字的时间复杂度其实就是二分查找的复杂度。

二分查找的基本思想是将n个元素分成大致相等的两部分,然后用a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止;如果x < a[n/2],则只要在数组a的左半部分继续搜索x,如果x>a[n/2],则只要在数组a的右半部搜索x。

所以二分查找的时间复杂度无非就是while循环的次数。

我们可以跟着循环去想。总共有n个元素,跟下去就是n, n/2, n/4, ...., n/2k,其中k就是循环的次数。

每比较一次,查找范围被缩短为原来1/2,当范围长度被缩短为1的时候,就完成查找了,然后要比较多少次,高中时的数学问题了。

另 n/2k = 1,即 2k = n,所以 k = log2n。

k 为次数,时间复杂度可以表示O()=O(logn)。

延伸阅读

此文章所在专题列表如下:

  1. 快速排序里的学问:从猜数字开始
  2. 快速排序里的学问:再看看称球问题
  3. 快速排序里的学问:信息熵
  4. 快速排序里的学问:快速排序的过程
  5. 快速排序里的学问:霍尔与快速排序
  6. 快速排序里的学问:霍尔快排的实现
  7. 快速排序里的学问:枢纽元选择与算法效率
  8. 快速排序里的学问:随机化快排
时间: 2024-12-17 16:55:25

快速排序里的学问:从猜数字开始 猜数字里的算法思想的相关文章

快速排序里的学问:枢纽元选择与算法效率

选择首尾元素做枢纽元 通常的.没有经过充分考虑的选择是将第一个或最后一个元素用作枢纽元.选择第一个元素作为枢纽元的程序例子可以参考专题的前一篇<快速排序里的学问:霍尔快排的实现>,而选择最后一个元素用作枢纽元的程序例子则可以参考<快速排序里的学问:快速排序的过程>这个算法导论里的例子. 选择最后一个元素作为枢纽元的排序过程是这样的: 如果输入是随机的,那么这是可以接受的,但是如果输入是预排序的或者是反序的,那么这样的枢纽元就产生一个劣质的分割,因为所有的元素不是被划入S1就是被划入

数字51在域名里有什么含义吗? 为什么叫51cto

数字51在域名里有什么含义吗? 为什么叫51cto

(hdu step 4.1.8)猜数字(求n次所能猜到的最大数字)

题目: 猜数字 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 318 Accepted Submission(s): 247   Problem Description A有1数m,B来猜.B每猜一次,A就说"太大","太小"或"对了" . 问B猜n次可以猜到的最大数. Input 第1行是

在虚拟机里安装centos 6.4和centos 5.8里配置vim 7.4安装过程

下是centos 6.4里安装vim配置操作命令 [BEGIN] 2014/5/13 星期二 上午 10:08:54 [[email protected] ~]# rpm -qa | grep vim [[email protected] ~]# yum remove vim vim-enhanced vim-common vim-minimal [[email protected] ~]# wget ftp://ftp.vim.org/pub/vim/unix/vim-7.4.tar.bz2

(二)数字证书和数字时间戳

一.证书 概要 证书是一个[经证书认证中心数字签名的]包含[公开密钥拥有者信息以及公开密钥的文件].证书格式及证书内容遵循X.509标准. 从证书的用途来看,数字证书分为签名证书和加密证书. a)         签名证书主要用于对用户信息进行签名,以保证信息的不可否认性(身份认证): b)         加密证书主要用于对用户传送信息进行加密,以保证信息的真实性和完整性(传输加密). 目前最安全的数字证书是由第三方 CA 机构(比如 GlobalSign)认证的数字证书,数字证书保存在[经国

61. 从1到n,共有n个数字,每个数字只出现一次。从中随机拿走一个数字x,请给出最快的方法,找到这个数字。如果随机拿走k(k&gt;=2)个数字呢?[find k missing numbers from 1 to n]

[本文链接] http://www.cnblogs.com/hellogiser/p/find-k-missing-numbers-from-1-to-n.html  [题目] 从1到n,共有n个数字(无序排列),每个数字只出现一次.现在随机拿走一个数字x,请给出最快的方法,找到这个数字.要求时间复杂度为O(n),空间复杂度为O(1).如果随机拿走k(k>=2)个数字呢? [分析] 题目给出的条件很强,数字是从1~n的数字,限制了数字的范围:每个数字只出现一次,限制了数字出现的次数:随即拿走了一

oracle 非数字型转数字型

原文:oracle 非数字型转数字型 oracle中如果一个字段内容不全是数字型 可以通过以下方式过滤 to_number(substr(translate(a.vital_signs_cvalues, '9876543210.' || a.vital_signs_cvalues, '9876543210.'), 1, instr(translate(a.vital_signs_cvalues, '9876543210.' || a.vital_signs_cvalues, '987654321

几个有用的javascript(日期比较,数字验证,数字和汉字长度计算)

1:日期大Js代码 Js代码   //人员失效职位日期是否小于组织失效日期 function perDateInvalidate(){ var flag = true; //组织失效日期 var orgDate = stringToTime(document.getElementById("orgDate").value); //人员失效日期 var personDate = stringToTime(document.getElementById("personDate&q

将数字字符串转为数字(java)

1 //讲数字字符串转为数值型(此处不考虑输入字符串的合法性),不允许使用parseInt方法和Character.digit 2 public class ConvertNumstr { 3 public static void main(String[] args) { 4 System.out.print(convertStr2Num("-2015")); 5 } 6 public static int convertStr2Num(String str) { 7 int len