Skip to main content

讨论 12 | CS 61A 2024 年春季学期

讨论 12:期末复习

提醒: 使用 Discord 与课程工作人员进行语音聊天。随时在 Discord 的 #discuss-queue 频道中向 @discuss 发送消息,课程工作人员会加入您小组的语音频道。

小组里派一个人加入 Discord就行。当然,多几个人加入也没问题,但一个人就够了。

现在转到 Pensieve:

  • 所有人:请前往 discuss.pensieve.co,用你的 @berkeley.edu 邮箱登录,然后输入你们小组的号码(就是你们的 Discord 频道号)。

登录 Pensieve 之后,就不用再回到这个页面了。Pensieve 上的内容和这里一样(而且功能更多)。如果由于某种原因 Pensieve 无法工作,请返回此页面并继续讨论。

有问题的话,可以在 Discord#help 频道里提问。

小提示: 你们可以在小组的 Discord 频道文本框里输入问题,加上 @discuss,课程人员会回复。

开始

如果您的团队中只有 1 或 2 个人,您可以加入房间中的其他团队。

破冰一下: 大家轮流说一下自己的名字,还有下学期最期待的非 CS/EECS 课程。

列表

列表最常见的两个修改操作是项目赋值和 append 方法。

>>> s = [1, 3, 4]
>>> t = s # 同一个列表的另一个名字
>>> t[0] = 2 # 这会把列表的第一个元素改成 2,s 和 t 都会受影响
>>> s
[2, 3, 4]
>>> s.append(5) # 这会将 5 添加到列表的末尾,影响 s 和 t
>>> t
[2, 3, 4, 5]

还有许多其他的列表修改方法:

  • append(elem):将 elem 添加到列表的末尾。返回 None
  • extend(s):将可迭代对象 s 中的所有元素添加到列表末尾。返回 None
  • insert(i, elem):在索引 i 处插入 elem。如果 i 大于或等于列表的长度,则将 elem 插入到末尾。这不会替换任何现有元素,只会添加新元素 elem。返回 None
  • remove(elem):删除列表中第一次出现的 elem 元素。返回 None。如果 elem 不在列表里,会报错。
  • pop(i):删除并返回索引 i 处的元素。
  • pop():删除并返回最后一个元素。

Q1:单词绳索

定义: 在 Python 中,绳索是一个列表,其中只包含单字母的字符串,但最后一个元素可以是单字母字符串,也可以是另一个绳索。

实现 word_rope,一个 Python 函数,它接受一个非空字符串 s,该字符串仅包含字母和空格,并且不以空格开头或结尾。返回一个绳索,包含字符串 s 中的字母,并且每个单词都位于单独的列表中。

重要: 不能用字符串的切片、splitfind 或者 index 方法。要用列表操作来解决。 提示: s[-1] 会返回序列 s 的最后一个元素。

 def word_rope(s):
"""Return a rope of the words in string s.
>>> word_rope('the last week')
['t', 'h', 'e', ['l', 'a', 's', 't', ['w', 'e', 'e', 'k']]]
"""
assert s and s[0] != ' ' and s[-1] != [ ]
result = []
word = _____
for x in s:
if x == ' ':
"*** YOUR CODE HERE ***"
else:
"*** YOUR CODE HERE ***"
return result

在 61A 代码编辑器中运行

在这个实现中,result 代表一个绳索,word 则是绳索中正在构建的列表。当 x 是空格时,将一个空列表添加到 word 的末尾,然后将 word 指向这个新的空列表。否则,将 x 添加到 word 的末尾。

链表

链表是一个 Link 对象或者 Link.empty

你可以通过以下两种方式修改 Link 对象 s

  • 使用 s.first = ... 改变第一个元素
  • 使用 s.rest = ... 改变剩余的元素

你可以通过调用 Link 创建一个新的 Link 对象:

  • Link(4) 创建一个长度为 1,包含 4 的链表。
  • Link(4, s) 创建一个以 4 开头,后跟链表 s 的元素的链表。
class Link:
"""A linked list is either a Link object or Link.empty

>>> s = Link(3, Link(4, Link(5)))
>>> s.rest
Link(4, Link(5))
>>> s.rest.rest.rest is Link.empty
True
>>> s.rest.first * 2
8
>>> print(s)
<3 4 5>
"""
empty = ()

def __init__(self, first, rest=empty):
assert rest is Link.empty or isinstance(rest, Link)
self.first = first
self.rest = rest

def __repr__(self):
if self.rest:
rest_repr = ', ' + repr(self.rest)
else:
rest_repr = ''
return 'Link(' + repr(self.first) + rest_repr + ')'

def __str__(self):
string = '<'
while self.rest is not Link.empty:
string += str(self.first) + ' '
self = self.rest
return string + str(self.first) + '>'

Q2: 线性子列表

定义: 链表 s 的一个 子列表 是由 s 中的部分元素按照原顺序组成的链表。

定义: 对于数字链表 s,其 线性子列表 指的是一个子列表,其中任意两个相邻数字的差值都相等。 实现 linear 函数, 该函数接收一个数字链表 s (可以是 Link 实例或 Link.empty 中的一种). 该函数返回 s 中最长的等差子链表. 如果存在两个长度相同的等差子链表, 返回任意一个即可.

