说明:作者已经给了各章习题1的答案,其他的习题答案我来补充下,使用语言为Python3,有问题欢迎留言。
附习题一答案:https://mitpress.mit.edu/books/programming-puzzled
点击左下角 Code for Selected Puzzle Solutions 即可下载。
1.10 习题(page11)
习题 2 修改pleaseConformOnepass,如习题1那样打印更自然一些的命令,并确保程序再输入是空列表时不会崩溃。
提示:你需要记住区间的起始位置(而不是在第6行打印)。
'''在line-opt.py上修改'''
def pleaseConformOnepass(caps):
if caps != []: #判断是否为空
caps = caps + [caps[0]]
for i in range(1, len(caps)):
if caps[i] != caps[i-1]:
if caps[i] != caps[0]:
temp = i #存储临时变量
print('People in positions', i, end='')
else:
if temp == i-1: #前后比较
print(' flip your caps!')
else:
print(' through', i-1, 'flip your caps!')
else:
print("You can't input a null list!")
难题3 假设在队伍中存在没戴帽子的人。我们用字符’H’代表他们。例如,有这样一组数据:
caps3 = [‘F’, ‘F’, ‘B’, ‘H’, ‘B’, ‘F’, ‘B’, ‘B’, ‘B’, ‘F’, ‘H’, ‘F’, ‘F’ ]
我们不想指示没戴帽子的人去转动不存在的帽子,这令人困惑,可能会导致有人试图从队伍前面的人那里偷帽子。因此我们希望跳过所有’H’位置。修改pleaseConform,使它生成正确并且最小数量的命令集合。对于上面的例子,它应当生成:
People in positions 2 flip your caps!
People in positions 4 flip your caps!
People in positions 6 through 8 flip your caps!
'''在line.py文件pleaseConform函数上修改'''
for i in range(1, len(caps)):
if caps[start] != caps[i]:
# each interval is a tuple with 3 elements (start, end, type)
if caps[start] == 'H': #在这边做下判断
start = i
continue
intervals.append((start, i - 1, caps[start]))
if caps[start] == 'F':
forward += 1
else:
backward += 1
start = i
习题 4 写一段程序实现简单的游程编码,将给定字符串(如BWWWWWBWWWW)转换为较短的字符串(1B5W1B4W),并且执行游程解码,将压缩过的字符串转换回原始字符串。你只能通过一次字符串遍历来执行压缩和解压缩过程。
str函数能将数字转换成字符串,例如str(12) = ‘12’。它在编码步骤汇总会很有用。
int函数能将字符串转换成数字,例如:int(‘12’) = 12。对于任意字符串s,如果s[i]是字母字符,则s[i].isalpha()将返回True,否则返回False。如果s中所有的字符都是字母字符,则s.isalpha()返回True,否则返回False。函数int和isalpha在解码步骤中会很有用。
"""
BWWWWWBWWWW ==> 1B5W1B4W
1B5W1B4W ==> BWWWWWBWWWW
"""
def encode(strs):
'''编码:每两个字符进行比较,如果不同输出前面的内容,
如果相同,开始累加,直到比较不同而输出为止,如此反复。'''
strs = strs + ' '
sum = 1
for c in strs[1:]:
if strs[0] != c:
print(sum, strs[0], sep='', end='')
sum = 1
else:
sum = sum + 1
strs = strs[1:]
print('')
def decode(strs):
'''解码:利用数字在先字母在后的特点,对处于索引偶数位的数字做记录,
对处于索引奇数位的字母做*运算'''
for n,s in enumerate(strs):
if n % 2 == 0:
num = int(s)
else:
print(s * num, end='')
n += 1
print('')
encode('BWTTTTWWBWQQQWW')
decode('1B1W4T2W1B1W3Q2W')
2.4 习题(page20)
习题 2 有另一种方法, 可以不依赖时间精度来计算参加派对的最佳时间。我们依次选择每位名人的时间区间,并确定有多少其他名人的时间区间包含所选名人的开始时间。我们选择出某位名人,使他的开始时间被最大数量的其他名人时间区间所包含,并将他的开始时间作为参加派对的时间。编写代码实现该算法,并验证它的结果与基于排序算法的结果是否相同。
'''在文件partysmart.py文件结尾处添加'''
def ex2(sched):
'''双循环,让每一个起始时间和所有时间比较,如果在区间中则记录,最后取人数最多的那个。'''
count = max_count = 0
for i in sched:
for j in sched:
if i[0] >= j[0] and i[0] < j[1]:
count += 1
#print(i[0],count) #可详细输出所有的信息
if count > max_count:
max_count = count
best_time = i[0]
count = 0
print('Best time to attend the party is at', best_time, 'o\'clock :', max_count, 'celebrities will be attending!')
ex2(sched2)
#sched2 = [(6.0, 8.0), (6.5, 12.0), (6.5, 7.0), (7.0, 8.0), (7.5, 10.0), (8.0, 9.0),(8.0, 10.0), (9.0, 12.0), (9.5, 10.0), (10.0, 11.0), (10.0, 12.0), (11.0, 12.0)]
'''
print:
Best time to attend the party is at 9.5 o'clock : 5 celebrities will be attending!
原程序的结果为:
Best time to attend the party is at 9.5 o'clock : 5 celebrities will be attending!
结果完全相同,不过感觉习题2的算法更好理解和实现。
'''
难题 3 假设每位名人都有一个权重,取决于你对这位名人的喜爱程度。可以在时间表中将其表示为一个三元组,如(6.0, 8.0, 3)。开始时间是6.0,结束时间是8.0,权重是3。修改代码,找出最大化名人总权重的时间。例如…下面是一个更复杂的例子:
sched3 = [(6.0, 8.0, 2), (6.5, 12.0, 1), (6.5, 7.0, 2), (7.0, 8.0, 2), (7.5, 10.0, 3), (8.0, 9.0, 2), (8.0, 10.0, 1), (9.0, 12.0, 2), (9.5, 10.0, 4), (10.0, 11.0, 2), (10.0, 12.0, 3), (11.0, 12.0, 7)]
根据名人的日程安排,你想要在11点参加派对,此时参加派对名人权重之和是13,为最大值。
'''在上面的文件partysmart.py上再追加如下代码'''
sched3 = [(6.0, 8.0, 2), (6.5, 12.0, 1), (6.5, 7.0, 2), (7.0, 8.0, 2), (7.5, 10.0, 3), (8.0, 9.0, 2),
(8.0, 10.0, 1), (9.0, 12.0, 2), (9.5, 10.0, 4), (10.0, 11.0, 2), (10.0, 12.0, 3), (11.0, 12.0, 7)]
def ex3(sched):
count = max_count = 0
for i in sched:
for j in sched:
if i[0] >= j[0] and i[0] < j[1]:
count += j[2] #把之前的+1改为+j[2]即可
#print(i[0],count)
if count > max_count:
max_count = count
best_time = i[0]
count = 0
print('Best time to attend the party is at', best_time, 'o\'clock :', max_count, 'celebrities will be attending!')
ex3(sched3)
'''
print:
Best time to attend the party is at 11.0 o'clock : 13 celebrities will be attending!
'''
3.6 习题(page32)
习题 2 修改ComputerAssistant,以防存在两对同花色的牌,则在选择隐藏牌与第一张牌时,选择其中需要编码的数值更小的一对牌。
'''直接在magic-exercise1.py文件上修改函数outputFirstCard,ComputerAssistant并添加了一个函数least_elem'''
def least_elem(numbers, oneTwo):
'''取出两个卡牌差值最小的两个元素'''
oneTwo_new = []
for oneTwo_one in oneTwo: # 拆包,将超过2个的元组全部扩展成2个,用于处理含有3个及以上相同花色的卡牌,题目没有要求处理这种情况,但我也把这种情况算进去了。比如oneTwo的值为[(0, 1, 3)],即三张牌同一花色。
oneTwo_new += [(i,j) for i in oneTwo_one for j in oneTwo_one if i < j ] # 如[(0, 1, 3)] ⇒ [(0, 1), (0, 3), (1, 3)]
oneTwo_least = 52 # 随便赋值一个较大的数
for oneTwo_one in oneTwo_new: #遍历所有元组,找出最小值
temp = min(((numbers[oneTwo_one[0]] - numbers[oneTwo_one[1]]) % 13), ((numbers[oneTwo_one[1]] - numbers[oneTwo_one[0]]) % 13))
if temp < oneTwo_least:
oneTwo_least = temp
oneTwo_really = oneTwo_one
return oneTwo_really #最后取出差值最小的两个元素
#This procedure figures out which card should be hidden based on the distance
#between the two cards that have the same suit.
#It returns the hidden card, the first exposed card, and the distance
def outputFirstCard(numbers, oneTwo, cards): #牌的数字,相同花色牌的列表[(0, 1), (2, 3)], 5张牌名
oneTwo = least_elem(numbers, oneTwo) #挑出最小的两个元素
encode = (numbers[oneTwo[0]] - numbers[oneTwo[1]]) % 13
if encode > 0 and encode <= 6:
hidden = oneTwo[0]
other = oneTwo[1]
else:
hidden = oneTwo[1]
other = oneTwo[0]
encode = (numbers[oneTwo[1]] - numbers[oneTwo[0]]) % 13
## #The following print statement is just for debugging!
## print ('Hidden card is:', cards[hidden], 'and need to encode', encode)
print ('First card is:', cards[other])
return hidden, other, encode
def ComputerAssistant():
print ('Cards are character strings as shown below.')
print ('Ordering is:', deck)
cards, cind, cardsuits, cnumbers = [], [], [], []
numsuits = [0, 0, 0, 0]
number = 0
while number < 99999:
number = int(input('Please give random number of at least 6 digits:'))
#Generate five "random" numbers from the input number
clist = []
i = 0
while len(clist) < 5:
number = number * (i + 1) // (i + 2)
n = number % 52
i += 1
if not n in clist:
clist.append(n)
#print (clist)
pairsuit = [] #创建一个列表
for i in range(5):
n = clist[i]
cards.append(deck[n]) #五张牌名,为了便于理解代码,下面随便举了个实例
cind.append(n)
cardsuits.append(n % 4) #五张牌的花色 [1, 1, 2, 2, 0]
cnumbers.append(n // 4) #五张牌的数字 [1, 3, 5, 2, 9] 两个数组 1_1代表2_D, 3_1代表4_D以此类推
numsuits[n % 4] += 1 #[1, 2, 2, 0] 算出红花各两张
if numsuits[n % 4] > 1:
pairsuit.append(n % 4) #将大于1的花色存储在列表中,防止被替换。 此时pairsuit值为[1, 2]
pairsuit = list(set(pairsuit)) #去重,防止2个以上的花色被多次记录在pairsuit中
## #Just for debugging
## print (cards)
cardh = []
cardh_tuple = [] #记录每个子列表
#print(pairsuit)
for pairsuit_one in pairsuit:
for i in range(5):
if cardsuits[i] == pairsuit_one:
cardh_tuple.append(i) #[0, 1] [2, 3]
cardh.append(tuple(cardh_tuple)) #[(0, 1), (2, 3)]
cardh_tuple = []
#print(cardh)
hidden, other, encode = outputFirstCard(cnumbers, cardh, cards)
remindices = []
for i in range(5):
if i != hidden and i != other:
remindices.append(cind[i])
sortList(remindices)
outputNext3Cards(encode, remindices)
# print(cards[hidden])
guess = input('What is the hidden card?')
if guess == cards[hidden]:
print ('You are a Mind Reader Extraordinaire!')
else:
print ('Sorry, not impressed!')
return
ComputerAssistant() #最后执行测试
'''
输入777777,会出现两对花色相同的情况,验证无误。
输入999999,会出现有三张同花色的情况,取三者之间差值最小的两个元素作为隐藏牌和第一张牌。
'''
习题 3 一些魔术师更喜欢按不同的方式对牌排序,将花色置为首要排序因子,而不是按数值排序,如下:
deck = [‘A_C’, ‘2_C’, ‘3_C’, ‘4_C’, ‘5_C’, ‘6_C’, ‘7_C’, ‘8_C’, ‘9_C’, ‘10_C’, ‘J_C’, ‘Q_C’, ‘K_C’, ‘A_D’, ‘2_D’, ‘3_D’, ‘4_D’, ‘5_D’, ‘6_D’, ‘7_D’, ‘8_D’, ‘9_D’, ‘10_D’, ‘J_D’, ‘Q_D’, ‘K_D’, ‘A_H’, ‘2_H’, ‘3_H’, ‘4_H’, ‘5_H’, ‘6_H’, ‘7_H’, ‘8_H’, ‘9_H’, ‘10_H’, ‘J_H’, ‘Q_H’, ‘K_H’, ‘A_S’, ‘2_S’, ‘3_S’, ‘4_S’, ‘5_S’, ‘6_S’, ‘7_S’, ‘8_S’, ‘9_S’, ‘10_S’, ‘J_S’, ‘Q_S’, ‘K_S’]
修改ComputerAssitant允许魔术师按如上的顺序排练。注意,按索引提取牌的牌号与花色的计算逻辑需要修改。同样,助手读牌的顺序也需要修改。需要正确处理一些细节,才能正确解出这道谜题的变体。
deck2 = ['A_C', '2_C', '3_C', '4_C', '5_C', '6_C', '7_C', '8_C', '9_C', '10_C', 'J_C', 'Q_C', 'K_C',
'A_D', '2_D', '3_D', '4_D', '5_D', '6_D', '7_D', '8_D', '9_D', '10_D', 'J_D', 'Q_D', 'K_D',
'A_H', '2_H', '3_H', '4_H', '5_H', '6_H', '7_H', '8_H', '9_H', '10_H', 'J_H', 'Q_H', 'K_H',
'A_S', '2_S', '3_S', '4_S', '5_S', '6_S', '7_S', '8_S', '9_S', '10_S', 'J_S', 'Q_S', 'K_S']
'''
将习题2修改后的文件经过如下修改:
'''
#ComputerAssistant()函数改动部分
......
for i in range(5):
n = clist[i]
cards.append(deck2[n])
cind.append(n)
cardsuits.append(n // 13)
cnumbers.append(n % 13)
numsuits[n // 13] += 1
if numsuits[n // 13] > 1:
pairsuit.append(n // 13)
pairsuit = list(set(pairsuit))
......
''' 再将代码中deck替换为deck2即可'''
难题 4 编写ComputerAssistant4Cards,允许排练这套4张牌的戏法。你可以选择上文描述的编码策略,利用这样的手段提供信息:(1)每张牌放置于桌面上的隐藏牌的左侧还是右侧;(2)所有3张牌是全部正面朝上还是正面朝下。你也可以设计自己的编码策略,确保对任意抽取的4张牌都能操作这套戏法。
#coding=utf-8
'''
一共有4张牌,除了隐藏牌以外,其他牌如果是正面朝上则代表1-8,背面朝上代表9-16。
我们把和隐藏牌最近的那张牌放在其右边,并将其视为一个整体c,这样和其他两张牌ab一共有6种组合,即
abc acb cab cba bca bac ,然后我们把和隐藏牌最近的那张牌放在其左边,并视为整体d,剩余两张牌只在其左边,
一共有2种组合,即 abd bad,这样8种表示方式就齐了,正反各8种,一共16种,足够表达了。
'''
deck = ['A_C', 'A_D', 'A_H', 'A_S', '2_C', '2_D', '2_H', '2_S', '3_C', '3_D', '3_H', '3_S',
'4_C', '4_D', '4_H', '4_S', '5_C', '5_D', '5_H', '5_S', '6_C', '6_D', '6_H', '6_S',
'7_C', '7_D', '7_H', '7_S', '8_C', '8_D', '8_H', '8_S', '9_C', '9_D', '9_H', '9_S',
'10_C', '10_D', '10_H', '10_S', 'J_C', 'J_D', 'J_H', 'J_S',
'Q_C', 'Q_D', 'Q_H', 'Q_S', 'K_C', 'K_D', 'K_H', 'K_S']
def shuru_shengcheng_4kapai():
number = 0
print('现在有扑克牌52张,分别为:', deck)
while number < 99999:
number = int(input('Please give random number of at least 6 digits:'))
clist = []
i = 0
while len(clist) < 4:
number = number * (i + 1) // (i + 2)
n = number % 52
i += 1
if not n in clist:
clist.append(n) #随机选择的卡牌索引 比如[13, 26, 6, 4]
#clist = [0, 13, 26, 39] #测试反面
return clist
def fenlei_shuchu(clist):
#选择差值最小的两位
cmp = [(i,j) for i in clist for j in clist if i != j]
min_cmp = 52
for i in cmp:
min_temp = (i[0] - i[1]) % 52
if min_temp < min_cmp:
min_cmp = min_temp
hide = i[0] #取出隐藏牌索引
bind = i[1] #取出绑定的牌索引
other = clist[:]
other.remove(hide)
other.remove(bind)
big = max(other) #取出大的牌索引
small = min(other) #取出小的牌索引
return hide, bind, big, small
def shengcheng_pailie(hide, bind, big, small):
print(hide, bind, big, small)
if (hide - bind) % 52 <= 8:
cha = (hide - bind) % 52
front = True
else:
cha = (hide - bind) % 52 - 8
front = False
if cha == 1:
return (big, small, bind, front, 2) #front代表正面还是反面,后面的数字表示hide的位置
elif cha == 2:
return (big, bind, small, front, 1)
elif cha == 3:
return (bind, big, small, front, 0)
elif cha == 4:
return (small, big, bind, front, 2)
elif cha == 5:
return (small, bind, big, front, 1)
elif cha == 6:
return (bind, small, big, front, 0)
elif cha == 7:
return (big, small, bind, front, 3)
elif cha == 8:
return (small, big, bind, front, 3)
def ComputerAssistant4Cards():
clist = shuru_shengcheng_4kapai()
hide, bind, big, small = fenlei_shuchu(clist)
res = shengcheng_pailie(hide, bind, big, small)
if res[-2]: #正面
print('助手把牌全都正面排列,且顺序如下:')
else:
print('助手把牌全都反面排列,且顺序如下:')
res2 = [deck[res[0]], deck[res[1]], deck[res[2]]]
res2.insert(res[-1], '???')
print(res2[0], res2[1], res2[2], res2[3])
magicin = input('请输入未知的卡牌:')
if magicin == deck[hide]:
print('恭喜你!猜的真准!')
else:
print('哎呀,演砸了!正确的卡牌应该是:', deck[hide])
ComputerAssistant4Cards()
4.5 习题(page46)
难题 2 修改EightQueens的代码,在列表中某些位置上已放置过皇后的基础上,寻找解法。你可以使用一维列表localtion作为列表,该参数对应皇后的固定位置的某些列并且非负。例如,localtion = [-1, 4, -1, -1, -1, -1, -1, 0],表示在第2列和第8列放置了两个皇后。你的代码应该生成[2, 4, 1, 7, 5, 3, 6, 0],作为与现有皇后位置相符的解。
'''
在8queens-iterative-exercise1.py文件上修改,考虑到每个都循环8次,已经给的那列就不需要循环了,这可以理解成只循环1次,按照这个思路修改代码如下:
'''
def noConflicts(board, current):
for i in range(current):
if (board[i] == board[current]):
return False
#We have two diagonals hence need the abs()
if (current - i == abs(board[current] - board[i])):
return False
return True
#This procedure places 8 Queens on a board so they don't conflict.
#It assumes n = 8 and won't work with other n!
#Additional argument: number of solutions
#Non-default argument needs to be first!
def EightQueens(numsol, location, n=8):
board = location
sol = 0
xunhuan = []
for b in board: #将需要循环的次数放置到xunhuan列表中
if b == -1:
xunhuan.append(8)
else:
xunhuan.append(1)
for i in range(xunhuan[0]):
if xunhuan[0] != 1: #如果循环1,说明已经给了board的值,那么就不需要重新赋值了;如果循环不为1,说明未给确定值,则需要遍历。
board[0] = i
for j in range(xunhuan[1]):
if xunhuan[1] != 1:
board[1] = j
if not noConflicts(board, 1):
continue
for k in range(xunhuan[2]):
if xunhuan[2] != 1:
board[2] = k
if not noConflicts(board, 2):
continue
for l in range(xunhuan[3]):
if xunhuan[3] != 1:
board[3] = l
if not noConflicts(board, 3):
continue
for m in range(xunhuan[4]):
if xunhuan[4] != 1:
board[4] = m
if not noConflicts(board, 4):
continue
for o in range(xunhuan[5]):
if xunhuan[5] != 1:
board[5] = o
if not noConflicts(board, 5):
continue
for p in range(xunhuan[6]):
if xunhuan[6] != 1:
board[6] = p
if not noConflicts(board, 6):
continue
for q in range(xunhuan[7]):
if xunhuan[7] != 1:
board[7] = q
if noConflicts(board, 7):
if sol < numsol:
print (board)
sol += 1
else:
return
return
EightQueens(1, [-1, 4, -1, -1, -1, -1, -1, 0])
习题 3 使用continue语句减少FourQueens代码中的缩进级别,使两种解法都打印出来。这比你想象的更棘手一点。
'''题目没读懂......'''
6.5 习题(page61)
难题 2 编写CoinComparisonGeneral,它可以不假设假币更重便能确定哪一枚是假币,就像当前代码所做的那样。这将涉及findFakeGroupAndType,中为resultland2填写另外两种情况,然后为第一段分片(split)调用findFakeGroupAndType,为剩余的分片调用findFakeGroupHeavier或者findFakeGroupLighter。给出的过程findFakeGroup假设假币更重,你需要写一个伙伴过程,让他假设假币更轻并返回合适的硬币组。你的代码也应当处理没有假币的情况。
'''
在weighings.py文件上做了修改。
'''
import sys
def splitCoins(coinsList):
length = len(coinsList)
group1 = coinsList[0:length//3]
group2 = coinsList[length//3:length//3*2]
group3 = coinsList[length//3*2:length]
return group1, group2, group3
def compare(groupA, groupB):
if sum(groupA) > sum(groupB):
result = 'left'
elif sum(groupB) > sum(groupA):
result = 'right'
elif sum(groupB) == sum(groupA):
result = 'equal'
return result
def findFakeGroupAndType(group1, group2, group3):
result1and2 = compare(group1, group2)
if result1and2 == 'left':
result1and3 = compare(group1, group3)
if result1and3 == 'left':
fakeGroup = group1
type = 'heavier'
elif result1and3 == 'equal':
fakeGroup = group2
type = 'lighter'
elif result1and2 == 'right':
result1and3 = compare(group1, group3)
if result1and3 == 'right':
fakeGroup = group1
type = 'lighter'
elif result1and3 == 'equal':
fakeGroup = group2
type = 'heavier'
elif result1and2 == 'equal':
result1and3 = compare(group1, group3)
if result1and3 == 'left':
fakeGroup = group3
type = 'lighter'
elif result1and3 == 'right':
fakeGroup = group3
type = 'heavier'
else:
print('There is no fake coin!')
sys.exit()
return fakeGroup, type
def findFakeGroupHeavier(group1, group2, group3):
result1and2 = compare(group1, group2)
if result1and2 == 'left':
fakeGroup = group1
elif result1and2 == 'right':
fakeGroup = group2
elif result1and2 == 'equal':
fakeGroup = group3
return fakeGroup
def findFakeGroupLighter(group1, group2, group3):
result1and2 = compare(group1, group2)
if result1and2 == 'left':
fakeGroup = group2
elif result1and2 == 'right':
fakeGroup = group1
elif result1and2 == 'equal':
fakeGroup = group3
return fakeGroup
def CoinComparisonGeneral(coinsList):
currList = coinsList[:]
group1, group2, group3 = splitCoins(currList)
currList, type = findFakeGroupAndType(group1, group2, group3)
counter = 2
while len(currList) > 1:
group1, group2, group3 = splitCoins(currList)
if type == 'heavier':
currList = findFakeGroupHeavier(group1, group2, group3)
elif type == 'lighter':
currList = findFakeGroupLighter(group1, group2, group3)
counter += 1
fake = currList[0]
print ('The fake coin is coin', coinsList.index(fake) + 1, '.It\'s', type , 'than others.')
print ('Number of weighings:', counter)
#Pretend that you actually can't see the values in coinsList!
coinsList2 = [10, 10, 10, 10, 10, 10, 11, 10, 10]
coinsList = [10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 9, 10]
CoinComparisonGeneral(coinsList2)
CoinComparisonGeneral(coinsList)
习题 3 假设有两枚假币,他们看起来和其他硬币完全相同但比其他硬币更重。修改CoinComparison,找到其中一枚假币(两个假币中的一个)。注意,如果你有两组硬币,每组都有一枚硬币,天平将会显示这两组硬币重量相等。如果你选择了第三组硬币(不在比较范围中),你将会错过找到这枚假币。在修改过的代码中,不要为正确计算称量次数而费心。
'''
在weighings.py原文件上修改如下。
'''
import sys
def splitCoins(coinsList):
length = len(coinsList)
group1 = coinsList[0:length//3]
group2 = coinsList[length//3:length//3*2]
group3 = coinsList[length//3*2:length]
return group1, group2, group3
def compare(groupA, groupB):
if sum(groupA) > sum(groupB):
result = 'left'
elif sum(groupB) > sum(groupA):
result = 'right'
elif sum(groupB) == sum(groupA):
result = 'equal'
return result
def findFakeGroup(group1, group2, group3):
result1and2 = compare(group1, group2)
if result1and2 == 'left':
fakeGroup = group1
elif result1and2 == 'right':
fakeGroup = group2
elif result1and2 == 'equal': #Could just be an else
result1and3 = compare(group1, group3)
if result1and3 == 'right':
fakeGroup = group3
elif result1and3 == 'left':
fakeGroup = group1
elif result1and3 == 'equal':
print('There is no fake coin!')
sys.exit()
return fakeGroup
def CoinComparison(coinsList):
currList = coinsList[:]
while len(currList) > 1:
group1, group2, group3 = splitCoins(currList)
currList = findFakeGroup(group1, group2, group3)
fake = currList[0]
print ('The fake coin is coin', coinsList.index(fake) + 1, 'in the original list')
#Pretend that you actually can't see the values in coinsList!
coinsList2 = [10, 11, 10, 10, 10, 10, 11, 10, 10]
coinsList = [10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 11, 11, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10]
CoinComparison(coinsList2)
CoinComparison(coinsList)
7.5 习题(page69)
习题 2 修改过程bsearch,多加一个参数:查找区间小于多少时,执行迭代顺序查找。当前的过程会持续二分搜索直到找到元素。实际上,当区间[lo, hi]的长度hi - lo 小于某特定长度时,不分割区间直接在区间内使用顺序查找反而可能更快。
'''
在bsearch.py文件上修改
'''
NOTFOUND = -1
Ls = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, \
71, 73, 79, 83, 89, 97] #len = 25
def lsearch(L, value, pre_index=0):
for i in range(len(L)):
if L[i] == value:
print ("Found at location", i + pre_index)
return i + pre_index
print ("Could not find the value", value)
return NOTFOUND
def bsearch(L, value, lenl=10):
lo, hi = 0, len(L)
pre_index = 0
while lo <= hi:
if hi - lo < lenl:
return lsearch(L[lo:hi+1], value, pre_index)
mid = (lo + hi) // 2
mid2 = (hi - lo) // 2
if L[mid] < value:
lo = mid + 1
pre_index += mid2 + 1
elif value < L[mid]:
hi = mid - 1
else:
print ("Found at location", mid)
return mid
lsearch(Ls, 89)
bsearch(Ls, 47, 3)
bsearch(Ls, 37, 7)