Sunteți pe pagina 1din 6

CS401, HW1

Due Tuesday, Tuesday Sept. 10 by 10:30AM


(Submission will be through Gradescope)
Handwritten submissions will be accepted. However, your writeup must
be neat and clear. It is strongly recommended that you work out your
solutions and then rewrite them for submission. (This is also very
useful in helping you find errors in your reasoning).

PART I (100 pts): ​ Exercises and Problems from CLRS (3rd edition). (Notice
that “problems” appear at the end of each chapter while “exercises” appear
after chapter ​subsections​).

REQUIRED - ​submit answers to these SUGGESTED - ​these problems are good


problems practice, but you will NOT submit
answers for them.

CHAPTER 2: CHAPTER 2:
Exercises 2.3-1, 2.3-3
Exercises: Problem 2-3(a) and (b)
2.3-4 (10 pts)
2.3-7 (15 pts) CHAPTER 3:
Problems: Exercises 3.1-7, 3.2-3
2-4 (15 pts)
Problems 3-1, 3-2 and 3-3(a)
CHAPTER 3:
Exercises: CHAPTER 4:
3.1-1 (10 pts) Exercise 4.4-6
3.1-3 (10 pts)
3.1-4 (10 pts) (explanations
required!)

Problems:
3-4 (a),(b),(c),(d),(g) only
(20 pts)
CHAPTER 4:
Exercise: ​4.4-7 (10 pts)
Part-II (20 points):​ Analyzing of an algorithm testing the AVL property.

Below is a C-function to check if a given binary tree obeys the AVL balance property. It uses
the height function as a helper.

TODO:​ show that the worst-case runtime of ​is_avl​ is

[It isn't ALWAYS quadratic -- for example, if the tree is as balanced as possible, the
runtime is Θ(n log n) time. You need to identify a class of trees which result in
quadratic time]

int height(TNODE *t) {


int h1, h2;
if(t==NULL) return -1;
h1 = height(t->left);
h2 = height(t->right);
if(h1>h2)
return h1+1;
else
return h2+1;
}
int is_avl(TNODE *t) {
int h1, diff;

if(t==NULL)
return 1;

h1 = height(t->left);
diff = h1 - height(t->right);

if(!is_avl(t->left) || !is_avl(t->right)
return 0;
return diff >= -1 && diff <= 1;
}
Part-III (60 points): Finding minimum elements in sub-arrays.

You are given an array of n numbers ​a[0..n-1]. ​The numbers are not sorted and their
ordering is fixed. You have an application in which you need to determine the minimum value
in various sub-arrays of ​a[]​ (and you may issue many such queries).

In other words, you need to support a query ​MIN_ELEM(low, hi) ​which yields the
smallest value in the subarray from index ​low​ to index ​hi​.

You might make many such queries. As an example, in the array below,
MIN_ELEM(1,4)=2.9 ; MIN_ELEM(5,5)=11.4 ;
MIN_ELEM(3,9)=1.12; MIN_ELEM(1,5)=2.9)

idx i 0 1 2 3 4 5 6 7 8 9

a[i] 4.1 2.9 6.6 9.1 7.1 11.4 1.12 3.13 1.9 8.1
Since you are going to do lots of queries, you are willing to do some preprocessing work
beforehand to make the queries faster.

A matrix-based approach:

Preprocess​: build an ​nxn​ matrix ​M​ where ​M[low, hi]​ stores the minimum value in
subarray ​a[low ... hi]. ​(Matrix entries ​MIN[i,j]​ where​ j>i ​are ignored).

Queries​: Now queries are trivial and take time just by accessing the correct
matrix entry.

