Notes@HKU by Jax

Examples & questions bank

Recursion

Solve recurrence relation with substitution method

Reference section

(lvl 1): f(n)=2f(n1)+1(lvl 2): f(n1)=2f(n2)+1 f(n)=2(2f(n2)+1)+1=4f(n2)+2+1(lvl 3): f(n)=2(2(2f(n3)+1)+1)+1=8f(n3)+4+2+1 (lvl k): f(n)=2kf(nk)+2k1 f(1)=f(nk)=1    k=n1f(n)=2n1f(1)+2n11=2×2n11=2n1\begin{aligned} (\text{lvl }1):\ f(n) & =2f(n-1)+1 \\ (\text{lvl }2):\ f(n-1) & =2f(n-2)+1 \\ \uparrow\ f(n) & =2(2f(n-2)+1)+1 \\ & = 4f(n-2)+2+1 \\ (\text{lvl }3):\ f(n) & =2(2(2f(n-3)+1)+1)+1 \\ & = 8f(n-3)+4+2+1 \\\ (\text{lvl }k):\ f(n) & =2^kf(n-k)+2^k-1 \\\ f(1) = f(n-k) & =1 \implies k=n-1 \\ \therefore f(n) & =2^{n-1}f(1)+2^{n-1}-1 \\ & =2\times2^{n-1}-1 \\ & =2^n-1 \end{aligned}

Proving with Mathematical Induction

Reference section

Prove f(n)=121+222++n2n=(n1)2n+1+2Base case: n=1LHS: f(1)=121=2RHS: (11)21+1+2=022+2=2Inductive step: Assume f(n) holds true nk:f(k+1): LHS =f(k)+(k+1)2k+1=[(k1)2k+1+2]+(k+1)2k+1=(k1)2k+1+(k+1)2k+1+2=(2k)2k+1+2=k2k+2+2=((k+1)1)2(k+1)+1+2=RHS Statement holds true  n>0\begin{aligned} & \text{Prove } f(n) = 1\cdot2^1 + 2\cdot2^2 + \cdots + n\cdot2^n = (n-1) \cdot 2^{n+1} + 2 \\ & \text{Base case: } n = 1 \\ \text{LHS:\ } & f(1) = 1\cdot2^1 = 2 \\ \text{RHS:\ } & (1-1) \cdot 2^{1+1} + 2 = 0 \cdot 2^2 + 2 = 2 \\ & \text{Inductive step: Assume }f(n)\text{ holds true }\forall n \leq k: \\ f(k+1):\ \text{LHS\ } & = f(k) + (k+1)\cdot2^{k+1} \\ & = [(k-1) \cdot 2^{k+1} + 2] + (k+1)\cdot2^{k+1} \\ & = (k-1) \cdot 2^{k+1} + (k+1)\cdot2^{k+1} + 2 \\ & = (2k) \cdot 2^{k+1} + 2 \\ & = k \cdot 2^{k+2} + 2 \\ & = ((k+1)-1) \cdot 2^{(k+1)+1} + 2 \\ & = \text{RHS} \\ \therefore\ & \text{Statement holds true }\forall\ n > 0 \end{aligned}

Algorithm Analysis

Disproving Big O notation

Reference section

Consider T(n)=3n3+1T(n) = 3n^3 + 1, to show that T(n)O(n2)T(n) \neq O(n^2):

3n3+1cn2 nn03n3+1cn2 n23n+1n2c n2\begin{aligned} 3n^3 + 1 & \leq c \cdot n^2 & \forall\ n \geq n_0 \\ 3n^3 + 1 & \leq c\cdot n^2 & \forall\ n \geq 2 \\ 3n + \frac{1}{n^2} & \leq c & \forall\ n \geq 2 \\ \end{aligned}

As this expression cannot hold true for all n2n \geq 2 for a specific cc value, we can conclude that T(n)O(n2)T(n) \neq O(n^2).

