Answers to Test 1, Compsci 100, Spring 2008, Astrachan Problem 1 A: calculate(2043) returns 2048. The while loop iterates while prod < n. prod takes on values 1,2,4,...,512,1024, enters the loop, is multiplied so that it is 2048, loop guard fails, method returns 2048 The complexity is O(log n) since loop executes number of times n can be divided by 2. Base of log is 2, but that doesn't matter in big-Oh B: zcal(n) takes O(n) time to execute, adding numbers 1..n. Recurrence is T(n) = T(n-1) + O(1) which is O(n) for running time value of zcal(n) is sum of numbers 1..n which is n(n+1)/2 which is O(n^2) and that's the answer since we're asked for big-Oh running time of zcal(zcal(n)) is running time of zcal(XXX) which is XXX, but XXX is n^2 from second answer, so answer is O(n^2) value is O(n^4) since we're asking for sum of numbers 1..n^2 Problem 2: Part A: public int listLength(Node list){ if (list == null) return 0; return 1 + listLength(list.next); } Part B: The classmate's code will be roughly twice as fast since it iterates over the list once instead of twice as in the case of the code: double avg = totalLength(list)*1.0/listLength(list); So, it's twice as fast, but it's still O(n), so it has the same complexity, but it's faster. Part C: easy recursion: check null/one node list, then others public boolean sorted(Node list){ if (list == null || list.next == null) return true; if (list.info.compareTo(list.next.info) > 0) return false; return sorted(list.next); } Part D: public Node first2last(Node list) { if (list == null || list.next == null) return list; Node first = list; Node second = first.next; // return this, it's new front while (list.next != null) { list = list.next; } list.next = first; first.next = null; // last node points at null return second; } Problem 3: We can see that the link code is linear, so going from 100,000 to one million, which is a factor of 10, should take 10 times as long. Thus 0.023*10 = 0.23, that's the answer For array list, code is quadratic we can see this from going from 20 to 40, double size, but time goes 0.176 to 0.686, note that 0.176*4 = 0.704 Similarly, from 50 to 100 is 1.069 to 4.234 and 1.069*4 is roughly 4.xx so we get a nice quadratic fit: double size, quadruple time. Can check 20 to 80, and get 0.176*16 = 2.816, reported time for 80 is 2.729, pretty good. So from 100,000 to one million, multiply by 100 since size increases by a factcor of 10: 4.234*100 = 423 seconds Note that the equations provided via excel presume units of 1 to 10, not 10 to 100, check by plugging in values for x to verify. Part B: see previous answer for how linear/quadratic justified by making specific reference to timings: when size goes up by factor of 8, run time should increase by factor of 8 for linear, 64 for quadratic. Verify with specific numbers. Part C: Key: array list insert requires all elements to right of insertion point to be shifted. For first element inserted: n shifts, then n-1 shifts, then ... last element no shifts. So total shifts is O(n^2). For linked list we can insert a new element by assigning pointers, so insertion is constant time O(1) Part E (there is no D) The code runs down since if it ran from 0..n it would first copy 0 to 1,2, overwriting existing values. Effectively the first element would be replicated everywhere, overwriting existing values. The code is fast for arraylists because get/set by index are O(1). For linked lists these are O(k) where k is the index of the get and set. Since we use every value of k from n to 0, where n is original size, we get O(n^2) for linked list, and it's worse in practice since there are three get/set operations in the loop. Problem 4: Part A: int awins = Collections.frequency(lostArray, a); The number of times a appears in lostArray is the number of times a has won since some team lost to team a each time. This must be O(n) since Collections.frequency looks at every element in the array once to see if it's equal to the search target. Part B: There are six lines. Both frequency lines are O(n), the linese with diff are O(1), they don't depend on n. The lines for aindex and bindex are O(n), they require searching through an array for a target which is O(n). So total is O(n) since 4n is O(n) Part C: maximum number of recursive calls is O(log n). This is a standard tournament, the number of runs is O(log n) for n-teams, in the first round, half the teams are knocked out, then half of those left (n/4) then n/8 ... when one team is left there have been O(log n) rounds. Part D: List is arranged from worst to best with ties broken alphabetically. This is not the exact reverse of theh original since teams that lose twice are still alphabetical. Part E: Map lookup is O(1) for each awins and losto. So complexity of compare without the recursive call is O(1) instead of O(n) Part F: Both frequency and indexOf are O(n), these are done n times: once for each string. So we get O(n^2) for answer: n operations n times, basically. Part G: For winMap, iterate over the elements in lostArray and bump a counter in the map each time. You could simply initialize the map for each element of the names array to 0, then just get/put : for(String s : names) winMap.put(s,0); // initialize for(String s : lostTo) winMap.put(s,winMap.get(s)+1); Similarly for lostMap we just use an index and store who each team lost to: for(int k=0; k < names.length; k++) lostMap.put(names[k],lostTo[k]); This is clearly O(n) since all put/gets are O(1) Part H: yes Problem 5: Part A: there's no base case and so after getting to the lower right corner (row+1 to bottom row, then col+1 to right hand side) the code repeats: row-1,row+1, row-1,row+1, ... nothing stops a space from being visited repeatedly during a sequence of calls. Part B: The two recursive calls are both one step closer to the bottom right, so they are T(n-1) each. Other stuff is O(1) Original call makes 2, which each make 2 (4) which each make 2 (8) .. or T(n) = 2T(n-1) + 1 but T(n-1) = 2T(n-2) + 1, so substituting: = 2[2T(n-2) + 1] + 1 = 4T(n-2) + 3 then expanding T(n-2) = 2T(n-3) + 1 gets = 8T(n-3) + 7 = 16T(n-4) + 15 = 2^kT(n-k) + 2^k-1 (by pattern/induction) Part C: ziggedy-zaggedy -- average 74.8 out of 85 80: 80, 80, 82, 82, 82, 83, 84, 84, 84, 87 75: 75, 78, 78, 78, 78, 79, 79 70: 70, 72, 72, 73, 74, 74 65: 67, 67, 68, 68, 68, 69 60: 55: 55 50: 51