Coursera公开课Functional Programming Principles in Scala习题解答:Week 1

引言

工作之余参加了Coursera的公开课Functional Programming Principles in Scala,这个课是第三次开讲了,讲师仍然是Scala的祖师爷Martin Odersky先生。个人认为学习公开课最大的阻碍在于有些老师的口音实在是……不忍直视,比如最早在Coursera开授公开课的Andrew Ng(当然他现在是小老板了)。幸好Martin大爷的英文口音不是很重,而且课程也不是很难,大家有兴趣可以去学习一下,地址在这里:https://class.coursera.org/progfun-004

好了,烟鬼正转,转到文章的主题上来。每周的课程是通过在线的Video Lectures来进行的,你可以自行在线观看或者下载到本地,当然在线观看是有字幕的。本地观看你只能自求有字幕组去制作外挂字幕咯。Video Lectures之后会有Assignments,也就是所谓的作业,只有完成了这些作业并提交,才有可能完成这门课的学习哦。

值得一提的是,每周作业的提交会有一个soft deadline和hard deadline,其中前者也叫做due date,就是应该上交作业的最后期限。在due date之前上交作业,作业的分数会根据你作业的质量来决定,在due date之后没延迟一天,作业的分数为实际分数*(1-20%*延迟的天数)。如果你聪明的话,应该算到due date五天之后提交的作业无论多完美,分数都会为0了……恩,hard deadline就是due date后的第五天。

为了防止误操作,也为了给童鞋们一个改过自新,哦不是止于至善的机会,每周作业最多有5次提交机会。作业的分数按照5次中得分最高的那次计算(业界良心啊!)。

废话不多说,现在讲解自己关于Week 1作业的思路。

Week 1主要讲Function & Evaluation,内容是函数式编程的一些基本概念、Scala的基本语法以及讲了一个递归和尾递归(尾递归会在后续博文中涉及……玛德我又给自己挖坑%>_<%)。总体来说比较简单,关于课程内容这里就不多做介绍,正式进入习题讲解。

本周一共有三道题目,都是在下载后Eclipse工程中的Main.scala文件中完成代码编写。

Exercise 1

Exercise 1是关于杨辉三角的(原文成为Pascal‘s Triangle):

    1
   1 1
  1 2 1
 1 3 3 1
1 4 6 4 1
   ...

这个相信大家都不陌生,应该小学的时候就见过。为了照顾低年级同学我还是简单介绍一下,杨辉三角左右两条边上的元素都为1,内部的元素值为其上面两个元素的和。第一个作业就是要写一个函数,任意给定元素的位置(以行和列的形式),求出其值。

怎么样,简单吧?人家还给出了函数原型:

def pascal(c: Int, r: Int): Int

OK,现在就来分析一下。碰到这种问题,我们首先想到就是使用递归来做,那么递归一般来讲有两个要素,递归调用关系和终止条件。

1.递归调用关系:杨辉三角的性质已经决定了,元素的值等于其上一行的两个元素值之和,即Value(c, r) = Value(c, r - 1) + Value(c - 1, r - 1)。这样就可以看到Value的两个参数会越来越小,直到达到终止条件;

2.终止条件:杨辉三角的左右两条边上的元素均为1,即Value(0, r) = 1, Value(x, x) = 1,其中前者表示左边上的元素、后者表示右边上的元素

有了以上两个条件,我们的代码就水稻渠成了!

  /**
   * Exercise 1
   */
  def pascal(c: Int, r: Int): Int =
  {
    if(0 == c || c == r) 1 else pascal(c - 1, r - 1) + pascal(c, r - 1)
  }

Exercise 2

第二个作业是Parentheses Balancing,就是括号匹配。函数原型如下:

def balance(chars: List[Char]): Boolean

以List[Char]的形式给出一个字符串,字符串内包含若干左括号和右括号,要求判定其中的括号是否能够匹配。若能返回true,否则返回false。

题目中各给出了两个正反例:

