谜题一 保持一致

谜题

假设有一大群人排队等待观看棒球比赛。他们都是主场球迷,每个人都戴着队帽,但不是所有人都用同一种戴法,有些人正着戴,有些人反着戴。

假定你是保安,只有在全组球迷帽子戴法一致时才能让他们进入球场,要么全部正着戴,要么全部反着戴。因为每个人对正戴和反戴的定义并不相同。因此你不能对他们说把帽子正着戴或反着戴,只能告诉他们转一下帽子。

举个栗子(我们用 F 表示正戴,B 表示反戴)

F F B B B F B B B F F B F

上面是一个13人的队伍,位置从0 ~ 12。你可以发出以下指令:

请 0 号位置的人转一下帽子,

请 1 号位置的人转一下帽子,

......

然后分别对5,9,10,12号位置的人发出同样的指令,总共要发出六次指令。

我们也可以发出这样的指令:

请 2~4 号位置的人转一下帽子,

请 6~8号位置的人转一下帽子,

请 11 号位置的人转一下帽子。

只需要 3 次指令。

我们的要求是让保安生成的命令数最少。难度更大的问题是:能否第一次沿着队伍就得正确答案呢?

算法

算法一 寻找想法相同的连续人员

计算正戴区间和反戴区间的个数, 区间数更少的即是我们要反转的帽子区间。

def pleaseconform(caps):
section = [] # 统计各区间的列表
start = 0
Fnum = 0 # 正戴区间数
Bnum = 0 # 反戴区间数
for i in range(1,len(caps)):
if caps[start] != caps[i]: # 标志着新区间的产生
section.append([start , i-1 ,caps[start]])
if caps[start]=='F':
Fnum += 1
else:
Bnum += 1
start = i
section.append([start,len(caps)-1,caps[start]]) # 6~13行代码未添加最后一个区间,这行代码用于添加最后一个区间
if caps[start]=='F':
Fnum += 1
else:
Bnum +=1
if Fnum>Bnum :
flag = 'B'
else:
flag = 'F'
for t in section:
if t[2]==flag:
if(t[0] == t[1]):
print("请"+str(t[0])+"号位置的人反转帽子")
else:
print("请"+str(t[0])+"到"+str(t[1])+"的人反转帽子") caps = ['F','F','B','B','B','F','B','B','B','F','F','B','F']
pleaseconform(caps) """
Output:
请2到4的人反转帽子
请6到8的人反转帽子
请11号位置的人反转帽子
"""
  • 我们注意到算法一的核心代码 6~13 行未添加最后一个区间,因此我们要再添加代码来完善算法,显得过于繁琐。实际上,我们只需要在 caps 列表添加一个其他元素如'M',就可以消除掉这种情况。
# 代码优化
def pleaseconform(caps):
caps.append('M')
section = []
start = 0
Fnum = 0
Bnum = 0
for i in range(1,len(caps)):
if caps[start] != caps[i]:
section.append([start , i-1 ,caps[start]])
if caps[start]=='F':
Fnum += 1
else:
Bnum += 1
start = i
if Fnum>Bnum :
flag = 'B'
else:
flag = 'F'
for t in section:
if t[2]==flag:
if(t[0] == t[1]):
print("请"+str(t[0])+"号位置的人反转帽子")
else:
print("请"+str(t[0])+"到"+str(t[1])+"的人反转帽子") caps = ['F','F','B','B','B','F','B','B','B','F','F','B','F']
pleaseconform(caps) """
Output:
请2到4的人反转帽子
请6到8的人反转帽子
请11号位置的人反转帽子
"""
算法二 单遍算法one pass

通过观察,实际上我们只需要通过 caps 列表中第一只帽子的方向,就可以得出我们需要反转的是正戴区间还是反戴区间。因为第一只帽子方向区间的个数一定大于等于另一方向的区间数。基于这一观察,能够实现一个one pass 算法。

# one pass
def pleaseconformonepass(caps):
caps.append(caps[0])
for i in range(1,len(caps)):
if(caps[i] != caps[i-1]):
if(caps[i] != caps[0]):
print("请"+str(i)+"号位置到")
else:
print(str(i-1)+"号位置的人反转帽子") pleaseconformonepass(caps) """
Output:
请2号位置到
4号位置的人反转帽子
请6号位置到
8号位置的人反转帽子
请11号位置到
11号位置的人反转帽子
"""

谜题背后

这道谜题背后的出发点是数据压缩。向同一方向的人发出的命令信息是相同的,可以被压缩为一组较少的命令,其中每一条命令指挥一组连续的人。

谜题拓展

数据压缩有多种实现方式,在思路上接近于这道习题的一种算法叫做游程编码。举一个最简单的例子最容易描述,假设有以下字符串:

WWWWWWWWWWWWWBBWWWWWWWWWWWWBBBBB

使用游程编码算法,我们可以把上述字符串压缩为一个由数字和字符构成的字符串:

13W2B12W5B

游程解码算法就是把' 13W2B12W5B '解压为原始字符串的过程。

现代计算机的压缩工具,便是利用了这种思想相关的算法。

以下是游程编码解码的具体实现:

