2.1 2/NO, 37, √M NMOO, NO, NOlog log NO, NOlog NO, NOlog (NO2 ), NOlog2 NO, NO1.5 , NO2 , NO2 log NO, NO3 , 2NO/ 2 , 2NO . NOlog NO and NOlog (NO2 ) grow at the same rate. 2.2 (a) True. (b) False. A counterexample is TO1(NO) = 2NO, TO2(NO) = NO, and PfOO(NO) = NO. (c) False. A counterexample is TO1(NO) = NO2 , TO2(NO) = NO, and PfOO(NO) = NO2 . (d) False. The same counterexample as in part (c) applies. 2.3 We claim that NOlog NO is the slower growing function. To see this, suppose otherwise. Then, NOε/ √MloMgM M NMOO would grow slower than log NO. Taking logs of both sides, we find that, under this assumption, ε/ √Ml MoMgM M NMOOlog NO grows slower than log log NO. But the first expression simplifies to ε√l MMoMgM M NMOO. If LO = log NO, then we are claiming that ε√LMMOO grows slower than log LO, or equivalently, that ε2 LO grows slower than log2 LO. But we know that log2 LO = ο (LO), so the original assumption is false, proving the claim. 2.4 Clearly, log kO1 NO = ο(log kO2 NO) if kO1 < kO2, so we need to worry only about positive integers. The claim is clearly true for kO = 0 and kO = 1. Suppose it is true for kO < iO. Then, by L’Hospital’s rule, NO→∞ lim N logiO _____N_ = NO→∞ lim i N logiO−1 ______N_ The second limit is zero by the inductive hypothesis, proving the claim. 2.5 Let PfOO(NO) = 1 when NO is even, and NO when NO is odd. Likewise, let gO(NO) = 1 when NO is odd, and NO when NO is even. Then the ratio PfOO(NO) / gO(NO) oscillates between 0 and ∞. 2.6 For all these programs, the following analysis will agree with a simulation: (I) The running time is OO(NO). (II) The running time is OO(NO2 ). (III) The running time is OO(NO3 ). (IV) The running time is OO(NO2 ). (V) PjO can be as large as i O2 , which could be as large as NO2 . kO can be as large as PjO, which is NO2 . The running time is thus proportional to NO. NO2. NO2 , which is OO(NO5 ). (VI) The ifO statement is executed at most NO3 times, by previous arguments, but it is true only OO(NO2 ) times (because it is true exactly iO times for each iO). Thus the innermost loop is only executed OO(NO2 ) times. Each time through, it takes OO(Pj O2 ) = OO(NO2 ) time, for a total of OO(NO4 ). This is an example where multiplying loop sizes can occasionally give an overestimate. 2.7 (a) It should be clear that all algorithms generate only legal permutations. The first two algorithms have tests to guarantee no duplicates; the third algorithm works by shuffling an array that initially has no duplicates, so none can occur. It is also clear that the first two algorithms are completely random, and that each permutation is equally likely. The third algorithm, due to R. Floyd, is not as obvious; the correctness can be proved by induction. -4-See J. Bentley, "Programming Pearls," Communications of the ACM 30 (1987), 754-757. Note that if the second line of algorithm 3 is replaced with the statement Swap( A[i], A[ RandInt( 0, N-1 ) ] ); then not all permutations are equally likely. To see this, notice that for NO = 3, there are 27 equally likely ways of performing the three swaps, depending on the three random integers. Since there are only 6 permutations, and 6 does not evenly divide 27, each permutation cannot possibly be equally represented. (b) For the first algorithm, the time to decide if a random number to be placed in AO[iO] has not been used earlier is OO(iO). The expected number of random numbers that need to be tried is NO/ (NO − iO). This is obtained as follows: iO of the NO numbers would be duplicates. Thus the probability of success is (NO − iO) / NO. Thus the expected number of independent trials is NO/ (NO − iO). The time bound is thus iO=0 Σ NO−1 NO−i __ N_i_ < iO=0 Σ NO−1 NO−i NO2 ____ < NO2 iO=0 Σ NO−1 NO−i __1__ < NO2 PjO=1 Σ N Pj _1_ = OO(NO2 log NO) The second algorithm saves a factor of iO for each random number, and thus reduces the time bound to OO(NOlog NO) on average. The third algorithm is clearly linear. (c, d) The running times should agree with the preceding analysis if the machine has enough memory. If not, the third algorithm will not seem linear because of a drastic increase for large NO. (e) The worst-case running time of algorithms I and II cannot be bounded because there is always a finite probability that the program will not terminate by some given time TO. The algorithm does, however, terminate with probability 1. The worst-case running time of the third algorithm is linear - its running time does not depend on the sequence of random numbers. 2.8 Algorithm 1 would take about 5 days for NO = 10,000, 14.2 years for NO = 100,000 and 140 centuries for NO = 1,000,000. Algorithm 2 would take about 3 hours for NO = 100,000 and about 2 weeks for NO = 1,000,000. Algorithm 3 would use 1 ⁄ 1 2 minutes for NO = 1,000,000. These calculations assume a machine with enough memory to hold the array. Algorithm 4 solves a problem of size 1,000,000 in 3 seconds. 2.9 (a) OO(NO2 ). (b) OO(NOlog NO). 2.10 (c) The algorithm is linear. 2.11 Use a variation of binary search to get an OO(log NO) solution (assuming the array is preread). 2.13 (a) Test to see if NO is an odd number (or 2) and is not divisible by 3, 5, 7, ..., √M NMOO. (b) OO(√NMMOO), assuming that all divisions count for one unit of time. (c) BO = OO(log NO). (d) OO(2BO/ 2 ). (e) If a 20-bit number can be tested in time TO, then a 40-bit number would require about TO2 time. (f) BO is the better measure because it more accurately represents the sizeO of the input. -2.14 The running time is proportional to NO times the sum of the reciprocals of the primes less than NO. This is OO(NOlog log NO). See Knuth, Volume 2, page 394. 2.15 Compute XO2 , XO4 , XO8 , XO10 , XO20 , XO40 , XO60 , and XO62 . 2.16 Maintain an array PowersOfXO that can be filled in a for loop. The array will contain XO, XO2 , XO4 , up to XO2OIlog NOK . The binary representation of NO (which can be obtained by testing even or odd and then dividing by 2, until all bits are examined) can be used to multiply the appropriate entries of the array. 2.17 For NO = 0 or NO = 1, the number of multiplies is zero. If bO(NO) is the number of ones in the binary representation of NO, then if NO > 1, the number of multiplies used is OIlog NOK + bO(NO) − 1 2.18 (a) AO. (b) BO. (c) The information given is not sufficient to determine an answer. We have only worstcase bounds. (d) Yes. 2.19 (a) Recursion is unnecessary if there are two or fewer elements. (b) One way to do this is to note that if the first NO−1 elements have a majority, then the last element cannot change this. Otherwise, the last element could be a majority. Thus if NO is odd, ignore the last element. Run the algorithm as before. If no majority element emerges, then return the NOthO element as a candidate. (c) The running time is OO(NO), and satisfies TO(NO) = TO(NO/ 2) + OO(NO). (d) One copy of the original needs to be saved. After this, the BO array, and indeed the recursion can be avoided by placing each BiO in the AO array. The difference is that the original recursive strategy implies that OO(log NO) arrays are used; this guarantees only two copies. 2.20 Otherwise, we could perform operations in parallel by cleverly encoding several integers into one. For instance, if A = 001, B = 101, C = 111, D = 100, we could add A and B at the same time as C and D by adding 00A00C + 00B00D. We could extend this to add NO pairs of numbers at once in unit cost. 2.22 No. If LowO = 1, HighO = 2, then MidO = 1, and the recursive call does not make progress. 2.24 No. As in Exercise 2.22, no progres