2.2 Analyzing algorithms
2.21
Express the function $n^3 / 1000  100n^2  100n + 3n$ in terms of $\Theta$notation.
$\Theta(n^3)$.
2.22
Consider sorting $n$ numbers stored in array $A$ by first finding the smallest element of $A$ and exchanging it with the element in $A[1]$. Then find the second smallest element of $A$, and exchange it with $A[2]$. Continue in this manner for the first $n  1$ elements of $A$. Write pseudocode for this algorithm, which is known as selection sort. What loop invariant does this algorithm maintain? Why does it need to run for only the first $n  1$ elements, rather than for all $n$ elements? Give the bestcase and worstcase running times of selection sort in $\Theta$notation.

Pseudocode:
n = A.length for i = 1 to n  1 minIndex = i for j = i + 1 to n if A[j] < A[minIndex] minIndex = j swap(A[i], A[minIndex])

Loop invariant:
At the start of the loop in line 1, the subarray $A[1..i  1]$ consists of the smallest $i  1$ elements in array $A$ with sorted order.

Why does it need to run for only the first $n  1$ elements, rather than for all $n$ elements?
After $n  1$ iterations, the subarray $A[1..n  1]$ consists of the smallest $i  1$ elements in array $A$ with sorted order. Therefore, $A[n]$ is already the largest element.

Running time: $\Theta(n^2)$.
2.23
Consider linear search again (see Exercise 2.13). How many elements of the in put sequence need to be checked on the average, assuming that the element being searched for is equally likely to be any element in the array? How about in the worst case? What are the averagecase and worstcase running times of linear search in $\Theta$notation? Justify your answers.
If the element is present in the sequence, half of the elements are likely to be checked before it is found in the average case. In the worst case, all of them will be checked. That is, $n / 2$ checks for the average case and $n$ for the worst case. Both of them are $\Theta(n)$.
2.24
How can we modify almost any algorithm to have a good bestcase running time?
You can modify any algorithm to have a best case time complexity by adding a special case. If the input matches this special case, return the precomputed answer.