Due before the start of lecture on October 28, 2025.
See below for a summary of the policies regarding late
submissions.
Homework is due prior to the start of lecture. If it is submitted more than 10 minutes after the start of lecture, it will be considered a full day late. There will be a 10% deduction for late submissions that are made by 11:59 p.m. on the Sunday after the deadline, and a 20% deduction for submissions that are made after that Sunday and before the start of the next lecture. We will not accept any homework that is more than 7 days late. Plan your time carefully, and don’t wait until the last minute to begin an assignment. Starting early will give you ample time to ask questions and obtain assistance.
Revised: Because PS 3 overlapped the midterm, we are waiving the usual late penalties for submissions made by 11:59 p.m. on the Sunday after the deadline, and we are reducing the usual 20% late penalty to 10%. If you submit during the usual 10% late window, Gradescope will still mark your submission as late, but we will not apply a late penalty.
In your work on this assignment, make sure to abide by our policies on academic conduct.
If you have questions while working on this assignment, please come to
office hours, post them on Ed Discussion, or email
cscie22-staff@lists.fas.harvard.edu
40 points total
Create a subfolder called ps3 within your
e22 folder, and put all of the files for this assignment in that
folder.
The problems from Part I will all be completed in a single PDF file. To create it, you should do the following:
Access the template that we have created by clicking on this link and signing into your Google account as needed.
When asked, click on the Make a copy button, which will save a copy of the template file to your Google Drive.
Select File->Rename, and change the name of the file to
ps3_partI.
Add your work for the problems from Part I to this file.
Once you have completed all of these problems, choose
File->Download->PDF document, and save the PDF file on your
machine. The resulting PDF file (ps3_partI.pdf) is the one that
you will submit. See the submission guidelines at the end of Part I.
8 points total; 4 points each part
Suppose that you have a linked list of integers containing nodes that are instances of the following class:
public class IntNode { private int val; private IntNode next; }
You may assume that the integers in these nodes are always positive.
Write a method named numMultRecur(first, n) that takes a
reference first to the first node in a linked list of IntNode
objects and an integer n, and that uses recursion to determine the
number of multiples of n in the list. (Hint: An integer
x is a multiple of n if the expression x % n evaluates to 0).
Write a method named numMultIter(first, n) that uses
iteration to perform the same task.
You do not need to code up these methods (or any method from Part I)
as part of a class. Simply put the methods in your ps3_partI file.
You may assume that the methods you write are static methods of the
IntNode class.
12 points total; 4 points each part
In lecture, we considered two different implementations of the list
ADT: ArrayList and LLList. For each of the following applications,
decide which list implementation would be better for that particular
application. Your should consider both time efficiency and space
efficiency, and you should assume that both implementations have an
associated iterator like the LLListIterator that we discussed in
lecture. Explain your answers.
You need to keep track of the orders placed to your online store. At the start of each month, you start with an empty list; as orders are made, you add them to the list. The number of orders varies greatly from month to month. You regularly display the list of orders, starting with the most recent order and working backwards chronologically towards the least recent one.
The human resources department in your company wants you to maintain its weekly list of workshops. The number of workshops is fairly consistent from week to week. The workshops will be added to the list in chronological order, and they will also be displayed in that order.
You are maintaining a list of information about all of the courses that are being offered in the coming semester. Each course has an id number between 1 and 5000, and you decide to use that id number as the position of the course’s record in the list. Once the list of courses is created, there are very few additions or removals. However, you need to frequently access the items in the list during the course registration period. Every time that a student registers for a course, you need to access that course’s record in the list so that you can increment the course’s count of enrolled students.
12 points total
Consider the following method, which takes a list that is an instance
of our LLList class from lecture and creates and returns a new list
that is a reverse of the original list:
public static LLList reverse(LLList list) { LLList rev = new LLList(); for (int i = list.length() - 1; i >= 0; i--) { Object item = list.getItem(i); rev.addItem(item, rev.length()); } return rev; }
Note that the original list is not altered.
What is the worst-case running time of this algorithm? Don’t
forget to take into account the time efficiency of the underlying
list operations, getItem() and addItem(). Use big-O
notation, and explain your answer briefly.
Rewrite this method to improve its time efficiency by improving
the ways in which the method manipulates the LLList
objects. Your new method should not modify the original list in
any way. Make the new method as efficient as possible. You should
assume that this method is not part of the LLList class, and
therefore it doesn’t have direct access to the fields of the
LLList objects. In addition, you may assume that the LLList
objects include support for the list-iterator functionality
discussed in lecture.
Note: In the ps3_partII.zip file that you will download for
Part II, we have included a file called Problem3.java that
contains the original version of the reverse method and a main
method with some preliminary test code. You are welcome to use
that file to test the correctness of your new version of the
method, although we encourage you to convince yourself of its
correctness before you test it in VS Code.
What is the worst-case running time of the improved algorithm? Use big-O notation, and explain your answer briefly.
8 points; 4 points each part
Write a method remAllStack(Stack<Object> stack, Object item)
that takes a stack and an item, and that removes all occurrences
of that item from the stack. After the removals, the remaining
items should still be in the same order with respect to each
other. For example, if you have a stack that contains (from top to
bottom) {5, 2, 7, 2, 10}, if you use the method to remove all
occurrences of 2, the resulting stack should contain (from top to
bottom) {5, 7, 10}.
Important guidelines:
Your method may use either another stack or a queue to assist it. It may not use an array, linked list, or other data structure. When choosing between a stack or a queue, choose the one that leads to the more efficient implementation.
You should assume that the method does not have access to the internals of the collection objects, and thus you can only interact with them using the methods in the interfaces that we discussed in lecture.
Although you aren’t writing this method as part of a class, you should use appropriate Java syntax. The methods should be static and should not return a value.
Write a method remAllQueue(Queue<Object> queue, Object item)
that takes a queue and an item, and that removes all occurrences
of that item from the queue. After the removals, the remaining
items should still be in the same order with respect to each
other. For example, if you have a queue that contains (from front
to rear) {5, 2, 7, 2, 10} and you use the method to remove all
occurrences of 2, the resulting queue should contain (from front
to rear) {5, 7, 10}. The same guidelines that we specified for
remAllStack() also apply here.
Suggestion
We have not given you a Java file for this problem, but we
strongly recommend writing a program to test your methods before
you copy them into your ps3_partI file. All of the necessary
classes can be found in the ps3_partII.zip file that you will
download for Part II.
Submit your ps3_partI.pdf file by taking the following steps:
If you still need to create a PDF file, open your file on Google Drive, choose File->Download->PDF document, and save the PDF file on your machine.
Click on the name of the assignment in the list of assignments on Gradescope. You should see a pop-up window labeled Submit Assignment. (If you don’t see it, click the Submit or Resubmit button at the bottom of the page.)
Choose the Submit PDF option, and then click the Select PDF button and find the PDF file that you created. Then click the Upload PDF button.
You should see a question outline along with thumbnails of the pages from your uploaded PDF. For each question in the outline:
As you do so, click on the magnifying glass icon for each page and doublecheck that the pages that you see contain the work that you want us to grade.
Once you have assigned pages to all of the problems in the question outline, click the Submit button in the lower-right corner of the window. You should see a box saying that your submission was successful.
Important
It is your responsibility to ensure that the correct version of every file is on Gradescope before the final deadline. We will not accept any file after the submission window for a given assignment has closed, so please check your submissions carefully using the steps outlined above.
If you are unable to access Gradescope and there is enough
time to do so, wait an hour or two and then try again. If you
are unable to submit and it is close to the deadline, email
your homework before the deadline to
cscie22-staff@lists.fas.harvard.edu
60-70 points total
Begin by downloading the following zip file: ps3_partII.zip
Unzip this archive, and you should find a folder named ps3_partII, and
within it the files you will need for Part II.
Keep all of the files in the ps3_partII folder, and open that
folder in VS Code using the File->Open Folder or File->Open menu
option.
Note: VS Code will show an “Unchecked cast” warning for the
lines in the ArrayStack and ArrayQueue constructors that create
the array for the items field and cast it to be of type T[]. You
can safely ignore these warnings.
30 points
If you haven’t already done so, complete the steps above to prepare for this and the remaining problems in Part II.
In lecture, we’ve been looking at linked lists of characters that are
composed of objects from the StringNode class. The class includes a
variety of methods for manipulating these linked lists, and many of
these methods provide functionality that is comparable to the methods
found in Java String objects.
Some of the existing StringNode methods use recursion, while others
use iteration (i.e., a loop!). In this problem, you will rewrite
several of the methods so that they use the alternative approach.
Guidelines
The revised methods should have the same method headers as the original ones. Do not rename them or change their headers in any other way.
Global variables (variables declared outside of the method) are not allowed.
Make sure to read the comments accompanying the methods to see how they should behave.
Because our StringNode class includes a toString() method,
you can print a StringNode s in order to see the portion of
the linked-list string that begins with s. You may find this
helpful for testing and debugging. However, you may not
use the toString() method as part of any of your
solutions.
More generally, you must not use any of the other
StringNode methods in your solutions. Rather, your methods
should do all of the work on their own.
Make your methods as efficient as possible. For example, you should avoid performing multiple traversals of the linked list if your task could be performed using a single traversal.
Another useful method for testing is the convert() method,
which converts a Java String object into the corresponding
linked-list string.
There is existing test code in the main() method.
Leave that code intact, and use it to test your new versions
of the methods. You are welcome to add extra test code
to this method, although doing so is not required.
A general hint: Drawing diagrams will be a great help as you design your revised methods.
Before you get started, we recommend that you put a copy of the
original StringNode class in a different folder, so that you can
compare the behavior of the original methods to the behavior of
your revised methods.
Rewrite the length() method. Remove the existing recursive
implementation of the method, and replace it with one that uses
iteration instead.
Rewrite the toUpperCase() method. Remove the existing iterative
implementation of the method, and replace it with one that uses
recursion instead. No loops are allowed.
Rewrite the printReverse() method so that it uses
iteration. This method is easy to implement using recursion–as we
have done in StringNode.java–but it’s more difficult to
implement using iteration. Here are two possible iterative
approaches, either of which will receive full credit:
reverse the linked list before printing it: This approach
is the trickier of the two, but we recommend it because it
uses less memory, and it will give you more practice with
manipulating linked lists. Remember that you may not use the
toString() method for this or any other method. In addition,
you should not use the print() method. Finally, don’t
forget to restore the linked list to its original form!
use an array: Create an array of type char that is large
enough to hold all of the characters in the string and use
it to help you with the problem.
Rewrite the removeFirst() method. Remove the existing iterative
implementation of the method, and replace it with one that uses
recursion instead. No loops are allowed.
Rewrite the copy() method. Remove the existing recursive
implementation of the method, and replace it with one that uses
iteration instead.
Remember: Draw diagrams to help you in your work!
StringNodes10 points; required of grad-credit students; “partial” extra credit for others
The guidelines for Problem 5 also apply here.
Add a new method with the following header:
public static StringNode substring(StringNode str, int start, int end)
This method may use either iteration or recursion to create a new
linked list that represents the substring of str that begins
with the character at index start and ends with the character at
index end - 1 (the character at index end is not included,
following the convention used by the substring method in the
String class). For example, if you run this test code:
StringNode s4 = StringNode.convert("hello"); StringNode s5 = StringNode.substring(s4, 1, 3); System.out.println(s4); System.out.println(s5);
you should see the following output:
hello el
The method should not change the original linked list, and it
should not use any of the existing StringNode methods.
Special cases:
IllegalArgumentException if the
indices are out of bounds, or if end is less than start. end is equal to start,
the method should return null (representing an empty
string). end is not equal to start and str is null, the
method should throw an IllegalArgumentException. Note: Depending on how you implement the method, you may not
need to explicitly check for all of these conditions. For example,
in a recursive implementation, if the initial values for the
indices are too large, the recursive calls should eventually get
to a call in which str is null.
Add a new method with the following header:
public static int nthIndexOf(StringNode str, int n, char ch)
This method must use recursion to find and return the index of
the nth occurrence of the character ch in the string str, or
-1 if there are fewer than n occurrences of ch in str.
For example, given the linked list s4 created in the example given
above for the substring method:
nthIndexOf(s4, 1, 'l') should return 2, because the first
occurrence of 'l' in "hello" has an index of 2.
nthIndexOf(s4, 2, 'l') should return 3, because the second
occurrence of 'l' in "hello" has an index of 3.
nthIndexOf(s4, 3, 'l') should return -1, because there are not
three occurrences of 'l' in "hello".
The method should return -1 if str is null, or if n is
less than or equal to 0.
18 points
Assume that we want list objects to support the following method:
boolean removeAll(Object item)
This method should take an arbitrary item, and it should removes
all occurrences of that item from the list. If one or more
occurrences of the item are removed, the method should return
true. If there were no occurrences of the item to begin with, it
should return false.
Create two implementations of this method: one as part of the
ArrayList class, and one as part of the LLList class. Both classes
can be found in the ps3_partII folder.
Important: For full credit, both methods should:
In order to do so, your methods will need to manipulate the internals of the list (i.e., the underlying array or linked list) themselves, and they will need to do so as efficiently as possible.
In addition, you should make sure that your ArrayList
version of the method doesn’t leave any extraneous references to
objects in the items array. For example, let’s say that
you have 9 items in the ArrayList. If a call to removeAll() removes
3 of them, you should end up with an array in which the first 6 elements
hold references to actual items, and all of the remaining elements
are null.
To facilitate testing, we have added a constructor to both classes
that takes an array of type Object containing the initial contents
of the list. Given these constructors, you can test your methods using
examples that look like this:
String[] letters = {"a", "b", "c", "a", "c", "d", "e", "a"}; ArrayList list1 = new ArrayList(letters); System.out.println(list1); System.out.println(list1.removeAll("a")); System.out.println(list1.removeAll("c")); System.out.println(list1.removeAll("x")); System.out.println(list1); LLList list2 = new LLList(letters); System.out.println(list2); System.out.println(list2.removeAll("a")); System.out.println(list2.removeAll("x")); System.out.println(list2);
which should produce the following output:
{a, b, c, a, c, d, e, a}
true
true
false
{b, d, e}
{a, b, c, a, c, d, e, a}
true
false
{b, c, c, d, e}
12 points
A palindrome is a string like "radar", "racecar", and "abba"
that reads the same in either direction. To enable longer palindromes,
we can ignore spaces, punctuation, and the cases of the letters. For
example:
"A man, a plan, a canal, Panama!"
is a palindrome, because if we ignore spaces and punctuation and convert everything to lowercase we get
"amanaplanacanalpanama"
which is a palindrome.
In the file Problem8.java that we’ve included in the ps3_partII
folder, implement the static method called isPal() whose header we
have provided. This method should take a String object as a
parameter and determine if it is a palindrome, returning true if it
is and false if it is not.
A string of length 1 and an empty string should both be considered
palindromes. Throw an exception for null values.
Although this problem could be solved using recursion or an
appropriately constructed loop that manipulates the String object
directly, your method must use an instance of one or more
of the following collection classes from the ps3_partII
folder:
ArrayStack LLStackArrayQueue LLQueueYou must not use any other data structure, including arrays or linked lists other than the ones that are “inside” instances of the above collections. Rather, you should put individual characters from the original string into an instance of one or more of the above collections, and use those collection object(s) to determine if the string is a palindrome.
For full credit, you should:
Write your method so that spaces, punctuation, and the cases of the letters don’t prevent a string from being a palindrome. To put it another way, make sure that your method only considers characters in the string that are letters of the alphabet and that it ignores the cases of the letters. See our example above.
Make your method as efficient as possible. In particular:
You should perform only one iteration over the original
String object. After that one iteration, any additional
manipulations of the characters should be done using the
collection object(s) that you have chosen to use.
You may not use the equals() method from the String
class to compare two strings. Rather, you should only compare
individual characters (i.e., individual values of type char)
using the == operator.
More generally, because we want to avoid unnecessary scanning,
you may not use any of the built-in
String methods except charAt() and
length().
Hints:
When constructing the collection object(s) that you decide to use,
you will need to specify the appropriate data type for the items
in the collection. Because char values are primitives, you should
use the corresponding “wrapper” class, which is called Character.
You may also find it helpful to use the Character.toLowerCase()
or Character.toUpperCase() method.
char values are essentially integers, so you can
compare them just as you would compare integers.
You should submit only the following files:
StringNode.javaArrayList.javaLLList.javaProblem8.javaYou do not need to submit any of the other files.
Here are the steps:
Click on the name of the assignment in the list of assignments. You should see a pop-up window with a box labeled DRAG & DROP. (If you don’t see it, click the Submit or Resubmit button at the bottom of the page.)
Add all three files to the box labeled DRAG & DROP. You can either drag and drop the files from their folder into the box, or you can click on the box itself and browse for the files.
Click the Upload button.
You should see a box saying that your submission was successful.
Click the (x) button to close that box.
The Autograder will perform some tests on your file. Once it is done, check the results to ensure that the tests were passed. If one or more of the tests did not pass, the name of that test will be in red, and there should be a message describing the failure. Based on those messages, make any necessary changes. Feel free to ask a staff member for help.
Note: You will not see a complete Autograder score when you submit. That is because additional tests will be run later, after the final deadline for the submission has passed. For such problems, it is important to realize that passing all of the initial tests does not necessarily mean that you will ultimately get full credit on the problem. You should always run your own tests to convince yourself that the logic of your solutions is correct.
If needed, use the Resubmit button at the bottom of the page to resubmit your work. Important: Every time that you make a submission, you should submit all of the files for that Gradescope assignment, even if some of them have not changed since your last submission.
Near the top of the page, click on the box labeled Code. Then click on the name of each file to view its contents. Check to make sure that you see the code that you want us to grade.
Important
It is your responsibility to ensure that the correct version of every file is on Gradescope before the final deadline. We will not accept any file after the submission window for a given assignment has closed, so please check your submissions carefully using the steps outlined above.
If you are unable to access Gradescope and there is enough
time to do so, wait an hour or two and then try again. If you
are unable to submit and it is close to the deadline, email
your homework before the deadline to
cscie22-staff@lists.fas.harvard.edu
Last updated on October 14, 2025.