Monday, August 15, 2016

Week 2 Algorithms Optional problem 1

Problem

  1. Give the best upper bound that you can on the solution to the following recurrence: T(1)=1 andT(n)T([n])+1 for n>1. (Here [x] denotes the "floor" function, which rounds down to the nearest integer.)
My answer
At jth level:
  Work done in combine step = 1
  Number of sub-problems = 1
  Thus the only thing needed to find out is depth of the recursion tree. 

To find out depth: 
Represent n as 2^(lgn). After k recursions, the size of the subproblem will be n^(1/2^k) = 2^(lgn/2^k). You want this to be small enough for the base case, i.e. say smaller than 2. 
Then 2^(lgn/2^k) = 2 
==> lgn/2^k = 1
==> lg n = 2^k
==>k = lg (lg n)

Thus the running time is O(lg(lg n))

Week 2 Algorithms

The questions

1. Your task is to compute the total number of comparisons used to sort the given input file by QuickSort. As you know, the number of comparisons depends on which elements are chosen as pivots, so we'll ask you to explore three different pivoting rules.
You should not count comparisons one-by-one. Rather, when there is a recursive call on a subarray of length m, you should simply add m1 to your running total of comparisons. (This is because the pivot element is compared to each of the other m1 elements in the subarray in this recursive call.)
WARNING: The Partition subroutine can be implemented in several different ways, and different implementations can give you differing numbers of comparisons. For this problem, you should implement the Partition subroutine exactly as it is described in the video lectures (otherwise you might get the wrong answer).
DIRECTIONS FOR THIS PROBLEM:
For the first part of the programming assignment, you should always use the first element of the array as the pivot element.
2. Compute the number of comparisons (as in Problem 1), always using the final element of the given array as the pivot element. Again, be sure to implement the Partition subroutine exactlyas it is described in the video lectures.
Recall from the lectures that, just before the main Partition subroutine, you should exchange the pivot element (i.e., the last element) with the first element.

3. Compute the number of comparisons (as in Problem 1), using the "median-of-three" pivot rule. [The primary motivation behind this rule is to do a little bit of extra work to get much better performance on input arrays that are nearly sorted or reverse sorted.] In more detail, you should choose the pivot as follows. Consider the first, middle, and final elements of the given array. (If the array has odd length it should be clear what the "middle" element is; for an array with even length 

2k, use the kth element as the "middle" element. So for the array 4 5 6 7, the "middle" element is the second one ---- 5 and not 6!) Identify which of these three elements is the median (i.e., the one whose value is in between the other two), and use this as your pivot. As discussed in the first and second parts of this programming assignment, be sure to implement Partition exactly as described in the video lectures (including exchanging the pivot element with the first element just before the main Partition subroutine).
EXAMPLE: For the input array 8 2 4 5 7 1 you would consider the first (8), middle (4), and last (1) elements; since 4 is the median of the set {1,4,8}, you would use 4 as your pivot element.
SUBTLE POINT: A careful analysis would keep track of the comparisons made in identifying the median of the three candidate elements. You should NOT do this. That is, as in the previous two problems, you should simply add m1 to your running total of comparisons every time you recurse on a subarray with length m.

My answers:
1. 
 #quicksort using first element of array as the pivot  
 def partition(A, l, r):  
   piv = A[l];  
   i = l+1  
   for j in range(l+1, r):  
     if A[j] <piv:  
       A[j], A[i] = A[i], A[j]   
       i = i+1  
   A[l], A[i-1] = A[i-1], A[l] #swap pivot into rightful place  
   return i  
 def quickSort(A, l, r):  
   count = 0  
   if l<r:  
     count = r-l-1  
     split = partition(A,l,r)  
     lc = quickSort(A,l,split-1) #during the for loop, this ends one before pivot  
     rc = quickSort(A,split,r) #because the split is the lower bound, syntax of for loop makes it one after the pivot  
     return count +lc +rc  
   else:  
     return 0  
 inFile = open("quickSort.txt", 'r')  
 with inFile as f:  
    numList = [int(integers.strip()) for integers in f.readlines()]  
 # numList = [line.rstrip() for line in open('quickSort.txt')] <- Doesn't work  
 tot = quickSort(numList, 0, len(numList))  
 print tot  

2.
 #quicksort using last element of array as the pivot  
 def partition(A, l, r):  
   piv = A[l];  
   i = l+1  
   for j in range(l+1, r):  
     if A[j] <piv:  
       A[j], A[i] = A[i], A[j]   
       i = i+1  
   A[l], A[i-1] = A[i-1], A[l] #swap pivot into rightful place  
   return i  
 def quickSort(A, l, r):  
   count = 0  
   if l<r:  
     A[l], A[r-1]= A[r-1], A[l]  
     count = r-l-1  
     split = partition(A,l,r)  
     lc = quickSort(A,l,split-1) #during the for loop, this ends one before pivot  
     rc = quickSort(A,split,r) #because the split is the lower bound, syntax of for loop makes it one after the pivot  
     return count +lc +rc  
   else:  
     return 0  
 inFile = open("quickSort.txt", 'r')  
 with inFile as f:  
    numList = [int(integers.strip()) for integers in f.readlines()]  
 tot = quickSort(numList, 0, len(numList))  
 print tot  