TODO-A (25 pts)​: Devise an algorithm to build this matrix in time (a trivial
brute-force approach takes time).
O(1) query time is nice, but quadratic time for the preprocess might be pretty lousy unless I
am going to do a lot of queries (like Ω(n2 ) queries).
Maybe we prefer a slightly slower query time if we can shrink the preprocessing time a lot? In
particular, here is your goal:
TODO-B1 (35 pts): ​ You will still have a preprocess to build a data structure but it won't be
a matrix (you will design the data structure) but you will limit yourself to time for this
step.

Subsequent queries are done in time.


Your Job: ​ Design a data structure, construction procedure and query procedure meeting
these goals. Explain why the runtime requirements are met.

1
Probably the most challenging problem in this homework!
Part-IV (50 points): The Peak-Finding Problem Revisited

Remember the "peak finding problem" from week one?

We devised the following divide and conquer strategy in which we eliminate about half of the
rows in each step.

We "probe" the middle row (among those remaining) and find the largest
element in that row by brute force.

If it happens to also be a peak for the matrix, we are done!

Otherwise we recursively find a peak among the elements among the rows in
an "uphill" direction (eliminating the others).
Below is pseudo-code describing this algorithm.
1 // m: the 2d matrix
2 // n: the matrix dimension (nxn)
3 // lowRow/hiRow: range of rows under consideration
4 find_peakB(m, n, lowRow, hiRow) {
5
6 if(lowRow==hiRow) {
7 return largest entry in m[lowRow]
8 }
9 else {
10 r = (lowRow + hiRow)/2;
11 find largest entry in row r
12 if it happens to be a peak in m return it
13 else {
14 if(the entry above it is larger)
15 return find_peakB(m, n, lowRow, r-1)
16 else {
17 // entry below it must be larger
18 return find_peakB(m, n, r+1, hiRow)
}
}
}

This approach has a worst case runtime of Θ(n log n) : The recursion examines about log n
rows in total and, for each such row spends Θ(n) time to scan it to find the max

TODO (20 pts):​ Devise a Θ(n) time algorithm for the peak-finding in a matrix problem. Hint:
try for a smarter divide and conquer algorithm using the same the general idea of the
time algorithm.
PART-V (25 pts):

Finding The k-th Smallest Element From Two Sorted Arrays

You are given two sorted arrays of integers each of length n where
all entries among the two arrays ​are distinct​. You are also given a
parameter k ≤ 2n.

You want to find the k’th smallest entry among all 2n numbers.

TODO​: Describe an algorithm solving this problem in O(log n) time.


Don’t forget to explain why it is O(log n).

Let’s call the two arrays a[0..n-1] and b[0..n-1].

Comments/discussion/hints:

If k=1, it must mean what? It means we are looking for the minimum
element overall.

If k=2n, we are looking for the maximum element.

If k=n, we are looking for the median element.

Some things to consider:

Under what conditions would a[0] be the k-th smallest?

Under what conditions would a[n-1] be the k-th smallest?

Under what conditions would a[k-1] be the k-th smallest?

(same questions for array b[]).

Hopefully by answering these questions, you will gain some insight


leading to a general solution.
Addendum - what is a good “algorithm description”??

In this class (and as a Computer Scientist in general), you will often be asked to
“devise an efficient algorithm for problem X.”

It is natural to wonder how to describe your solution. In other words, ​what qualifies as
a good algorithm description?

It seems impossible to give a complete set of precise rules to answer this question.
But for our purposes, here are some guidelines to remember:

1. Unless specifically requested, we do not expect a complete


implementation of your algorithm in some language like C or Java; in
fact, complete implementations often obscure the key insights of the
algorithm (see #5 below).
2. A good algorithm description can be translated to an equivalent
implementation by any competent Computer Scientist with the same
level of proficiency as the author.
3. A good algorithm description not only describes the steps, but
convinces the reader​ of the correctness of the approach.
4. A good algorithm description also ​convinces the reader​ of the
correctness of any runtime claims that are made
5. A good algorithm description ​emphasizes the key
insights/properties​ leading to the correctness and/or efficiency of
the approach.

S-ar putea să vă placă și