习题来自于这里的公开课 https://class.coursera.org/progfun-2012-001/
1. Exercise 1: Pascal’s Triangle
The following pattern of numbers is called Pascal’s triangle.
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
...
The numbers at the edge of the triangle are all1, and each number inside the triangle is the sum of the two numbers above it. Write a function that computes the elements of Pascal’s triangle by means of a recursive process.
Do this exercise by implementing thepascalfunction inMain.scala, which takes a columncand a rowr, counting from0and returns the number at that spot in the triangle. For example,pascal(0,2)=1,pascal(1,2)=2andpascal(1,3)=3.
def pascal(c: Int, r: Int): Int
解题思路:每个数是它上面里个数之和。
我的答案:
def pascalTriangle(column: Int, row: Int): Int = {
if (column == 0) 1
else if (row == 0) 0
else pascalTriangle(column - 1, row - 1) + pascalTriangle(column, row - 1)
}
Console:
println(pascalTriangle(0, 2)) //1
println(pascalTriangle(1, 2)) //2
println(pascalTriangle(1, 3)) //3
println(pascalTriangle(4, 6)) //15
>>>>>>>>>>>>split line>>>>>>>>>>>>>>>>>
2. Exercise 2: Parentheses Balancing
Write a recursive function which verifies the balancing of parentheses in a string, which we represent as aList[Char]not aString. For example, the function should returntruefor the following strings:
- (if (zero? x) max (/ 1 x))
- I told him (that it’s not (yet) done). (But he wasn’t listening)
The function should returnfalsefor the following strings:
- :-)
- ())(
The last example shows that it’s not enough to verify that a string contains the same number of opening and closing parentheses.
Do this exercise by implementing thebalancefunction inMain.scala. Its signature is as follows:
def balance(chars: List[Char]): Boolean
There are three methods onList[Char]that are useful for this exercise:
- chars.isEmpty: Booleanreturns whether a list is empty
- chars.head: Charreturns the first element of the list
- chars.tail: List[Char]returns the list without the first element
Hint: you can define an inner function if you need to pass extra parameters to your function.
Testing: You can use thetoListmethod to convert from aStringto aList[Char]: e.g."(just an) example".toList.
解题思路:如果使用java非递归来实现,会有一个stack来记录入栈和出栈, 遇到'('时入栈, 遇到')'时弹出栈顶,最后判断栈是否为空。此时要求使用递归,那么要用一个中间变量保存这样的入栈和出栈信息。
我的答案:
def balance(chars: List[Char]): Boolean = {
//inner function
def helper(chars: List[Char], likeStack: Int): Boolean = {
if (likeStack < 0) {
false
}
else {
chars match {
case Nil => if (likeStack == 0) true else false
case '(' :: rest => helper(rest, likeStack + 1)
case ')' :: rest => helper(rest, likeStack - 1)
case head :: rest => helper(rest, likeStack)
}
}
}
helper(chars, 0)
}
Console:
println(balance("(if (zero? x) max (/ 1 x))".toList)) //true
println(balance("I told him (that it’s not (yet) done). (But he wasn’t listening)".toList)) //true
println(balance(":-)".toList)) //false
println(balance("())(".toList)) //false
>>>>>>>>>>>>split line>>>>>>>>>>>>>>>>>
Exercise 3: Counting Change
Write a recursive function that counts how many different ways you can make change for an amount, given a list of coin denominations. For example, there are 3 ways to give change for 4 if you have coins with denomiation 1 and 2: 1+1+1+1, 1+1+2, 2+2.
Do this exercise by implementing thecountChangefunction inMain.scala. This function takes an amount to change, and a list of unique denominations for the coins. Its signature is as follows:
def countChange(money: Int, coins: List[Int]): Int
Once again, you can make use of functionsisEmpty,headandtailon the list of integerscoins.
Hint: Think of the degenerate cases. How many ways can you give change for 0 CHF? How many ways can you give change for >0 CHF, if you have no coins?
这一题对我来说有些难度,询问了同学,同学认为是SICP一书第一章的泛化,答案借助了谷歌:
连接:主题:有1元,5元,10元,20元,50元,问组成100元有多少种情况
量化后的一种答案(比较好理解),countingChanges函数返回List,其size即为结果:
def countingChanges() = {
for (a <- (0 to 2); b <- (0 to 5); c <- (0 to 10); d <- (0 to 20);
e <- (0 to 100); if ((50 * a + 20 * b + 10 * c + 5 * d + 1 * e) == 100))
yield (a, b, c, d, e)
}
Eastsun大神给予了答案:
scala> def count(vs: List[Int],all: Int): Int = vs match {
| case Nil => if(all == 0) 1 else 0
| case x::xs => (0 to all/x).map{ n => count(xs,all-x*n) }.sum
| }
count: (vs: List[Int],all: Int)Int
scala> count(50::20::10::5::1::Nil,100)
res2: Int = 343
上述count函数使用标记的方式来计算总个数,对于每次划分,如果本次能够正好划分,就标记本次为1;否则标记为0。第一个case语句说明了函数返回的条件,这也是一般递归函数定义时必不可少的一步;第二个case有点抽象不好懂,总的来说就是按照第一个元素(50)来划分,再把剩余的部分划分。(0 to all/x)表示能够使用第一个元素划分的次数,对于此时的每一次划分,都要分解剩余部分。最后一个sum计算结果List(...1,0,1...0,0,1...)的总和,即最终能被完全分解的总个数(因为不能分解的已经标注为0了)。
--END