Skip to content

第9周:第六次上机课 ​

详细讲义 · py 作业 6 · OJ 题集

一、列表的基本用法 ​

对应 01 · 列表练习、02 · 校门外的树 和 06 · 去除重复数字。

1. 下标与切片 ​

python
numbers = [10, 20, 30, 40]
print(numbers[0])    # 10,第一个元素
print(numbers[-1])   # 40,最后一个元素
print(numbers[1:3])  # [20, 30]

下标从 0 开始;切片 numbers[1:3] 包含下标 1,但不包含下标 3。

2. 用下标记录状态 ​

列表的下标可以表示位置,元素可以记录该位置的状态。例如,用 1 表示有树,0 表示没有树:

python
trees = [1] * 6             # 位置 0~5,初始都有树
for i in range(1, 4):       # 处理位置 1、2、3
    trees[i] = 0

print(trees)           # [1, 0, 0, 0, 1, 1]
print(trees.count(1))  # 3,还有树的位置数

位置从 0 到 5,一共需要 6 个元素。range(1, 4) 不包含 4;重复把同一位置标记为 0,不会重复减少树的数量。

3. 添加和删除元素 ​

python
numbers = [10, 20, 30]
numbers.append(40)     # [10, 20, 30, 40]:添加到末尾
numbers.insert(1, 15)  # [10, 15, 20, 30, 40]:插入到下标 1

del numbers[0]         # [15, 20, 30, 40]:按下标删除
numbers.remove(30)     # [15, 20, 40]:删除值为 30 的元素
print(numbers)

这些操作会修改原列表。remove(30) 删除第一个值为 30 的元素;如果列表中没有这个值,会报错。

也可以用切片一次删除多个元素:

python
numbers = [10, 20, 30, 40, 50]
del numbers[1:3]
print(numbers)  # [10, 40, 50]

4. 判断、统计与排序 ​

python
numbers = [5, 2, 5, 8]
print(5 in numbers)      # True,判断元素是否存在
print(numbers.count(5))  # 2,统计元素出现次数
print(len(numbers))      # 4,列表长度
print(max(numbers))      # 8,最大值
print(sorted(numbers))   # [2, 5, 5, 8],从小到大排序

sorted(numbers) 返回一个排好序的新列表,原列表不会因此改变。max() 需要列表中至少有一个元素。

二、二维列表与方向数组 ​

对应 04 · 矩阵换行求边缘和 和 05 · 图像模糊处理。

用方向数组访问上下左右 ​

二维列表用 image[行][列] 访问元素。要访问当前位置 (i, j) 的上下左右,可以把每个方向写成一对行、列的偏移量:

方向行、列的偏移量
上(-1, 0)
下(1, 0)
左(0, -1)
右(0, 1)

这些偏移量可以存入列表,通常称为“方向数组”。逐个取出 (di, dj),加到当前下标 (i, j) 上,就得到相邻位置的行、列下标。

一个内部像素的新值从哪里来?

原图:中心和上下左右,共 5 个值。

求平均:(100 + 0 + 50 + 200 + 50) ÷ 5 = 80

写入:新图的中心位置写 80;计算其他位置时仍读取原图。

下面从图中的中心位置出发,按上、下、左、右的顺序访问相邻元素:

python
image = [[100, 0, 100],
         [50, 100, 200],
         [50, 50, 100]]
i, j = 1, 1
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]

for di, dj in directions:
    ni, nj = i + di, j + dj
    if 0 <= ni < len(image) and 0 <= nj < len(image[0]):
        print(ni, nj, image[ni][nj])

输出依次为 0 1 0、2 1 50、1 0 50、1 2 200;每行分别是相邻位置的行下标、列下标和值。if 用来防止下标越界,移动方向时不要把行和列写反。

交换行与判断边缘 ​

text
原矩阵                 交换第 1、2 行后
1  2  3                4  5  6
4  5  6                1  2  3
7  8  9                7  8  9

