【编程的乐趣-用python解算法谜题系列】谜题一 保持一致
谜题一 保持一致
谜题
假设有一大群人排队等待观看棒球比赛。他们都是主场球迷,每个人都戴着队帽,但不是所有人都用同一种戴法,有些人正着戴,有些人反着戴。
假定你是保安,只有在全组球迷帽子戴法一致时才能让他们进入球场,要么全部正着戴,要么全部反着戴。因为每个人对正戴和反戴的定义并不相同。因此你不能对他们说把帽子正着戴或反着戴,只能告诉他们转一下帽子。
举个栗子(我们用 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解算法谜题系列】谜题一 保持一致的更多相关文章
- 大牛推荐的30本经典编程书籍,从Python到前端全系列。
注:为了方便阅读与收藏,我们也制作了30本书籍完整清单的Markdown.PDF版以及思维导图版,大家可以在实验楼公众号后台回复关键字"书籍推荐"获取. Python 系列(10本 ...
- python解无忧公主的数学时间编程题001.py
python解无忧公主的数学时间编程题001.py """ python解无忧公主的数学时间编程题001.py http://mp.weixin.qq.com/s?__b ...
- python基础课程_学习笔记26:编程的乐趣
编程的乐趣 编程柔术 当你坐下来,打算如何组织计划要定时,具体程序,然而,无论什么经验.在实现时间的函数的,你会逐渐学会了原来的设计,实用的新知识.我们不应该忽视沿途汲取的教训,相反,它们用于其他设计 ...
- Python聚类算法之基本K均值实例详解
Python聚类算法之基本K均值实例详解 本文实例讲述了Python聚类算法之基本K均值运算技巧.分享给大家供大家参考,具体如下: 基本K均值 :选择 K 个初始质心,其中 K 是用户指定的参数,即所 ...
- python 排序算法总结及实例详解
python 排序算法总结及实例详解 这篇文章主要介绍了python排序算法总结及实例详解的相关资料,需要的朋友可以参考下 总结了一下常见集中排序的算法 排序算法总结及实例详解"> 归 ...
- python 解压 压缩包
转 http://m.blog.csdn.net/blog/wice110956/26597179# 这里讨论使用Python解压如下五种压缩文件: .gz .tar .tgz .zip .rar ...
- Python猫荐书系列之五:Python高性能编程
稍微关心编程语言的使用趋势的人都知道,最近几年,国内最火的两种语言非 Python 与 Go 莫属,于是,隔三差五就会有人问:这两种语言谁更厉害/好找工作/高工资…… 对于编程语言的争论,就是猿界的生 ...
- Scala进阶之路-面向对象编程之类的成员详解
Scala进阶之路-面向对象编程之类的成员详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Scala中的object对象及apply方法 1>.scala 单例对象 ...
- python解压压缩包的几种方法
这里讨论使用Python解压例如以下五种压缩文件: .gz .tar .tgz .zip .rar 简单介绍 gz: 即gzip.通常仅仅能压缩一个文件.与tar结合起来就能够实现先打包,再压缩. ...
随机推荐
- 使用rapidjson把文本json数据解析到树状结构
一个递归搞定 无聊的时候练练手就写了一个 头文件什么的我就不贴了 demo程序是MFC写的 void ParseObject(rapidjson::Value dc, CTreeCtrl * pTre ...
- 【简要题解】Hihocoder 重复旋律1-9简要题解
[简要题解]Hihocoder 重复旋律1-8简要题解 编号 名称标签 难度 1403 后缀数组一·重复旋律 Lv.4 1407 后缀数组二·重复旋律2 Lv.4 1415 后缀数组三·重复旋律3 L ...
- 洛谷$P3227\ [HNOI2013]$切糕 网络流
正解:网络流 解题报告: 传送门! 日常看不懂题系列,,,$QAQ$ 所以先放下题目大意趴$QwQ$,就说有个$p\cdot q$的矩阵,每个位置可以填一个$[1,R]$范围内的整数$a_{i,j}$ ...
- 「P5004」专心OI - 跳房子 解题报告
题面 把\(N\)个无色格子排成一行,选若干个格子染成黑色,要求每个黑色格子之间至少间隔\(M\)个格子,求方案数 思路: 矩阵加速 根据题面,这一题似乎可以用递推 设第\(i\)个格子的编号为\(i ...
- web前端安全——常见的web攻击方法
面试题:你所了解的web攻击? 1.xss攻击 2.CSRF攻击 3.网络劫持攻击 4.控制台注入代码 5.钓鱼 6.DDoS攻击 7.SQL注入攻击 8.点击劫持 一.xss攻击 XSS攻击:跨站脚 ...
- nginx配置项。
一,用于调试进程,定位问题的配置项. (1)是否以守护进程方式运行nginx语法:daemon on | off:默认是on,daemon是脱离终端并且在后台运行的进程,off是关闭守护进程的模式 ...
- 【Springboot】注解@ConfigurationProperties让配置整齐而简单
1 简介 前面我们用一篇文章<[Spring]只想用一篇文章记录@Value的使用,不想再找其它了(附思维导图)> 详细讲解了在Spring中如何使用@Value来实现我们对配置的需求,它 ...
- 网络、TCP协议与UDP协议
1.网络模型 (1)什么是网络模型 网络编程的本质是两个设备之间的数据交换,当然,在计算机网络中,设备主要指计算机.数据传递本身没有多大的难度,不就是把一个设备中的数据发送给两外一个设备,然后接受另外 ...
- 详细解析Java虚拟机的栈帧结构
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货. 什么是栈帧? 正如大家所了解的,Java虚拟机的内存区域被划分为程序计数器.虚拟机栈.本地方法栈.堆和方法区.(什么?你还不知道,赶紧去看看 ...
- Scala实践8
1.1继承类 使用extends关键字,在定义中给出子类需要而超类没有的字段和方法,或者重写超类的方法. class Person { var name = "zhangsan" ...