(if (zero? x) max (/ 1 x))
I told him (that it’s not (yet) done). (But he wasn’t listening)
:-)
())(

其中前两个是正例,我们可以看到其中的左右括号完全匹配,应该返回true;后两个是反例,其中第三个只有右括号没有左括号,第四个的左右括号不匹配。

我们仍然用递归来解这道题目,初步观察输入数据中会包含非括号字符,这些字符对我们的处理过程会造成一定的麻烦,并且去掉他们之后不会对结果有影响。所以我们在预处理部分首先去掉输入中的非括号字符。

剩下的就都是括号了,按照递归的思路,我们仍然要确定递归调用关系和终止条件:

1.递归调用关系:相信大家都玩过俄罗斯方块,当一行的所有像素都被填满实体时,则消除此行。我们在此处也借用这种方法,那么我们就要思考,在什么情况下可以去掉一对括号呢?有三种情况:字符串的前两个分别是(和)时;字符串的最后两个分别是(和)时;字符串的首尾分别是(和)时。那么,消除的次序对结果是否有影响呢?我们来看一个简单的例子:()(),这个输入符合以上的三种可以消除的情况,那么应该先按照哪种情况来消除呢?明显地,如果按照第三种情况消除首尾,那么剩下的)(就不能匹配了,这就造成了错误的判断。如果首先按照前两种情况消除括号对就不会出现这种问题。所以消除的次序应该是将第三种情况放到最后。

2.终止条件:从递归调用关系可以观察到,在一直有括号匹配的情况下,字符串的长度会越来越短,当长度为0时,我们到达了一个边界,在这个边界上我们可以返回true。另外,因为括号都是成对匹配的,所以当字符串的长度为奇数时,我们可以直接返回false。最后,如果满足消除条件的三种情况都不存在,也需要返回false。

所以代码如下(我们定义了一个辅助函数):

  /**
   * Exercise 2
   */
  def balance(chars: List[Char]): Boolean =
  {
    val filterChars = chars.filter((c: Char) => (c == ‘(‘ || c == ‘)‘))
    balance_clear(filterChars)
  }

  def balance_clear(filterChars: List[Char]): Boolean =
  {
    val length = filterChars.length
    if(0 == length) true
    else if(length % 2 != 0) false
    else if(filterChars.apply(0) == ‘(‘ && filterChars.apply(1) == ‘)‘) balance_clear(filterChars.slice(2, filterChars.length))
    else if(filterChars.apply(filterChars.length - 2) == ‘(‘ && filterChars.apply(filterChars.length - 1) == ‘)‘) balance_clear(filterChars.slice(0, filterChars.length - 2))
    else if(filterChars.head == ‘(‘ && filterChars.last == ‘)‘) balance_clear(filterChars.slice(1, filterChars.length - 1))
    else false
  }

Exercise 3

第三道题目是Counting Change,也就是算法界著名的换零钱系列问题之一。

题目给定一个数额以及零钱的种类,要求计算出使用零钱种类分解数额的可能方案个数。函数原型如下:

def countChange(money: Int, coins: List[Int]): Int

同样考虑递归调用关系和终止条件:

1.递归调用关系:从零钱种类中拿出一个零钱面值coin,那么金额money的换零钱方式有两种:要么使用零钱面值coin,要么不使用。 如果不使用零钱面试coin,那么money的换零钱方式就等于使用去掉面值coin后的零钱种类分解money;如果使用零钱面试coin,那么money的换零钱方式为money - coin使用原始零钱种类换取的方式。

这个地方说的可能比较绕。概括的说,将总数为money的现金换成n种零钱的不同方式的数目等于:

a.将现金数money换成除第一种零钱外的所有其他零钱的不同方式数目,加上

b.将现金数money - coin换成所有种类的零钱的不同方式数目

其中coin为第一种零钱的面值,a、b中第一种零钱可以替换成任意一个零钱面值。

2.终止条件:因为在递归调用关系中,money和零钱集合都是缩小的,所以考虑边界情况:

a.如果money为0,则换取零钱的方式有1种,即所有面值零钱的个数为0

b.如果money小于0,则换取零钱的方式有0种

c.如果零钱集合为空,则换取零钱的方式有0种

这三种边界条件的判断先后关系是否影响结果呢?太晚了不想分析了,留给大家去思考吧

好,贴代码:

  /**
   * Exercise 3
   */
  def countChange(money: Int, coins: List[Int]): Int =
  {
    if(0 == money) 1
    else if(coins.isEmpty) 0
    else if(money < 0) 0
    else countChange(money, coins.tail) + countChange(money - coins.head, coins)
  } 

到此为止,Week 1的三个作业全都分析完成。总体来看还是比较简单的。本人代码写的很粗糙,如果有一起上这门课的,还望不吝赐教。

你也可以在GitHub上获取所有我关于这门课的作业代码:https://github.com/WangTaoTheTonic/Functional-Programming-Principles-in-Scala

参考:

《计算机程序的构造和解释》 Harold Abelson, Gerald Jay Sussman, Julia Sussman著,裘宗燕 译

声明:

本文为原创,禁止用于任何商业目的,转载请注明出处:http://blog.csdn.net/asongoficeandfire/article/details/25251709

Coursera公开课Functional Programming Principles in Scala习题解答:Week 1

时间: 2024-08-11 07:49:41

Coursera公开课Functional Programming Principles in Scala习题解答:Week 1的相关文章

Coursera公开课Functional Programming Principles in Scala习题解答:Week 2

引言 OK.时间很快又过去了一周,第一周有五一假期所以感觉时间绰绰有余,这周中间没有假期只能靠晚上加周末的时间来消化,其实还是有点紧张呢!后来发现每堂课的视频还有对应的课件(Slide).字幕(subtitles)可以下载,这样下载视频学习和在线学习就只差课程中间的Exercise了 Week 2主要讲函数,函数在Scala里是first-class citizen,可以在任意域内出现,这门课其实也是在借Scala来讲函数式编程原理.好了,不多说,进入习题解析. 这周的作业主要是使用函数来表示一

Coursera公开课Functional Programming Principles in Scala习题解答:Week 3

引言 这周的作业其实有点复杂,需要完成的代码有点多,有点绕.本周的课程主要讲了Scala中的类.继承和多态,作业也很好的从各个方面考察了课程的内容.作业题目工程主要需要完成的部分是TweetSet.scala这个文件中的内容,比较新潮,都是和推特相关.其中定义了一个抽象类TweetSet,以及其的两个子类Empty.NonEmpty,表示空集和非空集.非空集使用二叉树来表示,二叉树的根是一个Tweet类对象,表示一条推特(用天朝的话来说叫做"微博"),一条微博哦不,一条推特包含user

斯坦福大学机器学习公开课:Programming Exercise 2: Logistic Regression

斯坦福大学机器学习公开课:Programming Exercise 2: Logistic Regression---Matlab实现 1 Logistic Regression In this part of the exercise, I will build a logistic regression model to predict whether a student gets admitted into a university. You want to determine each

Coursera公开课笔记: 斯坦福大学机器学习第七课“正则化”

Coursera公开课笔记: 斯坦福大学机器学习第七课"正则化" NLPJob 斯坦福大学机器学习第七课"正则化"学习笔记,本次课程主要包括4部分: 1) The Problem of Overfitting(过拟合问题) 2) Cost Function(成本函数) 3) Regularized Linear Regression(线性回归的正则化) 4) Regularized Logistic Regression(逻辑回归的正则化) 以下是每一部分的详细解读