def youcengbianma(string):
start=0
newstring = ''
for i in range(1,len(string)):
if(string[start]!=string[i]):
newstring += str(i-start)
newstring += string[start]
start=i
newstring += str(i-start+1)
newstring += string[start]
return newstring print(youcengbianma("wwweeewwwweeffeee")) """
Output:
3w3e4w2e2f3e
""" def youcengjiema(string):
num = ''
newstring = ''
for i in range(0,len(string)):
if(not string[i].isalpha()): # isalpha() 如果是字母字符,返回true
num += string[i]
else:
for j in range(0,int(num)):
newstring += string[i]
num = ''
return newstring print(youcengjiema("3w3e4w2e2f3e") """
Output:
wwweeewwwweeffeee
"""

【编程的乐趣-用python解算法谜题系列】谜题一 保持一致的更多相关文章

  1. 大牛推荐的30本经典编程书籍,从Python到前端全系列。

    注:为了方便阅读与收藏,我们也制作了30本书籍完整清单的Markdown.PDF版以及思维导图版,大家可以在实验楼公众号后台回复关键字"书籍推荐"获取. Python 系列(10本 ...

  2. python解无忧公主的数学时间编程题001.py

    python解无忧公主的数学时间编程题001.py """ python解无忧公主的数学时间编程题001.py http://mp.weixin.qq.com/s?__b ...

  3. python基础课程_学习笔记26:编程的乐趣

    编程的乐趣 编程柔术 当你坐下来,打算如何组织计划要定时,具体程序,然而,无论什么经验.在实现时间的函数的,你会逐渐学会了原来的设计,实用的新知识.我们不应该忽视沿途汲取的教训,相反,它们用于其他设计 ...

  4. Python聚类算法之基本K均值实例详解

    Python聚类算法之基本K均值实例详解 本文实例讲述了Python聚类算法之基本K均值运算技巧.分享给大家供大家参考,具体如下: 基本K均值 :选择 K 个初始质心,其中 K 是用户指定的参数,即所 ...

  5. python 排序算法总结及实例详解

    python 排序算法总结及实例详解 这篇文章主要介绍了python排序算法总结及实例详解的相关资料,需要的朋友可以参考下 总结了一下常见集中排序的算法 排序算法总结及实例详解"> 归 ...

  6. python 解压 压缩包

    转 http://m.blog.csdn.net/blog/wice110956/26597179# 这里讨论使用Python解压如下五种压缩文件: .gz .tar  .tgz .zip .rar ...

  7. Python猫荐书系列之五:Python高性能编程

    稍微关心编程语言的使用趋势的人都知道,最近几年,国内最火的两种语言非 Python 与 Go 莫属,于是,隔三差五就会有人问:这两种语言谁更厉害/好找工作/高工资…… 对于编程语言的争论,就是猿界的生 ...

  8. Scala进阶之路-面向对象编程之类的成员详解

    Scala进阶之路-面向对象编程之类的成员详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Scala中的object对象及apply方法 1>.scala 单例对象 ...

  9. python解压压缩包的几种方法

    这里讨论使用Python解压例如以下五种压缩文件: .gz .tar  .tgz .zip .rar 简单介绍 gz: 即gzip.通常仅仅能压缩一个文件.与tar结合起来就能够实现先打包,再压缩. ...

随机推荐

  1. ulimit -u 解决 Jenkins OOM 错误

    Apr 24, 2018 11:19:48 AM hudson.init.impl.InstallUncaughtExceptionHandler$DefaultUncaughtExceptionHa ...

  2. 【小技巧】object上显示div

    这个现在不大常用了,就是object在页面中显示的优先级最高,其他层想覆盖在其上面,设置的z-index再高都不管用,解决办法是在层中加一个iframe.不多说了,直接记录下代码吧,估计以后用到的机率 ...

  3. TemplateMethodPattern(模板方法模式)-----Java/.Net

    一个抽象类公开定义了执行它的方法的方式/模板.它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行.这种类型的设计模式属于行为型模式

  4. Intellij IDEA 导入eclipse 项目

    HoJe一个会rep的程序猿 . 感谢2019 时间匆匆,一转眼2019要跟我们说再见了.我们怀有太多的期望就难免遭遇失望和挫折.我们遇到了困难,往往不是想办法去解决,而是抱怨这个命运的不公.如果生活 ...

  5. 小白学 Python 爬虫(37):爬虫框架 Scrapy 入门基础(五) Spider Middleware

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

  6. SQL Server2012高可用之日志传送测试

    (一)日志传送架构 (1.1)相关服务器 主服务器   :用于生产的服务器,上面运行这生产SQL Server数据库: 辅助服务器:用于存放主服务器上数据库的一个“镜像”数据库: 监控服务器:用来监控 ...

  7. 搞定SpringBoot多数据源(2):动态数据源

    目录 1. 引言 2. 动态数据源流程说明 3. 实现动态数据源 3.1 说明及数据源配置 3.1.1 包结构说明 3.1.2 数据库连接信息配置 3.1.3 数据源配置 3.2 动态数据源设置 3. ...

  8. Adaboost和随机森林

    在集成学习中,主要分为bagging算法和boosting算法.随机森林属于集成学习(Ensemble Learning)中的bagging算法. Bagging和Boosting的概念与区别该部分主 ...

  9. Node: 使用nrm管理npm源

    一.简介 npm是一款非常好用的包管理工具,在前端开发中很多时候都会使用npm安装其他包文件.但是,npm安装某些包时有时会安装地很慢,这是因为npm管理的源中有些是国外的,包下载的时候需要花费很多时 ...

  10. eclipse git 解决冲突 解决 mergetool 不能使用问题

    eclipse git 解决冲突 解决 mergetool 不能使用问题 本地代码 远程代码 第一步 --> 同步远程资源库,检查是否存在冲突 这里有冲突出现 第二步 --> 如果存在冲突 ...