15110 Fall 2011 [Cortina/von Ronne]

Written Homework 3 - due Friday, September 23 in class

Reading Assignment

Read sections 3.1-3.8 in chapter 3 and sections 4.1-4.2 in chapter 4 of the textbook Explorations in Computing.



  1. (2 pts) The Least Common Multiple (LCM) of two numbers x and y is the smallest positive integer that is a multiple of both x and y. (You use this when trying to find the lowest common denominator when adding fractions.)

    1. Consider the following iterative function that computes the LCM of integers x and y, for x > 0 and y > 0:

      def lcm(x,y)
      	p = x * y
      	while y != 0 do
      		temp = y
      		y = x % y
      		x = temp
      		q = p / x
      	return q

      Show how this function computes lcm(45,60) by creating a table that shows the values of each variable at the end of each iteration of the loop. We have started the table for you with the initial values of the variables before the first iteration of the loop:

        x     y     temp       p      q
       45    60      ---     2700    ---

    2. Consider the following recursive function that computes the LCM of x and y:

      def lcm(x, y)
      	return lcm2(x, y, x, y)
      def lcm2(x, y, a, b)
      	if (a == b) then
      		return a
      	if (a < b) then
      		return lcm2(x, y, a+x, b)
      	else    # otherwise, a > b
      		return lcm2(x, y, a, b+y)

      Show how lcm(45,60) is computed recursively here by showing the chain of recursive calls that are made until an answer is found. We have started the chain for you below:

      lcm(45, 60) --> lcm2(45, 60, 45, 60) --> lcm2(45, 60, 90, 60) --> 

  2. (2 pts) Recall the function we wrote for finding the maximum in an array of integers:

    def findmax(list)
            max_so_far = list[0]
            for i in (1..list.length-1) do
                    if list[i] > max_so_far then
                            max_so_far = list[i]
            return max_so_far
    1. Rewrite the function so that it returns the index of the maximum integer in the array. If there are duplicates of the maximum integer, return the index of the first of these duplicates.

      HINT: Instead of keeping track of the maximum so far, keep track of the index of the maximum so far.

    2. Someone wants to delete the maximum (and its duplicates) from an array called list and writes this statement:

      list.delete_if { |item| item == findmax(list) }

      What is wrong with this computation? Explain with an example.

  3. (1 pt) Let scores represent an array of exam scores. All of the exam scores are between 1 and 100, inclusive. There may be duplicates. For each of the following Ruby statements, state what it is computing in common English.

    1. scores.each{ |x| 
      	if x / 10 == 7 then
      		print x 
      		print "\n"

    2. scores.delete_if { |x| x / 10 == x % 10 }

  4. (1 pt) Let dictionary represent an array of words in alphabetical order.

    1. Write a Ruby statement that prints the second-to-last word in the dictionary without changing the array.

    2. Write a Ruby statement that removes all of the words that are less than 7 letters long.

  5. (2 pts) Recall the implementation of the Sieve of Eratosthenes that we discussed in class:

    def sieve(n)
            numlist = Array(2..n)
            primes = []
            while numlist.length > 0 do
                    primes << numlist.first
                    numlist.delete_if { |x| x % primes.last == 0 }
            return primes

    1. How would you modify the function above so that it returns the number (amount) of primes less than or equal to n?

    2. How would you modify the function above so that it returns the largest prime less than or equal to n?

    3. A modification we can make to the original function is to remove multiples of 2, 3, ..., up to the square root of n. For example, if we want the primes up to and including 50, we can stop after we remove the multiples of 7 (since the sqrt(50) is a little more than 7). A revised implementation is given below.

      def sieve2(n)
              numlist = Array(2..n)
              primes = []
              while numlist.first < Math.sqrt(n) do
                      primes << numlist.first
                      numlist.delete_if { |x| x % primes.last == 0 }
              return primes + numlist 

      The return statement returns an array containing the values in primes followed by the values in numlist. Briefly explain why we need to do this.

    4. If we test this modified function from part c for n = 1000000, the modification suggests that we are going to remove multiples of all numbers up to sqrt(1000000) = 1000, but when we execute the function, it only repeats its loop 168 times. Why?

  6. (2 pts) In class, we discussed the linear search algorithm, shown below in Ruby:

    def search(list, key)
            index = 0
            while index < list.length do
                    if list[index] == key then
                            return index
                    index = index + 1
            return nil

    Suppose that we know the additional fact that the list is sorted in non-decreasing order (this means that list[i]list[i+1], for 0 ≤ i < list.length-1). For example, if our list has the values:

    [25, 37, 45, 61, 73, 79, 82, 94]

    then if we want to search for the key 50 using linear search, we can stop when we reach 61 and return nil (assuming that the list is sorted).

    1. Revise the method above so that it also returns nil if it examines a list element that is larger than the key. (Since the array is sorted, this implies that there's no need to search the rest of the array.)

    2. If the array has n elements, what is the number of elements that would be examined in the worst case for this revised method? Explain.

    3. In order to use your new method, you should probably have a method that allows you to check to make sure that the array is sorted in non-decreasing order before you use the search method. Write a Ruby function sorted? that returns true if an array called list is sorted in non-decreasing order or false if it is not.

      def sorted?(list)

      HINT: Set up a loop to compare list[i] with list[i+1]. If you ever get two neighboring elements that are not in non-decreasing order, then the whole list cannot be sorted. Be careful with the range you use for i.