知识焦点
先建立概念地图
- study group
- course policies
- academic honesty
- logarithms
- proofs
- recurrence relations
- asymptotic notation
- polynomial vs exponential
CS170 · 作业 1
UC Berkeley CS 170 Fall 2023 第一次作业,涵盖课程分组、课程政策、学术诚信、数学基础(对数与恒等式证明)、递推关系求解、介于多项式与指数之间的函数构造,以及十进制转二进制的分治编码题。
知识焦点
建议顺序
先完整作答,再按需展开提示;最后才展开官方参考解答并逐步核对证明与计算。
本地来源
题面与解答均由本地一手资料整理:hw01.pdf、hw01-sol.pdf
本地一手资料完整提取 · 作业
本节按本地一手资料完整整理,共 7 道大题。本地官方解答已完整收录并默认折叠;建议先独立完成,再逐题核对推导。
hw01.pdf、hw01-sol.pdf列出你的学习小组中所有成员的姓名与 SID(学生编号)。如果你没有合作者,则必须明确写出 "none"。
这是作业提交的形式要求,直接据实填写即可;没有特别的解题思路。
学生根据自身情况填写即可。
解答来源:hw01-sol.pdf · 1 · confidence: high
题面来源:hw01.pdf · 1 · confidence: high
请阅读 https://cs170.org/syllabus/ 上的教学大纲与课程政策,并回答以下问题。
(a) 本学期 CS170 的考试时间与时刻分别是什么?是否安排有备用(alternate)考试?注意:我们会为时区相差较远的同学做出特别安排。
(b) 作业在每周一晚上 10:00 pm 截止,晚交(late)截止时间为 11:59 pm。你认为我们建议你把作业在什么时间之前完成?
(c) 课程提供 2 次作业丢弃(homework drops),用于应对作业提交中可能出现的紧急情况或技术问题。如果你错过了 Gradescope 的晚交截止时间(哪怕只是晚了几分钟),并仍希望提交作业,你应该怎么做?
(d) CS170 用来向学生发布信息的首要(primary)沟通渠道是什么?我们会通过这一媒介发布所有重要截止时间,你有责任查看邮件并完整阅读每一条通知。
(e) 请阅读以下全部内容:
Syllabus and Policies: https://cs170.org/syllabus/
Homework Guidelines: https://cs170.org/resources/homework-guidelines/
Regrade Etiquette: https://cs170.org/resources/regrade-etiquette/
Forum Etiquette: https://cs170.org/resources/forum-etiquette/
阅读完毕后,请在你的作业提交中抄写并签名以下句子:
"I have read and understood the course syllabus and policies."
本题答案均来自课程主页 syllabus,可直接查阅。注意区分"截止日期"与"建议完成时间",以及"首要沟通渠道"的具体名称。
(a) Midterm 1: Tuesday 10/3, 7:00pm - 9:00pm PST;Midterm 2: Tuesday 11/7, 7:00pm - 9:00pm PST;Final: Friday 12/15, 8:00am - 11:00am PST。我们不计划提供备用考试。
(b) 10:00 pm。
(c) 这 2 次 homework drops 正是为了应对你在最后一刻出现问题并错过 Gradescope 截止时间的情况。由于截止时间后不久答案就会发布,因此不会批准作业延期(homework extensions),你什么都不用做。不过,我们会对 DSP 相关原因及同时影响多周的严重情况给予例外;如果你认为自己符合条件,请联系 cs170@。
(d) 首要沟通渠道是 Edstem。
(e) 抄写并签名:"I have read and understood the course syllabus and policies."(官方样例签名用了 Alan Turing。)
解答来源:hw01-sol.pdf · 1-2 · confidence: high
题面来源:hw01.pdf · 1 · confidence: high
在回答以下任何问题之前,请先仔细阅读教学大纲与课程政策(https://cs170.org/syllabus/)。对下面每一条陈述:如果该行为被课程政策所允许,请写 OK;否则写 Not OK。
(a) 你向一位曾经修过 CS 170 的朋友要他们的作业解答,其中有一部分与本学期的作业题重叠。你看了他们的解答,随后用自己的话写了下来。
(b) 你同一天有 5 门期中考试,作业落定了。你决定向已经完成作业的同学求助,他们告诉了你前三个问题的做法。
(c) 你上网查找了一道作业题,并找到了它的确切解答。随后你用自己的话写下来,并引用了来源。 (d) 你在网上查找 Dijkstra 算法时,无意间进入一个网站,上面有一道与你的作业题非常相似的题目。你阅读了该题,包括它的解答,然后关闭网站,从零写出了你的解答,并在作业中引用了该网站 URL。
判断的关键在于:你是否曾拥有过除自己解答之外的"确切作业解答",以及"事后引用"是否能弥补事先阅读答案的行为。
(a) Not OK.
(b) Not OK.
(c) Not OK。一般经验法则是:你绝不应该持有除自己解答之外的任何确切作业解答。
(d) OK。鉴于你是无意间在网上发现了该资源,请明确引用它,并确保从零写出你的解答。
解答来源:hw01-sol.pdf · 2 · confidence: high
题面来源:hw01.pdf · 1-2 · confidence: high
以下各小问将涉及一些在本课程其余部分会用到的数学恒等式、技巧与方法。
(a) 将下列表达式化简为一个对数(即写成 \(\log_a b\) 的形式):
(i) \(\displaystyle \frac{\ln x}{\ln y}\)
(ii) \(\ln x + \ln y\)
(iii) \(\ln x - \ln y\)
(iv) \(170 \ln x\)
(b) 证明下列恒等式:
(i) \(x^{\log_{1/x} y} = \frac{1}{y}\)
(ii) \(\displaystyle \sum_{i=1}^{n} i = \frac{n(n+1)}{2}\)
(iii) \(\displaystyle \sum_{k=0}^{n} a r^{k} = \begin{cases} a \cdot \frac{1-r^{n+1}}{1-r}, & r \neq 1 \\ a(n+1), & r = 1 \end{cases}\)
(a) 使用换底公式与对数的运算性质(积、商、幂)。 (b)(i) 把 \(x\) 写成 \(\ln x\) 的幂,或把 \(\log_{1/x} y\) 用自然对数展开;(b)(ii) 考虑正序与倒序配对;(b)(iii) 对 \(S_n\) 与 \(r S_n\) 作错位相减,并单独讨论 \(r=1\)。
(a) (i) \(\log_y x\)。 (ii) \(\ln (xy)\)。 (iii) \(\ln (x/y)\)。 (iv) \(\ln (x^{170})\)。
(b) (i) 由换底公式 \(\log_{1/x} y = \frac{\ln y}{\ln(1/x)} = \frac{\ln y}{-\ln x}\), \[x^{\log_{1/x} y} = x^{\frac{\ln y}{-\ln x}} = \bigl(x^{\frac{\ln y}{\ln x}}\bigr)^{-1}.\] 而 \(x^{\frac{\ln y}{\ln x}} = x^{\log_x y} = y\), 故整体等于 \(y^{-1} = \frac{1}{y}\)。
(ii) 设 \(S = \sum_{i=1}^{n} i = 1 + 2 + \cdots + (n-1) + n\)。将其正序与倒序相加配对: \[S = [1+n] + [2+(n-1)] + [3+(n-2)] + \cdots = \frac{n(n+1)}{2}.\]
(iii) 设 \(S_n = \sum_{k=0}^{n} a r^{k}\)。当 \(r \neq 1\) 时, \[S_n = a + ar + \cdots + ar^{n},\] \[rSn = ar + ar^{2} + \cdots + ar^{n+1}.\] 两式相减得 \((1-r) S_n = a - ar^{n+1}\), 因此 \[S_n = \frac{a - ar^{n+1}}{1-r} = a \cdot \frac{1-r^{n+1}}{1-r}.\] 当 \(r = 1\) 时,\(S_n = a + a + \cdots + a\)(共 \(n+1\) 项),故 \(S_n = a(n+1)\)。
解答来源:hw01-sol.pdf · 3 · confidence: high
题面来源:hw01.pdf · 2 · confidence: high
对每一小问,求 \(T(n)\) 的渐近增长阶,即找出一个函数 \(g(n)\) 使得 \(T(n) = \Theta(g(n))\)。请展示你的推理过程,不得直接套用主定理(master theorem)。在所有小问中,你可以忽略因取整(integer)带来的问题。
(a) \(T(n) = 3T(n/4) + 10n\)
(b) \(T(n) = 97T(n/100) + \Theta(n)\)
(c) 算法 A 需要 \(\Theta(n^{2})\) 的时间把输入划分为 5 个大小均为 \(n/5\) 的子问题,然后递归地在其中 3 个子问题上运行自身。试描述算法 A 的运行时间 \(T(n)\) 满足的递推关系,并求其渐近增长阶。
(d) \(T(n) = 3T(n/3) + \Theta(n)\)
(e) \(T(n) = T(3n/5) + T(4n/5)\)(已知 \(T(1) = 1\))
提示:试着猜一个形如 \(a n^{b}\) 的 \(T(n)\), 再用归纳法论证其正确性。
递归树:(a) 规模 n -> 3 个子问题 n/4,每层总工作量 10n * (3/4)^k;(d) 规模 n -> 3 个子问题 n/3,每层总工作量 cn,共 log_3 n 层。
来源:hw01.pdf · 2-3
(a)(b)(c) 的共同观察:在每一层递归上,子问题总规模相比该层输入都会减少一个常数比例,从而形成收敛的等比级数,总工作量由第一层主导。(d) 每层工作量同为 \(\Theta(n)\),而层数最多 \(\log n\) 层。(e) 先用 \(T(n) \ge 2T(n/2)\) 与 \(T(n) \le 2T(4n/5)\) 夹出指数范围,再代入 \(T(n)=n^{b}\) 解出 \(b\)。
(a) 将 \(T(n)\) 按递归树展开: \[T(n) = 10n + 3\bigl(10n/4 + 3T(n/16)\bigr) = 10n + 10\cdot\frac{3n}{4} + 10\cdot\frac{9n}{16} + 10\cdot\frac{27n}{64} + \cdots\] 该求和式为 \[T(n) = \sum_{k=0}^{\lfloor \log_{4} n \rfloor} \Bigl(\frac{3}{4}\Bigr)^{k}\cdot 10n \le \sum_{k=0}^{\infty} \Bigl(\frac{3}{4}\Bigr)^{k}\cdot 10n = \frac{1}{1-3/4}\cdot 10n = \Theta(n).\] 直观解释:每一层都有 3 个规模为 \(n/4\) 的递归调用,所以下一层输入总规模为 \(3n/4\),即每层会"丢掉" \(1/4\) 的输入,形成收敛的等比级数,总工作量与第一层同阶,为 \(\Theta(n)\)。
(b) 答案为 \(\Theta(n)\)。与 (a) 同理:递归调用数(97)小于子问题规模的分母(100),问题规模每次减少一个常数比例(\(3/100\)),运行时间由第一层的工作量 \(\Theta(n)\) 主导,无需主定理。
(c) 递推关系为 \(T(n) = 3T(n/5) + \Theta(n^{2})\)。与 (a)(b) 思路相同,每层都会丢掉输入规模/工作量中的一个常数比例,因此答案为 \(\Theta(n^{2})\)。
(d) 画出递归树,每一层的工作量之和都是 \(\Theta(n)\),而层数最多为 \(\log n\),因此整体运行时间为 \(\Theta(n \log n)\)。
(e) 主定理不能直接套用。采用如下两步: 首先给出上下界:由 \(T(n) \ge 2T(n/2)\) 得到 \(T(n) \ge \Omega(n)\);由 \(T(n) \le 2T(4n/5)\) 得到 \(T(n) \le O\bigl(n^{\log_{5/4} 2}\bigr)\)。由此猜测 \(T(n)\) 形如 \(a n^{b}\)。 由初值 \(T(1) = 1 = a\), 得 \(a = 1\), 即 \(T(n) = n^{b}\)。把它代回递推式: \[n^{b} = T(3n/5) + T(4n/5) = \Bigl(\frac{3}{5}\Bigr)^{b} n^{b} + \Bigl(\frac{4}{5}\Bigr)^{b} n^{b}.\] 两边除以 \(n^{b}\) 得到 \(\bigl(\frac{3}{5}\bigr)^{b} + \bigl(\frac{4}{5}\bigr)^{b} = 1\)。函数 \(f(b) = (3/5)^{b} + (4/5)^{b}\) 对 \(b > 0\) 单调递减,且 \(f(2) = 9/25 + 16/25 = 1\),故唯一正解为 \(b = 2\)。因此 \(T(n) = n^{2}\),答案是 \(\Theta(n^{2})\)。
解答来源:hw01-sol.pdf · 4-6 · confidence: high
题面来源:hw01.pdf · 2-3 · confidence: high
在本题中,我们要找一个函数 \(f(n)\),它渐近地比多项式时间差、但仍比指数时间好。也就是说,\(f\) 必须同时满足:
对所有常数 \(k > 0\),\(f(n) = \Omega(n^{k})\) (1)
对所有常数 \(c > 0\),\(f(n) = O(2^{cn})\) (2)
(a) 试着把 \(f(n)\) 取为一个次数 \(d\) 很大的常数多项式,即 \(f(n) = a_{0} + a_{1}n + a_{2}n^{2} + \cdots + a_{d}n^{d}\)。对哪些 \(k\)(如果有),\(f\) 会不满足 (1)?
(b) 再试着把 \(f(n)\) 取为 \(a^{n}\),其中 \(a\) 是尽可能小的常数但仍满足 (1)(例如 \(1.000001\))。对哪些 \(c\)(如果有),\(f\) 会不满足 (2)?
提示:先把 \(a^{n}\) 改写成 \(2^{bn}\),其中 \(b\) 是依赖于 \(a\) 的常数。
至此我们发现:形如 \(O(n^{d})\)(\(d\) 为常数)的函数增长太慢,而形如 \(O(a^{n})\) 的函数即使 \(a\) 非常小也增长太快。
(c) 找一个函数 \(D(n)\),使得令 \(f(n) = O\bigl(n^{D(n)}\bigr)\) 同时满足 (1) 与 (2)。并证明你的答案同时满足两者。
提示:请确保 \(D(n)\) 渐近地小于 \(n\)。
(a)(b) 分别考察多项式与指数在哪些常数下失败。(c) 的关键是让指数本身随 \(n\) 增长,但比线性慢:试试把 \(D(n)\) 取成对数级别。
(a) 当 \(k > d\) 时 \(f\) 不满足 (1),因为 \(n^{d}\) 的增长严格慢于 \(n^{k}\)。
(b) 当 \(c < \lg a\) 时 \(f\) 不满足 (2)。改写 \(a^{n} = 2^{n \lg a}\) 后可见,只要 \(c\) 小于 \(\lg a\),\(2^{cn}\) 的增长就会慢于 \(a^{n}\)。
(c) 取 \(D(n) = \lg n\)。则对任意常数 \(k\), \[f(n) = n^{\lg n} = \Omega(n^{k}),\] 因为 \((\lg n)^{2}\) 最终会超过任意常数 \(k \cdot \lg n\)。同时,对任意常数 \(c\), \[n^{\lg n} = 2^{(\lg n)^{2}} = O(2^{cn}),\] 因为 \((\lg n)^{2} = o(n)\)。 更一般地,凡满足 \(D(n) = o(n / \lg n)\) 的函数均可,因为此时 \(n^{D(n)} = 2^{\lg n \cdot D(n)} = 2^{o(n)}\)。
解答来源:hw01-sol.pdf · 6 · confidence: high
题面来源:hw01.pdf · 3-4 · confidence: high
给定一个数的 \(n\) 位十进制表示,用朴素方法把它转换为二进制需要 \(O(n^{2})\) 步。
(a) 给出一个分治算法,在 \(O(n^{\log_{2}3} \log n)\) 时间内完成该转换。
提示:参考课堂讲义,从 Karatsuba 算法(Karatsuba\'s algorithm)中汲取灵感!
(b) 写出来自 (a) 的算法的递推关系,并用它推导出期望的运行时间。
(c) 实现你的解答!请到 https://github.com/Berkeley-CS170/cs170-fa23-coding 并按照 README.md 中的指引,在本周的编码作业 hw01 中完成编码部分。
说明:
提交指引(Submission Instructions):请下载你完成的 decimal_to_binary.ipynb 文件,并提交到名为 "Homework 1 Coding Portion" 的 Gradescope 作业中。
OH/HWP 指引:我们会为作业中的编码部分提供概念性帮助,但 Office Hour (OH) 工作人员不会查看你的代码,也不会帮你调试。
学术诚信指引:我们意识到,要求你实现的某些算法在网上可能已有现成代码,但我们强烈建议不要直接照搬这些来源的代码。请改为参考 notebook 中提到的资源,自己编写代码。尽管如此,我们也承认某些算法可能实现方式并不多,你的解答可能与网上其他解答相似。
仿照 Karatsuba 算法,把 \(x\) 写成 \(10^{n/2}\cdot a + b\),其中 \(a, b\) 为两个 \(n/2\) 位数。递归地把 \(10^{n/2}, a, b\) 都转成二进制,再用一次乘法与一次加法拼出 \(x\) 的二进制表示。乘法用 Karatsuba 可在 \(O(n^{\log_{2}3})\) 完成。
(a) 与 Karatsuba 算法类似,把 \(x\) 写成 \(10^{n/2}\cdot a + b\),其中 \(a, b\) 为两个 \(n/2\) 位的十进制数。算法递归地计算 \(10^{n/2}, a, b\) 的二进制表示,然后用一次乘法和一次加法得到 \(x\) 的二进制表示。
(b) 在每一步递归上,我们把问题分成 3 个规模为一半的子问题。合并时,乘法耗时 \(O(n^{\log_{2}3})\),加法耗时 \(O(n)\)。于是得到递推式 \[T(n) = 3T(n/2) + \bigl[O(n^{\log_{2}3}) + O(n)\bigr] = 3T(n/2) + O(n^{\log_{2}3}).\] 用主定理或画出递归树均可得到解 \(O(n^{\log_{2}3} \log n)\)。 (事实上存在 \(O(n^{\log_{2}3})\) 的算法:我们可以通过依次计算 \(10 \cdot 10,\ 10^{2} \cdot 10^{2},\ 10^{4} \cdot 10^{4}, \ldots\) 来得到 \(10^{n}\) 的二进制表示——其中 \(10^{n/2} \cdot 10^{n/2}\) 的乘法主导这段计算的总时间。这给出递推式 \(T(n) = 2T(n/2) + O(n^{\log_{2}3})\),解为 \(T(n) = O(n^{\log_{2}3})\)。)
(c) 提供的编码实现如下:
def decimal_to_binary(decimal):
"""
args:
decimal: string = decimal representation of a number, passed as a string
returns:
A string representing the binary representation of the number
"""
# BEGIN SOLUTION
# base case
if not decimal:
return '0'
if len(decimal) == 1 or decimal == '10':
return digit_to_binary(decimal)
# split the decimal into halves and recursively
# generate the binary representation
lhs = decimal[:(len(decimal)+1)//2]
rhs = decimal[(len(decimal)+1)//2:]
power_of_10 = '1' + '0'*len(rhs)
lhs_bin = decimal_to_binary(lhs)
rhs_bin = decimal_to_binary(rhs)
power_of_10_bin = decimal_to_binary(power_of_10)
# reconstruct the original number by multiplying and adding
return add_binary(mul_binary(lhs_bin, power_of_10_bin), rhs_bin)
# END SOLUTION
该实现将十进制串平分为两半 lhs 与 rhs,构造 \(10^{\text{len(rhs)}}\) 的字符串 power_of_10,把三者分别递归转成二进制后,用 mul_binary 与 add_binary 合并得到原数的二进制表示。
解答来源:hw01-sol.pdf · 7-9 · confidence: high
题面来源:hw01.pdf · 3-4 · confidence: high
hw01.pdfhw01-sol.pdf