Test #1 Review

February 8, 2021

Assignment Comments, Sample Solutions

Writing Recursive Functions

Your only task is to simplify the original problem, or to solve it directly when simplification is either unnecessary or impossible; the Recursion Fairy will solve all the simpler subproblems for you, using Methods That Are None Of Your Business…

The Recursion Fairy is the inductive hypothesis.

Candy Swap Saga

  • If you swap your candy for another candy of the same type, you earn one point.
  • If you swap your candy for a candy of a different type, you lose one point.
  • If you visit an animal and decide not to swap candy, your score does not change.

Would the greedy algorithm work?

Recursive Specification in English

Find the highest possible score by comparing:

  • The highest score for the rest of the animals after choosing to swap, versus
  • The highest score for the rest of the animals after choosing not to swap.

To make the decision for animal[i], let the Recursion Fairy give you the maximum score for the rest of the animals. (No for-loop needed.)

Recursive Description

CandySwap(i,h):
  if h=C[i]:
    point <- 1
    if i=n:
      return 1
  else:
    point <- -1
    if i=n: 
      return 0
  else:
    swap <- point + CandySwap(i+1, C[i])
    skip <- CandySwap(i+1, h)
    return max(swap, skip)

Dependencies, data structure, evaluation order

  • At any point in the recursive problem, the subproblems are CandySwap(i+1, held_candy) and CandySwap(i+1, animals[i]).

  • We can memoize past results in a 2-dimensional array CS based on the two input values. The first value we can fill in is CS[n+1][1..3] = 0, and from there we can go in descending order with n, n-1, n-2, et cetera.

Dynamic Programming Solution

CandySwapMemo(h):
  initialize CS[n, *] to 0 for 0 < * < 4
  CS[n,C[n]] <- 1   
  for i <- (n-1) down to 1:   
    for j <- 1 to 3:   
      if C[i]=j:   
        point <- 1   
      else: 
        point <- -1   
      swap <- point + CS[i+1, C[i]]   
      skip <- CS[i+1,j]
      CS[i,j] <- max(swap, skip)
  return CC[1, h]

Time: \(O(n)\), Space: \(O(n)\)

Can improve space

Note: you can make it constant space, since the solution only depends on the previous subproblem

C[1..n]       // the types of candy held by each animal
PrevMSC[1..3] // memoization structure for max scores of candy, depending on current candy held
tmp[1..3]     // a temporary array for storing max scores of candy
FastMaxScoreCandy(CurrentCandy):
    PrevMSC[C[n]] <- 1                    // we can get a point in the end if we swap
    PrevMSC[all candies except C[n]] <- 0 // or maybe we stick with what we have
    from animal <- n-1 down to 1:
        for candy <- 1..3:
            if candy is C[animal]:
                DoSwapScore <- 1 + PrevMSC[C[animal]]
            otherwise
                DoSwapScore <- -1 + PrevMSC[C[animal]]
            DontSwapScore <- PrevMSC[candy]
            tmp[candy] <- max(DoSwapScore, DontSwapScore)
        copy tmp -> PrevMSC
    return PrevMSC[CurrentCandy]

Candy Swap Saga: Recursive Solution in R

set.seed(4323)
candyTypes <- c("peanut", "heath", "truffle")
n <- 20
animalCandy <- sample(candyTypes, n, replace=TRUE)

maxScore <- function(i, myCandy) { # max score from visiting animals i..n holding myCandy
  if(i > n)
    return(0)
  if(myCandy == animalCandy[i])
    swap <- 1 + maxScore(i+1, myCandy)
  else
    swap <- -1 + maxScore(i+1, animalCandy[i])
  same <- maxScore(i+1, myCandy)
  return(max(swap, same))
}

Candy Swap Saga: Iterative Solution in R

FastMaxScore <- function() {
  S <- matrix(rep(0, 3*(n+1)), nrow = n+1, ncol = 3)
  for(i in n:1) {
    currentAnimalCandyNum <- which(candyTypes == animalCandy[i])
    # holding peanut: Score goes in S[i, 1]
    # holding heath: Score goes in S[i, 2]
    # holding truffle: Score goes in S[i, 3]
    for(myC in 1:3) {
      if(candyTypes[myC] == animalCandy[i])
        swap <- 1 + S[i+1,myC]
      else
        swap <- -1 + S[i+1,currentAnimalCandyNum]
      same <- S[i+1, myC]
      S[i, myC] <- max(swap, same)
    }
  }
  return(S[1,1])
}

Tests

n <- 4
animalCandy <- c("heath", "heath", "heath", "heath")
maxScore(1, "peanut")
[1] 2
FastMaxScore()
[1] 2
set.seed(4323)
candyTypes <- c("peanut", "heath", "truffle")
n <- 20
animalCandy <- sample(candyTypes, n, replace=TRUE)
FastMaxScore()
[1] 9

Timing Experiments

system.time(maxScore(1, "peanut"))
   user  system elapsed 
  1.833   0.007   1.843 
system.time(FastMaxScore())
   user  system elapsed 
      0       0       0 

Test #1 Contents

Study Guide on Canvas

Practice Exercises

Table Groups

Table #1 Table #2 Table #3 Table #4 Table #5 Table #6 Table #7
Josiah Andrew Blake Claire Jordan James Grace
John Trevor Bri Jack Logan Isaac Kristen
Nathan Kevin Drake Levi Ethan Graham Talia