(Example: if c=10c = 10 the equation does not hold when let's say n=100n = 100)

Proving Little o notation

Reference section

To show that T(n)o(n4)T(n) \in o(n^4):

3n3+1<cn4 nn03n+1n4<c nn0\begin{aligned} 3n^3 + 1 & < c \cdot n^4 & \forall\ n \geq n_0 \\ \frac{3}{n} + \frac{1}{n^4} & < c & \forall\ n \geq n_0 \\ \end{aligned}

As this express can hold true for any c>0c > 0 with sufficiently large n0n_0, we can conclude that T(n)o(n4)T(n) \in o(n^4).

(Example: if c=1c = 1 the equation holds with n0=100n_0 = 100)

Proving Big Theta notation

Reference section

Consider T(n)=4n2T(n)=4n^2, to show that T(n)Θ(0.5n2+10n+20)T(n) \in \Theta(0.5n^2+10n+20):

We know that T(n)c2(0.5n2+10n+20)T(n) \leq c_2 \cdot (0.5n^2 + 10n + 20) for c2=8c_2 = 8 easily.

Consider the lower bound:

4n2c1(0.5n2+10n+20) nn0n20.5n2+10n+20 nn0,c1=14n210n200 nn0\begin{aligned} 4n^2 & \geq c_1 \cdot (0.5n^2 + 10n + 20) & \forall\ n \geq n_0 \\ n^2 & \geq 0.5n^2 + 10n + 20 & \forall\ n \geq n_0, c_1 = \frac14 \\ n^2 - 10n -20 & \geq 0 & \forall\ n \geq n_0 \\ \end{aligned}

Therefore we can simply take n0=10n_0 = 10 and c1=14,c2=8c_1 = \frac14, c_2=8 to satisfy the definition of big Theta.

Identifying asymptotic growths

Reference section

Example 1:T(n)=3n3+1    O(n3) Ω(n3) Θ(n3) o(n4) ω(n2)T(n)=3n^3+1\implies O(n^3)\ \Omega(n^3)\ \Theta(n^3)\ o(n^4)\ \omega(n^2)

Example 2:n2O(2n)n^2 \in O(2^n) (n22nn^2 \leq 2^n order of growth. This is one of the many satisfying g(n)g(n). The useful g(n)g(n) would be: n2O(n2)n^2 \in O(n^2))

Example 3:nlognΩ(elogn)n\log n \in \Omega(e^{\log n}) (nlognnn\log n \geq n)

Data Structures

Reverse a linked list psuedocode

Example implementation of reversing a linked list. Reference section

def reverse_linked_list(head):
    prev = None
    current = head
    while current:
        next = current.next
        current.next = prev
        prev = current
        current = next
    return prev
 
def find_middle_node(head):
    slow = head
    fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    return slow

Find middle node of a linked list psuedocode

Example implementation of finding the middle node of a linked list. Reference section

def reverse_linked_list(head):
    prev = None
    current = head
    while current:
        next = current.next
        current.next = prev
        prev = current
        current = next
    return prev
 
def find_middle_node(head):
    slow = head
    fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    return slow

BFS psuedocode

Example implementation of BFS. Reference section

def bfs(mtx, start):
    q = Queue()
    
    q.enqueue(start) # queue start node
    qd = [start]
    
    while not q.isEmpty():
        cur = q.dequeue() # visit node
        print(cur)
        for x in mtx[cur]:
            if x not in qd:    # if not queued
                q.enqueue(x)  # put in queue
                qd.append(x)   # mark as queued

Example of finding the average number of slots inspected for unsuccessful search of built hash table with resolution method double hashing. Reference section

m=5,h(k)=kmod5m = 5,\quad h(k) = k \mod 5 with double hashing f(i)=ih(k),h(k)=2(kmod2)f(i) = i \cdot h'(k),\quad h'(k) = 2 - (k \mod 2).

Therefore the average is (4+1+3+1+2)+(2+1+2+1+3)5×2=2\frac{(4+1+3+1+2)+(2+1+2+1+3)}{5\times 2} = 2

Sorting

Selection sort psuedocode

Example of implementation of selection sort. Sort Summary

function selection_sort(array):
    for i in array:
        min_index = i
        for j in array after i:
            if current element < min element:
                min_index = j
        swap(A, i, min_index)
    return A

Bubble sort psuedocode

Example of implementation of bubble sort. Sort Summary

function bubble_sort(array, n): 
    for i in 0 to n - 1:
        swapped = False
        for j in 0 to before n - i - 1:
            if current element > next element:
                swap(current, next)
                swapped = True
        if not swapped break 
        # if no two elements were swapped, the array is sorted
    return A

Insertion sort psuedocode

Example of implementation of insertion sort. Sort Summary

function insertion_sort(array):
    for i in array after 0:
        for j in array before i reversed:
            if array[j] > array[i]:
                swap(array, i, j)
            else:
                break
    return array
    
            

Heap sort psuedocode

Example of implementation of heap sort. Sort Summary

function heap_sort(array):
    create_max_heap(array)
 
    for i from right in array:
        swap(array, 0, i)
        heapify(array from 0 to i - 1)
    
    return array

Merge sort psuedocode

Example of implementation of merge sort. Sort Summary

function merge_sort(array):
    function merge(A1, A2):
        result = []
        while A1 and A2:
            if A1[0] < A2[0]:
                result.append(A1.pop(0))
            else:
                result.append(A2.pop(0))
        return result + A1 + A2
    
    if len(array) < 2 return array
 
    mid = len(array) // 2
    left = merge_sort(array to mid)
    right = merge_sort(array after mid)
 
    return merge(left, right)

Quick sort psuedocode

Example of implementation of quick sort. Sort Summary

function quick_sort(array):
    function partition(array):
        pivot = random index from array
        swap = -1
 
        for j in array:
            if current element < pivot element:
                swap += 1
                swap(arr, swap, current)
        
        # move pivot element to its correct position
        pivot_index = swap + 1
        swap(arr, pivot_index, pivot) 
        return pivot_index
    
    if len(array) < 2 return array
 
    pivot = partition(array)
    quickSort(array before pivot)
    quickSort(array after pivot)

Count sort psuedocode

Example of implementation of count sort. Sort Summary

function counting_sort(array):
    k = max(array) # O(n)
    counter = Array(k)
    for i in array:
        counter[i] += 1
    
    for i in counter after 0:
        counter[i] += counter[i-1]
    
    result = Array(len(array))
    for i, x in array:
        result[counter[x]-1] = x
        counter[x] -= 1
    
    return result

Radix sort psuedocode

Example of implementation of radix sort. Sort Summary

function radix_sort(array, b=10):
    function countin_sort_exp(i):
        function get_key(n):
            return ith digit of n in base b (0 based)
            # (n // b**i) % b
 
        counter = Array(b)
        for i in array:
            key = get_key(i)
            counter[key] += 1
            
            for i in counter after 0:
                counter[i] += counter[i-1]
            
            result = Array(len(array))
            for x in array:
                key = get_key(x)
                result[counter[key]] = x
                counter[key] -= 1
            array = result
 
    d = len(max(array))
 
    for i from 0 to d - 1:
        counting_sort_exp(i)

On this page