3.
 #quicksort using median of three as pivot  
 def partition(A, l, r):  
   piv = A[l];  
   i = l+1  
   for j in range(l+1, r):  
     if A[j] <piv:  
       A[j], A[i] = A[i], A[j]   
       i = i+1  
   A[l], A[i-1] = A[i-1], A[l] #swap pivot into rightful place  
   return i  
 def isMedian(a,b,c):  
   if(a<=b and b<=c) or (a>=b and b>=c):  
     return True   
 def quickSort(A, l, r):  
   count = 0  
   if l<r:  
     mid = l + (r-l+1)/2 - 1 #find out middle element  
     if isMedian(A[l], A[mid], A[r-1]):  
       A[l], A[mid] = A[mid], A[l] #switch middle (if it is median) to be the first element and use as pivot  
     elif isMedian(A[l], A[r-1], A[mid]):  
       A[l], A[r-1]= A[r-1], A[l]  #switch last (if it is median) to be first element and use as pivot
     count = r-l-1  
     split = partition(A,l,r)  
     lc = quickSort(A,l,split-1) #during the for loop, this ends one before pivot  
     rc = quickSort(A,split,r) #because the split is the lower bound, syntax of for loop makes it one after the pivot  
     return count +lc +rc  
   else:  
     return 0  
 NUMLIST_FILENAME = "quickSort.txt"  
 inFile = open(NUMLIST_FILENAME, 'r')  
 with inFile as f:  
    numList = [int(integers.strip()) for integers in f.readlines()]  
 # numList = [line.rstrip() for line in open('integerArray.txt')]  
 tot = quickSort(numList, 0, len(numList))  
 print tot  


Sunday, July 24, 2016

Algorithms Data and Analysis part 1

This question regards the problem of finding inversions and merge-sort. The code I used (if you don't like this code, there are numerous similar ones all over the web) to find the answer is- 
 def countInversion(alist):  
   global cnt  
   if len(alist)>1:  
     mid = len(alist)/2  
     leftHalf = alist[:mid]  
     rightHalf = alist[mid:]  
     countInversion(leftHalf)  
     countInversion(rightHalf)  
     i=0  
     j=0  
     k=0  
     for k in range(len(alist)):  
       if leftHalf[i] <= rightHalf[j]:  
         alist[k] = leftHalf[i]  
         i += 1  
         if i == len(leftHalf) and j != len(rightHalf):  
           while j != len(rightHalf):  
             k +=1  
             alist[k] = rightHalf[j]  
             j += 1  
           break  
       elif leftHalf[i] > rightHalf[j]:  
         alist[k] = rightHalf[j]  
         j += 1  
         cnt+=len(leftHalf)-i  
         if j == len(rightHalf) and i != len(leftHalf):  
           while i != len(leftHalf):  
             k+= 1  
             alist[k] = leftHalf[i]  
             i += 1            
           break   
   return alist  
 alist = [int(line.rstrip('\n')) for line in open('integerArray.txt')]  
 print 'Number of lines is', len(alist)  
 cnt = 0  
 countInversion(alist)  
 print cnt  

I get an answer which is accepted. The key thing that I got stuck on was the

line.rstrip('\n') for line in open('integerArray.txt')

If you don't cast it as an int, as in int(line.rstrip('\n')), you will get the wrong answer, because data is stored as string instead of integers. It is a rather silly mistake, but that is unfortunately the most common kind of mistake. 

Sunday, July 17, 2016

Hackerrank Day 26: Nested Logic

The problem:
Task 
Your local library needs your help! Given the expected and actual return dates for a library book, create a program that calculates the fine (if any). The fee structure is as follows:
  1. If the book is returned on or before the expected return date, no fine will be charged (i.e.: .
  2. If the book is returned after the expected return day but still within the same calendar month and year as the expected return date, .
  3. If the book is returned after the expected return month but still within the same calendar year as the expected return date, the .
  4. If the book is returned after the calendar year in which it was expected, there is a fixed fine of .
Input Format
The first line contains  space-separated integers denoting the respective , and  on which the book was actually returned. 
The second line contains  space-separated integers denoting the respective , and  on which the book was expected to be returned (due date).
Constraints
Output Format
Print a single integer denoting the library fine for the book received as input.
Sample Input
9 6 2015
6 6 2015
Sample Output
45
Explanation
Given the following return dates: 
Actual:  
Expected: 
Because , we know it is less than a year late. 
Because , we know it's less than a month late. 
Because , we know that it was returned late (but still within the same month and year).
Per the library's fee structure, we know that our fine will be . We then print the result of  as our output.

My submission:

 #include <cmath>  
 #include <cstdio>  
 #include <vector>  
 #include <iostream>  
 #include <algorithm>  
 #include <cstring>  
 using namespace std;  
 int main() {  
   /* Enter your code here. Read input from STDIN. Print output to STDOUT */  
    int n[6];  
   int len = sizeof(n)/sizeof(*n);  
   for(int i =0; i<len;i++){  
     cin>>n[i];  
   }  
   int fine = 0;  
   int yearDif = n[2]-n[5];  
   int monthDif = n[1]-n[4];  
   int dayDif = n[0]-n[3];  
   if (yearDif>0) fine = 10000;  
   else{  
     if(monthDif>0&&yearDif==0) fine = 500*monthDif;  
     else{  
       if (dayDif>0&&monthDif==0) fine = 15*dayDif;  
     }  
   }  
   cout<<fine;    
 }