【个人笔记】编程的乐趣(用python解算法谜题)——谜题1,2

谜题 1 保持一致

s = 'Alice'
#不能修改字符串s[0] = 'B'



# print默认末尾换行
# end = '' 末尾不换行,加空格
print(s, end=' ')

  

Python中的列表(list)可理解为元素的序列或数组 

L = [1, 2, 'A', [3,4] ]

 

元组与列表类似但不可修改

T1 = (1, 2, 'A', [3, 4] )

T2= (1, 2, 'A', (3, 4) )

T1[3]不可修改,T1[3][0]可修改

T2[3][0]不可修改

 

习题

cap1 = ['F', 'F', 'B', 'B', 'B', 'F', 'B', 'B', 'B', 'F', 'F', 'B', 'F']
cap2 = ['F', 'F', 'B', 'B', 'B', 'F', 'B', 'B', 'B', 'F', 'F', 'F', 'F']
cap3 = ['F', 'F', 'B', 'H', 'B', 'F', 'B', 'B', 'B', 'F', 'H', 'F', 'F']

习题 1.修改代码使命令听起来更自然一些。

 

增加判断语句,输出时先判断区间大小是否为1

def pleaseConform(caps):
    start = forward = backward = 0
    intervals = []
    #caps += ['end']
    for i in range(1, len(caps)):
        if caps[start] != caps[i] or i == len(caps) - 1:
            intervals.append((start, i - 1, caps[start]))
            if caps[start] == 'F':
                forward += 1
            else:
                backward += 1
            start = i

    if forward < backward:
        flip = 'F'
    else:
        flip = 'B'
    for t in intervals:
        if t[2] == flip:
            if t[0] == t[1]:
                print('People in positions', t[0], 'flip your caps!')
            else:
                print('People in positions', t[0], 'through', t[1], 'flip your caps!')

 

习题2.修改pleaseConformOnepass,如习题1那样打印更自然一些的命令,并确保程序再输入是空列表时不会崩溃。
  提示:你需要记住区间的起始位置(而不是在第6行打印)。

 

记录开始位置,输出时先判断区间大小是否为1

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]:
                    start = i
                else:
                    if start == i-1:
                        print('People in positions', i-1, 'flip your caps!')
                    else:
                        print('People in positions', start, ' through', i - 1, 'flip your caps!')


pleaseConformOnepass(cap2)

 

习题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!

 

增加对不戴帽子 'H' 的判断

def pleaseConform(caps):
    start = forward = backward = 0
    intervals = []
    #caps += ['end']
    for i in range(1, len(caps)):
        if caps[start] != caps[i] or i == len(caps) - 1:
            if caps[start] != 'H':
                intervals.append((start, i - 1, caps[start]))
                if caps[start] == 'F':
                    forward += 1
                else:
                    backward += 1
            start = i

    if forward < backward:
        flip = 'F'
    else:
        flip = 'B'
    for t in intervals:
        if t[2] == flip:
            if t[0] == t[1]:
                print('People in positions', t[0], 'flip your caps!')
            else:
                print('People in positions', t[0], 'through', t[1], 'flip your caps!')


pleaseConform(cap3)

 

 

 习题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在解码步骤中会很有用。

 

s = "BWWWWWBWWWWQ"


def encode(string):
    string += ' '
    time = idx = 1
    res = ''
    while idx < len(string):
        if string[idx] != string[idx - 1]:
            res += str(time)
            res += string[idx - 1]
            time = 1
        else:
            time += 1
        idx += 1
    print(res)
    return res


def decode(string):
    time = 0
    res = ''
    for c in string:
        if '0' <= c <= '9':
            time = time * 10 + int(c)
        else:
            for i in range(time):
                res += c
            time = 0
    print(res)
    return res


decode(encode(s))

  

 

谜题 2 参加派对的最佳时间

#选择排序
def sortList(tlist):
    for ind in range(len(tlist) - 1):
        iSm = ind
        for i in range(ind, len(tlist)):
            if tlist[iSm][0] > tlist[i][0]:
                iSm = i
        tlist[ind], tlist[iSm] = tlist[iSm], tlist[ind]

 