Apply Functional Programming Principles

Apply Functional Programming Principles Edward Garson FUNCTiONAL PROGRAMMiNG has recently enjoyed renewed interest from the mainstream programming community. Part of the reason is because emergent properties of the functional paradigm are well positi

Functional Programming Principles in ScalaScala函式编程原理 第一章笔记

所有non-trival编程语言都提供了 基本表达式(expression)去表示最简单的表达式 组合表达式的方法 抽象表达式的方法,也就是为表达式引入一个名字去引用它 substitional model 替代模型 sumOfSquares(3,2+2) sumOfSquares(3,4) square(3)+square(4) 9+square(4) 9+16 25 这种模型的核心概念是所有的表达式都规约成值,替代模型在lamada表达式中被形式化,构成了函数式编程的基石 substitio

Coursera公开课机器学习:Linear Regression with multiple variables

多特征 实际上我们真正买过房子的都知道,在选择房子的时候,需要考虑的不仅仅是面积,地段.结构.房龄.邻里关系之类的都应该是考虑对象,所以前面几讲谈论的,单纯用面积来谈房价,不免失之偏颇. 多考虑些特性 我们加入一些特性来考虑房价问题: 符号解释 $n$:特性数目 $x ^{(i)}$:输入的第$i$个训练数据 $x ^{(i)} _j$:第$i$个训练数据的第$j$个特性 $h _\theta (x)$ 相应的,$h _\theta (x)$也就变了: $h _\theta (x) = \the

Coursera公开课机器学习:Introduction

机器学习的定义 Arthur Samuel (1959). Machine Learning: Field of study that gives computers the ability to learn without being explicitly programmed. Tom Mitchell (1998) Well-posed Learning Problem: A computer program is said to learnfrom experience E with r

Coursera公开课机器学习:Linear Algebra Review(选修)

这节主要是回顾了下线性代数的一些简单知识. 矩阵与向量 矩阵 由$m\times n$个数$a _{ij}(i=1,2,...,m;j=1,2,...,n)$排成的$m$行$n$列的数表,称为$m$行$n$列的矩阵,简称$m\times n$矩阵,记作: $$ \matrix{A}= \begin{bmatrix} a _{11} & a _{12} & \cdots & a _{1n} \cr a _{21} & a _{22} & \cdots & a