Title: Recursive Problem Solving
1Recursive Problem Solving
- Definition a recursive algorithm (method) to
solve a problem is an algorithm (method) that
calls itself to solve "a smaller version" of the
problem - Example
int factorial(int n) if (n lt 1) return
1 else return n factorial(n-1)
Base case
A recursive call solving a "smaller" problem
Local value (pertains to n)
Combined with.
2Avoiding Infinite Recursion.
int factorial(int n) if (n lt 0) throw
new IllegalArgumentException() else if (n lt
1) return 1 else return n
factorial(n-1)
3Variation on the Same Theme
- Sum of the squares of numbers from 1 to n
A recursive call solving a "smaller" problem
int sumSquares(int n) if (n lt 0)
return 0 else return (nn)
sumSquares(n-1)
Base case
Local value (pertains to n)
Combined with.
4Another Variation
- Sum the even numbers from 0 to n if n is even, or
0 to (n-1) if n is odd
int sumEvenNumbers(int n) if (n lt 0)
return 0 else if (n2 ! 0) return
sumEvenNumbers(n-1) else return n
sumEvenNumbers(n-2)
5"Helper Function"
- It's often cleaner and more convenient to
separate argument checking in one method and
recursion / computation in another
int sumEvenNumbers(int n) if (n lt 0)
throw new IllegalArgumentException() else if
(n2 ! 0) return sumEvenNumbersHelper(n-1)
else return sumEvenNumbersHelper(n)
// We know that n is gt0 and even int
sumEvenNumbersHelper (int n) return (n0) ?
0 (n sumEvenNumbersHelper(n-2))
6In-Class Example
- Fibonacci sequence
- undefined for n lt 0
- f(0) 0
- f(1) 1
- f(n) f(n) f(n-1) for n gt 1
- Count the number of primes between 1 and 1000
- Are there at least 10 primes between n and m (for
input n and m)?
7The Idea of a "Smaller Problem" or "Diminishing
Sequence"
- In the above example we are "recursing" or
iterating over the sequence 0, 1, 2, n - actually it's n, n-1, n-2, , 0 but that's a
detail - So the parameter n really is a shorthand for a
sequence of length n - and so at every recursive call the sequence gets
shorter - until the base case takes care of the situation
where the sequence diminishes to 0 - This can be extended to other sequences
- a String, where successive calls "shorten" the
sequence by taking off the first character, so
the String gets progressively shorter and the
base case takes care of the empty String - an array, where you begin with the array (a1,
, alength) then (a2, , alength) and the
base case takes care of the array with length 0
8Recursion Over Strings
int countWhitespace(String s) if
(s.equals("")) return 0 else if
(Character.isWhitespace(s.charAt(0))
return 1 countWhitespace(s.substring(1))
else return countWhitespace(s.substring(1)
)
boolean allDigits(String s) if
(s.equals("")) return true else if
(!Character.isDigit(s.charAt(0))) return
false else return
allDigits(s.substring(1))
9String Accumulation
String upperCaseCharacters(String s) if
(s.equals("")) return "" else if
(Character.isUpperCase(s.charAt(0))) return
upperCaseCharacters(s.substring(1)) else
return s.charAt(0) upperCaseCharacters(s.subst
ring(1))
String reverse(String s) if (s.equals(""))
return "" else return
s.charAt(s.size() 1) reverse(s.substring(1))
10Recursion over Arrays
- Arrays are sequences just like strings so they
are a natural candidate for recursive processing - The technical problem is that there is no
analogue to substring that produces a shorter
string - In lieu of "subarray" we instead pass in an index
or range of indexes into the array - Example
- sum the positive integers in the array
11Recursion and Binary Search
- Consider the problem of determining whether an
integer is in a collection (array) of integers - If the collection is not ordered (sorted), there
is no alternative to searching every element of
the array to determine the answer - Now suppose that the array is in sorted order
can we do better?
-4
-1
-1
62
63
900
1000
1000
12The Idea Behind Binary Search
- If you are searching for a value in an array of
size 0, you are unlikely to find it - If you are searching for a value in an array of
size 1, you can immediately determine whether
it's there - If the array is of size 2 or more
- split the array into two (almost) equal halves
- determine whether it's potentially in the left
half, the right half, or neither (but not both) - recursively search the appropriate half
13Recursion in Linked List Structures
- Lists are a lot like arrays, except that with
linked lists there is the equivalent of a
"substring" that allows you to "shorten" the list
easily for a recursive call
length 3
length 2
length 1
?
length 0
1
82
-3
14Conventional Magic Using Linked Lists
- Supposing a linked list of Strings
- compute the length of the list
- compute the total number of characters
- are all of the strings non-empty?
- retrieve the String at the ith element of the list
15Sheer Beauty
- Insert a new ith element
- add(index i, Object thing)
- Remove the first equal object
- remove(Object thing)
- Insert in the correct position into an ordered
list - add(Comparable thing)
- And just for fun reverse a linked list