交换后,只有中间的 2 不在边缘,所以边缘和是 43。题面行号从 1 开始,列表下标从 0 开始;换行时要先转换下标。

判断位置 (i, j) 是否为边缘,可以看它是否在首行、末行、首列或末列。每个位置只判断一次,四个角不会重复加。

想一想: 只有一行、一列或者一个元素时,哪些位置属于边缘?

从原图读取,写到新图 ​

四周边缘保持不变。对于内部像素,从原图读取中心和上下左右五个值,将平均值舍入后写入新图。不能一边修改原图,一边继续使用它作为下一次计算的输入。

想一想: 如果先把左边的值改掉,下一格计算时还能读到原来的左邻居吗?只有一行或一列的图像有内部像素吗?

三、区间合并 ​

对应 07 · 小鹿的工作和休息时间。

先按开始时间排序,再逐段观察:后一段的起点不大于当前段的终点,说明重叠或相接,可以合并;否则中间有空隙,需要另起一段。

把重叠或相接的时间段连起来
已按起点排序;点击“下一步”逐段观察。
[1, 4]
[3, 7]
[7, 9]
[11, 14]
015
准备尚未开始

区间已经按起点排序。每次取一个区间,观察它与当前区间的关系。

0 / 5

注意右端点要取两段右端的较大值:例如 [1, 8] 包含 [2, 3],合并后仍是 [1, 8]。所有连续段合并后再比较长度;如果一样长,选开始较早的那一段。

想一想: [1, 3] 和 [3, 5] 为什么可以连起来?如果 [1, 4] 和 [6, 9] 长度一样,选哪一段?

四、字典的用法与排序 ​

对应 03 · 成绩排序、08 · 字典练习、09 · 单词出现频率统计、10 · 网站网页访问统计 和 11 · 单词打分。

判断键、值和键值对 ​

python
scores = {"a": 8, "b": 1, "c": 0}
print("c" in scores)           # True:检查键
print(0 in scores.values())   # True:检查值
print(scores.get("b") == 1)   # True:检查 b 对应的值

注意 "1" 是字符串,1 是整数。读入键值对后,数字要转换成整数再判断。

按单词计数 ​

使用字典可以为每个键累计次数:

python
counts = {}
for word in ["about", "send", "about", "me"]:
    counts[word] = counts.get(word, 0) + 1
print(counts)  # {'about': 2, 'send': 1, 'me': 1}

get(word, 0) 在单词还没有出现时返回 0。第 9 题的单词一行一个,读到输入结束为止;第一行不是单词数量。

按多个条件排序 ​

counts.items() 可以取出每个 (单词, 次数)。先按次数降序,再在次数相同时按单词升序:

python
counts = {"about": 2, "send": 1, "me": 1}
ranking = sorted(counts.items(), key=lambda item: (-item[1], item[0]))
print(ranking)  # [('about', 2), ('me', 1), ('send', 1)]

item[0] 是单词,item[1] 是次数。次数前加负号,使出现更多的词排在前面;次数相同时再按单词升序比较。

成绩排序也使用相同思路:以 (-分数, 姓名) 为排序关键字。姓名没有保证唯一时,应先用列表保留每条成绩记录。

按网页累计时长 ​

把时间统一换算成秒:小时 × 3600 + 分钟 × 60 + 秒,每次把结束秒数减去开始秒数,再累加到对应网页。

网页访问与累计时长
index.html6 + 183 = 189 秒
study.html185 秒

单次最长的是 study.html,累计最长的是 index.html。

平均分需要总分和次数 ​

同一个单词获得 2、8、8 分,平均分是 (2 + 8 + 8) / 3 = 6。如果另一个单词只获得一个 5 分,它的平均分是 5,更简单。

不要把“旧平均分 + 新分数”再除以 2,这样会给后来的评分更大权重。除了分数,还要保存给这个单词评分的人的 id,才能按题目要求输出。

想一想: 只保存最低分或总分,能直接判断哪个单词平均分最低吗?

课程资料由授课教师、助教与同学共同积累。