习题1

 

在计算名人参加派对最多的时间时,增加对时间是否满足[ystart, yend]范围的判断

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)]


def bestTimeToPartySmart(schedule, ystart, yend):
    times = []
    for c in schedule:
        times.append((c[0], 'start'))
        times.append((c[1], 'end'))


    sortlist(times)
    maxcount, time = chooseTime(times, ystart, yend)
    print(maxcount, time)

# 选择排序
def sortlist(tlist):
    for ind in range(len(tlist) - 1):
        iSm = ind
        for i in range(ind, len(tlist)):
            if tlist[iSm][0] > tlist[i][0]:
                iSm = i
        tlist[ind], tlist[iSm] = tlist[iSm], tlist[ind]

    return


def chooseTime(times,  ystart, yend):
    rcount = 0
    maxcount = 0
    time = 0

    # Range through the times computing a running count of celebrities
    for t in times:
        if t[1] == 'start':
            rcount = rcount + 1
        elif t[1] == 'end':
            rcount = rcount - 1
        if rcount > maxcount and ystart < t[0] < yend:
            maxcount = rcount
            time = t[0]

    return maxcount, time


##bestTimeToPartySmart(sched)
ystart = 8
yend = 10
bestTimeToPartySmart(sched2, ystart, yend)

 

习题2

有另一种方法, 可以不依赖时间精度来计算参加派对的最佳时间。我们依次选择每位名人的时间区间,并确定有多少其他名人的时间区间包含所选名人的开始时间。我们选择出某位名人,使他的开始时间被最大数量的其他名人时间区间所包含,并将他的开始时间作为参加派对的时间。编写代码实现该算法,并验证它的结果与基于排序算法的结果是否相同。

 

计算每一位名人在开始时间时,有多少其它名人在场

def fun2(time):
    max_count = count = 0
    best_time = 0;
    for t in time:
        for t0 in time:
            if t0[0] <=t[0] < t0[1] :
                count += 1
        if max_count < count:
            max_count = count
            best_time = t[0]
    return best_time, max_count

  

 习题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,为最大值。

 

对2.2的算法进行修改:

在排序时间前,即bestTimeToPartySmart函数中,对每一个开始时间和结束时间都记录上该名人的权重值

在最终选择时间时,即chooseTime函数中,“start” 时刻将增加此名人对应的权重,“end” 时刻减少权重

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 bestTimeToPartySmart(schedule):
    times = []
    for c in schedule:
        times.append((c[0], 'start', c[2]))
        times.append((c[1], 'end', c[2]))


    sortlist(times)
    maxcount, time = chooseTime(times)
    return maxcount, time

# 选择排序
def sortlist(tlist):
    for ind in range(len(tlist) - 1):
        iSm = ind
        for i in range(ind, len(tlist)):
            if tlist[iSm][0] > tlist[i][0]:
                iSm = i
        tlist[ind], tlist[iSm] = tlist[iSm], tlist[ind]

    return


def chooseTime(times):
    rcount = 0
    maxcount = 0
    time = 0

    # Range through the times computing a running count of celebrities
    for t in times:
        if t[1] == 'start':
            rcount = rcount + t[2]
        elif t[1] == 'end':
            rcount = rcount - t[2]
        if rcount > maxcount:
            maxcount = rcount
            time = t[0]

    return maxcount, time


maxcount, time = bestTimeToPartySmart(sched3)
print('The best time to go is', time, 'with pow', maxcount)

  

 

 

 参考资料:

编程的乐趣用Python解算法谜题 —— 斯里尼·德瓦达斯

编程的乐趣:用Python解算法谜题 课后习题答案 —— CSDN博主「咬不动的椰果」:https://blog.csdn.net/qgazq/article/details/102711260

posted @ 2021-03-17 16:14  Left_Stan  阅读(156)  评论(0编辑  收藏  举报