Discussion 4: Recursive Methods
The goal of today’s discussion is to practice thinking recursively by developing some recursive methods involving Strings. You’ll also get some practice visualizing the call structure of a recursive method and using this to analyze its time and space complexity. As we will soon see, recursion is a powerful tool for developing sorting algorithms such as Merge Sort and Quicksort. It’s also useful when working with data structures such as trees and graphs, for which many natural traversal algorithms are most elegantly expressed recursively.
Learning Outcomes
- Visualize the state of the runtime stack in a program involving multiple method calls and/or recursion.
- Develop recursive methods in Java given their specifications.
- Determine the number of recursive calls and the maximum depth of the call stack of a recursive method and use these to compute its time and space complexities.
The isPalindrome() Method
A String is a palindrome if it reads the same forwards and backwards. For the purpose of this discussion, we’ll ignore case sensitivity.
By applying this definition, we can conclude that:
"racecar"is a palindrome."Madam"is a palindrome (ignoring case)."hello"is not a palindrome."a"is a palindrome (start thinking about base cases!).""(empty string) is also a palindrome.
The goal of this discussion is to gain exposure to recursive thinking using a classic problem that can be defined in terms of smaller, structurally identical problems.
static method isPalindrome() that returns whether a given String is a palindrome.
String methods that you may find helpful are listed at the end of this handout.
Strings before we start our recursive implementation. Looking at the examples from earlier, how should we format the String?
isPalindrome() method, we should first check for the simplest possible inputs. When can we directly know that a String is a palindrome without needing to do any work?
String should be the argument to this recursive call, and how do we obtain this smaller String? How should we use the result of the recursive call to finish our definition of the method?
String of length \(N\), let's think about the time and space complexities of the isPalindrome() method.
isPalindrome() method on a String of length \(k\). By summing this over all of the recursive calls in the stack, what is the overall time complexity of isPalindrome() in terms of the original input length \(N\)?
isPalindrome() on a String of length \(k\)? By summing this over all of the recursive calls in the stack, what is the overall space complexity of isPalindrome()?
isPalindrome() by adopting a similar strategy to the "array views" that we saw in lecture.
rangeIsPalindrome(String s, int i, int j) that returns whether s.substring(i,j) is a palindrome, and use this to re-implement isPalindrome() (which should only handle the pre-processing and call this helper method).
Useful String Methods
Here, we summarize some methods from Java’s String class that may be useful for the problems that follow.
int length()
[Documentation]
This method returns the number of characters comprising a String and runs in \(O(1)\) time (constant, not depending on the length of the String).
char charAt(int index)
[Documentation]
This method returns the character located at the specified index within the String (where the first, leftmost index is 0). It runs in \(O(1)\) time (constant, not depending on the length of the String).
String substring(int beginIndex, int endIndex)
[Documentation]
This method returns a new string that is a portion of the original string. The substring begins at beginIndex and extends to the character at endIndex - 1. The endIndex is exclusive. It runs in time \(O(\)endIndex - beginIndex\()\), the length of the substring that is constructed and returned.
String toLowerCase()
[Documentation]
This method returns a new string in which all characters have been converted to lowercase. It runs in \(O(N)\) time, where \(N\) denotes the length of the String.