def linear(s):
"""
Return the longest linear sublist of a linked list s.
>>> s = Link(9, Link(4, Link(6, Link(7, Link(8, Link(10))))))
>>> linear(s)
Link(4, Link(6, Link(8, Link(10))))
>>> linear(Link(4, Link(5, s)))
Link(4, Link(5, Link(6, Link(7, Link(8)))))
>>> linear(Link(4, Link(5, Link(4, Link(7, Link(3, Link(2, Link(8))))))))
Link(5, Link(4, Link(3, Link(2))))
"""
def complete(first, rest):
"The longest linear sublist of Link(first, rest) with difference d."
if rest is Link.empty:
return ____
elif ____ == d:
return Link(____, complete(____, ____))
else:
return complete(first, rest.rest)

if s is Link.empty:
return s

longest = Link(s.first) # The longest linear sublist found so far
while s is not Link.empty:
t = s.rest
while t is not Link.empty:
d = t.first - s.first
candidate = ____
if length(candidate) > length(longest):
longest = candidate
t = t.rest
s = s.rest
return longest

def length(s):
if s is Link.empty:
return 0
else:
return 1 + length(s.rest)

Run in 61A Code

以下是三种情况:

  • 如果 rest 为空,则返回一个仅包含 first 的单元素列表。
  • 如果 rest.first 可以接在以 first 开头的等差子链表之后, 那么构建一个包含 firstrest.first 的列表.
  • 否则,complete(first, rest.rest)

这个 while 循环针对每两个可能的起始值 s.firstt.first 创建一个候选的等差子链表. 该子链表的剩余部分必须存在于 t.rest 中.

Scheme

Q3: Increasing Rope

定义: Scheme 中的 rope (这里我们称之为“绳索列表”) 是一个非空列表,其中仅包含数字,但最后一个元素除外,该元素可以是数字或 rope。

实现 up,这是一个接受正整数 n 的 Scheme 过程。它返回一个包含 n 的数字的 rope,该 rope 是最短的 rope,其中同一列表中每对相邻的数字都按递增顺序排列。

提醒quotient 过程执行向下取整除法,类似于 Python 中的 //remainder 过程类似于 Python 中的 %

(define (up n)
(define (helper n result)
(if (zero? n) result
(helper (quotient n 10)
(let ((first (remainder n 10)))
(cons first (if (null? result) '() (list result)))))))
(helper (quotient n 10) '()))

(expect (up 314152667899) '(3 (1 4 (1 5 (2 6 (6 7 8 9 (9)))))))

Run in 61A Code

first(car result) 进行比较,以决定是将值 first consresult 上,还是形成一个包含 firstresult 作为元素的新列表。

为了从 up 中正确调用 helper,需要构建一个仅包含 n 的最后一位数字的 rope,即 (remainder n 10)

SQL

SELECT 查询语句描述了基于输入行的输出表。要编写一个:

  1. 使用 FROMWHERE 子句来描述输入行
  2. 对这些行进行分组,并使用 GROUP BYHAVING 子句来确定哪些分组应该作为输出行显示。
  3. 使用 SELECTORDER BY 子句来格式化和排序输出行和列。

SELECT (步骤 3) FROM (步骤 1) WHERE (步骤 1) GROUP BY (步骤 2) HAVING (步骤 2) ORDER BY (步骤 3);

步骤 1 可能涉及连接多个表(使用逗号分隔),从而形成由现有表中两行或多行数据组成的输入行。

WHEREGROUP BYHAVINGORDER BY 子句是可选的。

Q4:一个秘密消息

替换密码用表中的另一个单词替换每个单词,以加密消息。 要解码加密消息,请将每个单词 x 替换为代码表中对应的 y

编写一个 select 语句,使用 code 表解码 original 消息 It's The End

 CREATE TABLE original AS
SELECT 1 AS n, "It's" AS word UNION
SELECT 2, "The" UNION
SELECT 3 , "End";

CREATE TABLE code AS
SELECT "Up" AS x, "Down" AS y UNION
SELECT "Now", "Home" UNION
SELECT "It's" , "What" UNION
SELECT "See", "Do" UNION
SELECT "Can", "See" UNION
SELECT "End", "Now" UNION
SELECT "What" , "You" UNION
SELECT "The", "Happens" UNION
SELECT "Love" , "Scheme" UNION
SELECT "Not", "Mess" UNION
SELECT "Happens", "Go";
SELECT "REPLACE THIS LINE WITH YOUR SOLUTION";

在 61A 代码环境中运行

连接 original 表和 code 表,并确保连接后的行中 wordx 的值相同。

现在会发生什么? 编写另一个 select 语句,使用相同的 code 表解码此加密消息。

CREATE TABLE original AS
SELECT 1 AS n, "It's" AS word UNION
SELECT 2 , "The" UNION
SELECT 3 , "End";

CREATE TABLE code AS
SELECT "Up" AS x, "Down" AS y UNION
SELECT "Now" , "Home" UNION
SELECT "It's" , "What" UNION
SELECT "See" , "Do" UNION
SELECT "Can" , "See" UNION
SELECT "End" , "Now" UNION
SELECT "What" , "You" UNION
SELECT "The" , "Happens" UNION
SELECT "Love" , "Scheme" UNION
SELECT "Not" , "Mess" UNION
SELECT "Happens", "Go";

SELECT "REPLACE THIS LINE WITH YOUR SOLUTION";

在 61A 代码环境中运行

original 表与 code AS acode AS b 连接起来,会生成类似这样的六列数据行:2|The|The|Happens|Happens|Go,其中末尾的 Go 就是解码后的消息片段。

时间安排: 这是最后一次讨论课了,不过大家可以约一下,下周和组员们一起复习备考。如果需要,你们平时的讨论室和时间在 RRR 周仍然可以使用。

记录这一时刻

请大家填写出勤表(每周每人提交一份)。

重要提示: 离开前,请大家帮忙把房间里的家具恢复原位。 谢谢合作!