Problem #1
solution
Method Call Output Produced
------------------------------------------------
mystery(2); 2+
mystery(5); 52+-
mystery(7); 731---
mystery(18); 8942++-+
mystery(21); 1052+-+-
1 point per column
Method Call +'s 1st other
----------------------------------------------------------
mystery(2); 2 +
mystery(5); 52 + -
mystery(7); 731 - --
mystery(18); 8942 + +-+
mystery(21); 1052 + -+-
-0 for quotes around output
-------------------------------------------------------------------------------
Problem #2
solution
public String undouble(String s) {
if (s.length() < 2) {
return s;
} else if (s.charAt(0) == s.charAt(1)) {
return s.charAt(0) + undouble(s.substring(2));
// could instead be: return undouble(s.substring(1));
} else {
return s.charAt(0) + undouble(s.substring(1));
}
}
1 header (static okay)
4 base cases
1 attempt to test string length of 0 or 1 or testing for equality with
empty string (can get this even if syntax is bad)
1 returns empty string without throwing an exception for empty string
2 returns original string without throwing an exception for 1-char string
4 basic idea (don't take off for syntax for these)
1 testing whether the first and second characters are equal
1 recurse with a shorter string by calling substring(1) or substring(2)
1 correctly combines one of the 2 chars with recursive call on substring(1)
or substring(2)
1 separate recursive call on either substring(1) or substring(2) without
including one of the 2 chars
6 correct for strings of length 2 or more
2 correctly tests whether first 2 characters are equal
2 works when first 2 characters are equal
2 works when first 2 characters are not equal (must be a call using
substring(1))
syntax deductions (categorical, first 2 could be their one free syntax mistake)
-1 for confusing equals and == on string/char
-1 for confusing length/length()/size/size()
-1 for failing to say "return" with a recursive call
notes: All loop or extra data structure solutions go to question leader. The
criteria assume students are looking at the front characters of a
string, but you should adjust appropriately for other approaches that
work (e.g., they look at the last characters or they introduce a private
method with an index parameter).
-------------------------------------------------------------------------------
Problem #3
Statement Output
------------------------------------------------------------
var1.method2() Box 2
var2.method2() Jar 2
var3.method2() Cup 2/Box 2
var4.method2() Jar 2
var5.method2() compiler error
var6.method2() Pill 2
var1.method3() Box 2/Box 3
var2.method3() compiler error
var3.method3() Cup 2/Box 2/Box 3
var4.method3() Jar 2/Box 3
((Cup)var1).method1() runtime error
((Jar)var2).method1() Jar 1
((Cup)var3).method1() Cup 1
((Cup)var4).method1() runtime error
((Jar)var4).method2() Jar 2
((Box)var5).method2() Box 2
((Pill)var5).method3() compiler error
((Jar)var2).method3() Jar 2/Box 3
((Cup)var3).method3() Cup 2/Box 2/Box 3
((Cup)var5).method3() runtime error
1 pt each
-1 if no slashes anywhere
-0 if they put quotes around answers
-------------------------------------------------------------------------------
Problem #4
before after code
-----------------------+-----------------------+-------------------------------
p->[1]->[2] | p->[1]->[2]->[3] | p.next.next = q;
| | q = null;
q->[3] | q |
-----------------------+-----------------------+-------------------------------
p->[1] | p->[2]->[1] | ListNode temp = q;
| | q = q.next;
q->[2]->[3] | q->[3] | temp.next = p;
| | p = temp;
-----------------------+-----------------------+-------------------------------
p->[1]->[2] | p->[2]->[4] | p.next.next = q.next;
| | q.next = null;
q->[3]->[4] | q->[1]->[3] | ListNode temp = p;
| | p = p.next;
| | temp.next = q;
| | q = temp;
-----------------------+-----------------------+-------------------------------
p->[1] | p->[2]->[1]->[4] | p.next = q.next.next;
| | q.next.next = null;
q->[2]->[3]->[4]->[5] | q->[5]->[3] | ListNode temp = p;
| | p = q;
| | q = temp.next.next;
| | q.next = p.next;
| | p.next = temp;
| | temp.next.next = null;
2 problem 1
1 attempt: change 2 of (q, 1 ~.next)
1 correct
3 problem 2
1 attempt: change 2 of (p, q, 1 ~.next)
2 correct
4 problem 3
1 attempt: change 3 of (p, q, 3 ~.next)
1 better attempt: change 4 of (p, q, 3 ~.next)
2 correct
6 problem 4
1 attempt: change 4 of (p, q, 5 ~.next)
1 better attempt: change 6 of (p, q, 5 ~.next)
4 correct
Notes
correctness is generally atomic except:
-1 per "setting to null" error if otherwise correct
-1 per exception thrown if otherwise correct
-1 if adding or subtracting a single ".next" somewhere makes it work
can lose up to 2 syntax points if they get correctness points, examples:
-1 not declaring temp variable to be of type ListNode (categorical)
-1 saying p.next() instead of p.next (categorical)
-1 per occurrence (max of 2) for "p.data" instead of "p" or equivalent
if they construct new list nodes:
-1 if they don't use them
lose all correctness for any subproblem that relies on the new nodes
if they use more than 2 temp variables:
-2 from correctness per subproblem
-------------------------------------------------------------------------------
Problem #5
solution
public void removeMax() {
if (size == 0) {
throw new IllegalStateException();
}
int max = 0;
for (int i = 1; i < size; i++) {
if (elementData[i] > elementData[max]) {
max = i;
}
}
for (int i = max; i < size - 1; i++) {
elementData[i] = elementData[i + 1];
}
size--;
}
1 header (non-void okay if there is a return that is consistent)
2 exception
1 reasonable attempt
1 correct (has to prevent ArrayIndexOutOfBoundsException)
4 loop to find index of max value
1 initialize max variable to first array element (could be max value)
1 reasonable attempt to loop over array, looking for the max (could be
max value)
2 correctly computes index of max value (-1 if close as in OBOB)
2 loop to remove max value (must be a second loop, can't be a call on remove)
1 reasonable attempt: must have at least two of:
* loop that starts at max index
* correct shifting code (elementData[i]=elementData[i + 1])
* correct bounds to shift until the end without going out of bounds
1 correct loop (lose this point if the shifting loop is inside the loop to
find the max)
1 decrements size exactly once
Notes: -3 if they use an extra structure (array, ArrayList, etc)
-1 if they use elementData.length instead of size
can get attempt but not correct points for using methods like get/set
-------------------------------------------------------------------------------
Problem #6
solutions
public static void makePalindrome(Stack s) {
Queue q = new LinkedList();
while (!s.isEmpty()) {
q.add(s.pop());
}
for (int i = 0; i < q.size(); i++) {
int n = q.remove();
q.add(n);
s.push(n);
}
int oldSize = q.size();
for (int i = 0; i < oldSize; i++) {
int n1 = q.remove();
int n2 = s.pop();
if (n1 == n2) {
q.add(n1);
}
}
while (!q.isEmpty()) {
s.push(q.remove());
}
}
public static void makePalindrome(Stack s) {
Queue q = new LinkedList();
int size = s.size();
while (!s.isEmpty()) {
q.add(s.pop());
}
for (int i = 0; i < size / 2; i++) {
s.push(q.remove());
}
int middle = 0;
if (size % 2 == 1) {
middle = q.remove();
}
while (!s.isEmpty()) {
int n1 = q.remove();
int n2 = s.pop();
if (n1 == n2) {
q.add(n1);
}
}
int newSize = q.size();
for (int i = 0; i < newSize; i++) {
int n = q.remove();
q.add(n);
s.push(n);
}
while (!s.isEmpty()) {
q.add(s.pop());
}
if (size % 2 == 1) {
q.add(middle);
}
for (int i = 0; i < newSize; i++) {
q.add(q.remove());
}
while (!q.isEmpty()) {
s.push(q.remove());
}
}
1 header (static okay, non-void okay if there is a return that is consistent)
2 constructs temporary queue using generics correctly (-1 per error)
1 does nothing and no exception for empty stack based on tests (loop tests ok)
2 initial s->q loop (ok if it transfers only half of the values)
1 reasonable attempt
1 correct
4 duplicating loop that contains:
int n = q.remove();
q.add(n);
s.push(n);
or loop that transfers just half from one structure to the other, as in:
int size = s.size();
for (int i = 0; i < size / 2; i++) {
s.push(q.remove());
}
5 loop that includes code to compare values looking for palindromic pairs:
int n1 = q.remove();
int n2 = s.pop();
if (n1 == n2) {
q.add(n1); // okay if this is done twice
}
mostly atomic, but -2 if they also add back to stack and -3 if they only add
to the stack; the following is equivalent:
int n = q.remove();
if (n == s.pop()) {
q.add(n);
}
2 ends with a q->s loop (ok if it transfers only half of the values)
1 attempt
1 correct
8 actually works (no double jeopardy with initial/final loops, but they can't
get full credit for those loops if you have to change them to get them
points here...take off the points there instead if it leads to a higher
score; question leader can authorize lesser deductions--see below)
1 works for length 3 test case
1 works for length 4 test case
1 works for length 6 test case
1 works for length 7 test case
2 works for length 14 test case
2 works for length 15 test case
approved deductions for these 8 correctness points (only apply if it gives
them some points)
-2 if in their comparing loop they added the value back to the queue twice
-2 minor loop error (OBOB, oldSize vs size())
-3 major loop error (while-not-empty vs oldSize)
Notes:
-2 from the 8 "actually works" points if it isn't O(n)
no parens for calls like q.remove() is a syntax mistake (could be free)
naming errors where you can infer what they meant are -1 each, max -2:
while (!s.isEmpty()) { q.add(s.remove()); }
testing program has s2q and q2s methods, but ONLY use these for the
simplest of while loops that match exactly, not for for loops
-2 from "actually works" for using peek
Give to question leader all solutions that involve: peek, foreach loop,
iterator, other illegal stack/queue operations; extra structure
Stuart Reges
Last modified: Fri Sep 16 16:16:07 PDT 2011