Scala : Recursion Homework-1

本文通过三个递归函数的实现,详细介绍了如何解决Pascal三角形元素计算、括号平衡验证及硬币组合计数问题。每部分都提供了清晰的解题思路和代码示例,帮助读者掌握递归在不同场景下的应用。

习题来自于这里的公开课 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

转载于:https://my.oschina.net/placeholder/blog/88314

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值