- Assigned
- Friday, 15 March 2019
- Due
- Thursday, 4 April 2019
- Summary
- To get some practice (a) solving small algorithmic problems and (b) analyzing the complexity of solutions to these problems, you’ll solve a handful of these problems in Java.
- Collaboration
- Each student should turn in his, her, zir, or their own solutions. Students should feel free to support each other, provided they cite any help they’ve received.
- Submitting
- Share your GitHub repo with csc207-grader. Then send
an email to csc207-01-grader@grinnell.edu with the address of
your repository. The subject of your
email should be
**[CSC207-01] Assignment 6**and should contain your answers to all parts of the assignment.

In addition to placing your code in a private GitHub repository, you should also include a `README.md`

file as well as a write-up of the complexity analyses and questions described in each problem in a file called `writeup.txt`

.

Write a static method `contains`

that takes three parameters—an array of doubles `dubs`

, a double value `eps`

, and a double `d`

—and returns `true`

if there is a element `dubs[i]`

in the array such that `abs(dubs[i] - d) < eps`

.

Once you have written the `contains`

method, analyze its *worst-case* complexity.
Choose an appropriate set of operations to count, define the input of your model, describe what the worst-case scenario is for this method, and give a model *T* of the time complexity of your method.
Finally, summarize the model with a tight upper bound characterization of *T* using Big-O notation, proving (by giving an appropriate *c* and *x_0*) that the upper bound is sound.

Write a method `fastModExp`

that takes three integers, *x*, *y*, and *m* and returns *x ^{y}* mod

*x*^{y}mod*m*= (*x*^{2}mod*m*)^{(y/2)}mod*m*when*y*is even.*x*^{y}mod*m*= (*x** (*x*^{(y-1)}mod*m*)) mod*m*when*y*is odd.

Once you have written the `fastModExp`

method, analyze its complexity, assuming that the input *y* is a power of two.
Choose an appropriate set of operations to count, define the input of your model and give a model *T* as a recurrence relation of the time complexity of your method.
Solve your recurrence relation using the substitution method described in class to obtain an explicit formula for the time complexity.
Finally, summarize the model with a tight upper bound characterization of *T* using Big-O notation, proving (by giving an appropriate *c* and *x _{0}*) that the upper bound is sound.

(*Hint*: your complexity model should not be linear!)

With the following class definition for a Pair class (defined in `Pair.java`

):

```
// In IntPair.java
public class IntPair {
private int fst;
private int snd;
public IntPair(int fst, int snd) {
this.fst = fst;
this.snd = snd;
} // IntPair(int,int)
public int getFst() {
return fst;
} // getFst()
public int getSnd() {
return snd;
} // getSnd()
} // IntPair
```

Write a static method in your `Program`

class called `allPairs`

that takes an integer array and returns all possible pairs of elements from the input array in a new array (of type `Pair`

array).
The set of possible pairs includes pairing each element with itself.
For example, if the input array `arr`

has the form `{ 3, 5, 9 }`

, then `allPairs(arr)`

returns the array `{ (3, 3), (3, 5), (3, 9), (5, 3), (5, 5), (5, 9), (9, 3), (9, 5), (9, 9) }`

(although not necessarily in that order).
If the `null`

array is passed to `allPairs`

, then an `IllegalArgumentException`

should be thrown.

Once you have written the `allPairs`

method, analyze its complexity.
Choose an appropriate set of operations to count, define the input of your model, and give a model *T* of the time complexity of your method.
Finally, summarize the model with a tight upper bound characterization of *T* using Big-O notation, proving (by giving an appropriate *c* and *x _{0}*) that the upper bound is sound.

Write a static method called `concatAndReplicateAll`

that takes an array of strings and an integer *n* and returns a single string that is the result of *replicating* them all *n* times and then *concatenating* them all together.
For example, if the input array `arr`

has the form `{ "hello", "world", "!" }`

and *n = 3* then `concatAndAreplicateAll(arr)`

returns the string `"hellohellohelloworldworldworld!!!"`

If the `null`

array is passed to `concatAndReplicateAll`

, then an `IllegalArgumentException`

should be thrown.

Once you have written the `concatAndReplicateAll`

method, analyze its complexity *informally*.
Choose an appropriate set of operations to count, define the input of your model, give a tight upper bound characterization of the method’s time complexity using Big-O notation, and in a sentence, justify your choice of bound.

Finally, does your analysis change if I tell you that Java string concatenation of two strings of lengths *n* and *m* is *O*(*n*+*m*)?
This is because strings are immutable, so that building the resulting string consists of traversing both strings rather than simply appending the second string onto the first.
State how your runtime changes as a result of this new information.

Write a static method called `interleave`

that takes two arrays of integers and returns a third array that is the result of interleaving the first array with the second.
For example, if the input arrays `arr1`

and `arr2`

have values `{0, 1, 2}`

and `{3, 4, 5}`

, respectively, then `interleave(arr1, arr2)`

produces the new array `{0, 3, 1, 4, 2, 5}`

.
If one array is longer than the other, then the remains of the longer array are simply placed at the end of the output array after interleaving.
For example, if `arr2`

above was `{3, 4, 5, 6, 7, 8}`

then `interleave(arr1, arr2)`

produces `{0, 3, 1, 4, 2, 5, 6, 7, 8}`

.

Once you have written the `interleave`

method, analyze its time complexity *informally*.
Choose an appropriate set of operations to count, define the input of your model, give a tight upper bound characterization of the method’s time complexity using Big-O notation, and in a sentence, justify your choice of bound.

Next, analyze the `interleave`

method’s *space complexity* informally.
Recall that the space complexity of a function is how much memory it uses—heap allocations and stack space (for recursive functions).
Give a tight upper bound characterization of the method’s space complexity using Big-O notation and in a sentence, justify your choice of bound.

Finally, review the previous problem’s functions and their space complexity.
(You do not need to provide them in your write-up, but you should go back and informally analyze their space complexity).
After review, what can you conclude about the *relationship* between time and space complexity?
In other words, if we know the space complexity of a function, can we put a bound on its time complexity?

The original version of this assignment was written by Peter-Michael Osera. Samuel A. Rebelsky make some updates for Spring 2019.