Whiteboarding Coding Challenges in Python

A
Andrew FerlitschSecurity Engineer/Consultant at AllMed Healthcare Management
Whiteboarding
Coding Challenges
in Python
Portland Data Science Group
Created by Andrew Ferlitsch
Community Outreach Officer
August, 2017
Whiteboarding Interview
• The X
Coding Challenge
• Python Language Constructs Covered:
1. Main body
2. Indentation
3. Print
4. Line Comments
5. For loop – Range and Steps
6. If / else
7. Integer conversion
Prime Numbers
Prime Numbers
• Prime numbers are numbers that are only divisible by one and itself.
• Iterative Algorithm
1. For each number, we attempt to divide it by every number less than it, except for one.
2. The integer modulo operator is used to test if there is a remainder from the integer
division.
3. If there is no remainder, it is divisible by the number and therefore not a prime.
4. If each of the numbers it is divided by has a remainder, it is a prime.
print(“1)
print(“2”)
# Primes for numbers above 2
for number in range(3, 101):
# Attempt to divide this number by every number between 2 and one less than itself
for div in range(2, number):
if (number % div) == 0:
break
else:
print(number)
Range is always one less than the endpoint
Else clause is triggered when for loop does not complete all loops (i.e., break)
Prime Numbers – Skip Even Numbers
• Improvement:
1. Skip all even numbers, since they are divisible by two.
2. Odd numbers are not divisible by two, so skip dividing by even numbers.
print(“1)
print(“2”)
Print(“3”)
# Primes for numbers above 5
for number in range(5, 101, 2):
# Attempt to divide this number by every number between 3 and one less than itself
for div in range(3, number, 2):
if (number % div) == 0:
break
else:
print(number)
Step thru range in increments of 2 (odd numbers)
Prime Numbers – Skip Even Numbers, Divide by only
1/3 of range
• Improvement:
1. Since we are skipping evens, each prime must be divisible by at least the number 3.
2. So a prime must be divisible by 1/3 of less of itself.
print(“1)
print(“2”)
Print(“3”)
# Primes for numbers above 5
for number in range(5, 101, 2):
third = int(number / 3) + 1
# Attempt to divide this number by every number between 3 and 1/3 of itself
for div in range(3, third, 2):
if (number % div) == 0:
break
else:
print(number)
Round result to an integer
Coding Challenge
• Python Language Constructs Covered:
1. Function Definition
2. Iterative vs. Recursion
3. Variable Initialization
4. Return values
Fibonacci Sequence
Fibonacci Sequence – Recursive
• A Fibonacci sequence is F(n) = F(n-1) + F(n-2)
• Recursive Algorithm
1. Where F(0) = 0, F(1) = 1
2. F(n) = F(n-1) + F(n-2), where n >= 2
def fibonacci(n):
# Where F(0) = 0, F(1) = 1
if n == 0:
return 0
if n == 1:
return 1
# Recursion when n >= 2
return fibonacci(n – 1) + fibonacci(n – 2)
Recursion
Function Definition
Fibonacci Sequence - Iterative
• Iterative Algorithm
1. Where F(0) = 0, F(1) = 1
2. F(n) = F(n-1) + F(n-2), where n >= 2
def fibonacci(n):
# Where F(0) = 0, F(1) = 1
if n == 0:
return 0
if n == 1:
return 1
fn = 0 # current value for F(n)
f_minus_1 = 1 # current value for F(n-1)
f_minus_2 = 0 # current value for F(n-2)
for i in range(2, n+1):
# F(n) = F(n-1) + F(n-2) for current iteration
fn = f_minus_1 + f_minus_2
# Calculate F(n-1) and F(n-2) for next iteration
f_minus_2 = f_minus_1
f_minus_1 = fn
return fn
Initialize accumulators with n = 2
Range is always one less than the endpoint
Next F(n-1), F(n-2) would equal the current
F(n), F(n-1)
Coding Challenge
• Python Language Constructs Covered:
1. Static vs. Dynamic Array
2. Linked Lists
3. Class Definition
4. Class Constructor
5. Class Methods
6. Null (None) pointer
7. List Traversal
Dynamic Arrays
Dynamic Array
• An Array which can dynamically resize itself (i.e., linked list).
1. Add or Insert into the array (i.e., expand).
2. Remove any element in the array (i.e., shorten).
Static Array
0
Dynamically added element
3
1 2 3
Array is a contiguous block of memory,
with each element of fixed size.
Index of Element
Address of element is:
Address of start of array + ( index * element_size )
Dynamic Array
0 1 2
Link Link Link
Array is a non-contiguous block of memory,
With each element chained together by a link.
Dynamic Array
class Entry(object): # Definition for an array element
def __init__(self, data):
self.data = data # Entry data
self.link = None # Link to next Entry in Array
class Array(object):
def __init__(self):
self.array= None # initialize array to empty
# Add element an element to the end of the array
def add(self, data):
# Empty Array
if self.array is None:
self.array = Entry(data)
# Non-empty array
else:
# Find the last entry in the array
prev = self.array
while prev.link is not None:
prev = prev.link
# Add the element to the end of the list
prev.link = Entry( data )
Definition for an entry in
the dynamic array to hold
the entry data and link.
None is the null pointer.
Set array to a single entry
Remember last entry visited
In the linked list of entries.
When the link member is
None (null), you are at the
end of the linked list.
Dynamic Array - Improvement
class Array(object):
last = None # last entry in array
def __init__( self ):
self.array= None # initialize array to empty
# Add element an element to the end of the array
def add( self, data ):
entry = Entry( data )
# Empty Array
if self.last is None:
self.array = entry
# Non-empty array
else:
self.last.link = entry
# Set last entry to the newly added entry
self.last = entry
Keep location of last
entry in array.
Dynamic Array – Time Complexity
• Add
1. By maintaining pointer to the end, does not need to traverse the array
O(1)
• Find
1. Must traverse the links in the array (index-1) times for the index, where 0 < index < n
O(n/2) = O(n)
• Delete
1. Must traverse the links in the array (index-1) times for the index, where 0 < index < n
O(n/2) = O(n)
In complexity notation (Omega), multiplication and
division by a constant is removed
Omega
In complexity notation (Omega), 1 is used to represent
constant time.
In complexity notation (Omega), n is the number of
elements.
Coding Challenge
• Python Language Constructs Covered:
1. First In, First Out
2. Python Dynamic (builtin) Arrays
3. append() array method
4. len() object method
5. Copying elements
6. del operator
Queue
Queue
• FIFO (First In, First Out) – Data Structure
1. Enqueue – add an element to the back of the list
2. Dequeue – remove an element from the front of the list
x1
x2
Enqueue
Each element
is added to the
end of the queue
x2
Dequeue
x3
x3
Each element is
removed from the
front of the queue
x3 x1
Queue
class Queue(object):
def __init__(self):
self.queue = [] # initialize queue to empty dynamic array
# Add element to queue
def enqueue( self, element ):
self.queue.append( element )
# Remove element from front of the queue
def dequeue( self ):
# Empty Queue condition
if len( self.queue ) == 0:
return None
# Get (remember) the first element from the queue
element = self.queue[ 0 ]
# Remove (drop) the first element in the queue
del self.queue[ 0 ]
# Return the first element
return element
append() method adds an element to end of array/list.
len() function returns the number of
elements in an array/list.
Makes a local copy of the first element.
The del operator will remove an element
in an array/list at the specified location.
Notation for empty list/array.
Coding Challenge
• Python Language Constructs Covered:
1. Last In, Last Out
2. insert() array method
Stack
Stack
• LIFO (Last In, First Out) – Data Structure
1. Push – add an element to the front of the list
2. Pop – remove an element from the front of the list
x3
x2
Push
Each element is
added to the front
of the stack
x2
Pop
x1
x3
Each element is
removed from the
front of the stack
x3 x3
Stack
class Stack(object):
def __init__( self ):
self.stack = [] # initialize stack to empty dynamic array
# Add element to the stack
def push( self, element ):
self.stack.insert( 0, element )
# Remove element from front of the stack
def pop( self ):
# Empty Stack condition
if len( self.stack ) == 0:
return None
# Get (remember) the first element from the stack
element = self.stack[ 0 ]
# Remove (drop) the first element in the stack
del self.stack[ 0 ]
# Return the first element
return element
insert() method inserts an element to an array/list
at the specified index.
Coding Challenge
• Python Language Constructs Covered:
1. Importing a library
2. Prioritized Queue : heappush(), heappop()
Heap
Heap
• Prioritized Queue (Sorted by value) – Data Structure
1. Push – add an element to the sorted position in the list
2. Pop – remove an element from the front of the list
x3
x3
Push
Each element is
added at it’s
sorted location
In the queue
x2
Pop
x1
x3
Each element is
removed from the
front of the queue
x3 x3
Heap
from heapq import heappush, heappop
class Heap(object):
def __init__( self ):
self.heap = [] # initialize heap to empty dynamic array
# Add element to the (sorted) heap
def push( self, element ):
heappush( self.heap, element )
# Remove element from front of the (sorted) heap
def pop( self ):
# Empty Heap condition
if len( self.heap ) == 0:
return None
# Get the first element from the heap
element = heappop( self.heap )
# Return the first element
return element
heappush() function inserts an element to a sorted array/list.
Heappop() function removes the first element from a
sorted array/list.
Import the classes heappush and heappop
from the library heapq.
Queue, Stack, Heap -Time Complexity
• Queue
Enqueue O(1)
Dequeue O(1)
• Stack
Push O(1)
Pop O(1)
• Heap
Push O(n)
Pop O(1)
Must traverse array to find location
to insert.
Coding Challenge
• Python Language Constructs Covered:
1. Arithmetic Assignment
2. Recurring back in Recursion
StackChain
StackChain
• Chain of Stacks of Fixed Size
1. When an element is pushed to a stack that has reached its maximum (fixed) size, the
bottom of the stack is removed and pushed to the top of the next stack on the chain.
2. Likewise, when an element is popped from the stack, the top of the next stack that is
chained to it is popped and added to the bottom of the stack, and so forth.
x4
x3
Push
x2
x4
x1
Fixed Size
(e.g., 3) Removed
from the
bottom and
pushed to
top of the
next stack.
x3
Pop
x2
x3
x1
Removed
from the
top and
pushed to
top of the
previous stack.
StackChain
class StackChain(object):
def __init__( self, max ):
self.max = max # maximum size of a stack
self.stack = [] # initialize this stack to empty list/array.
self.chain = None # next stack in chain
# Add element to the stack chain
def push( self, element ):
self.stack.insert( 0, element )
# stack is less than full
if len( self.stack ) < self.max:
self.max += 1
# stack is full
else:
# Allocate the next stack in chain, if there is not one already.
if self.chain == None:
self.chain = stackChain( self.max )
# Get (remember) the element from the bottom of the stack
element = self.stack[ self.max - 1 ]
# Remove the element
del self.stack[ self.max - 1 ]
# push the element to the next stack in the chain
self.chain.stack.push( element )
No increment/decrement in Python.
Recursive call, will cascade
until the last stack in chain is less
than full.
StackChain
class StackChain(object):
# Remove element from the stack chain
def pop( self ):
# stack is empty
if len( self.stack ) == 0:
return None
# Get (Remember) top element in stack
element = self.stack[ 0 ]
# Remove the element from the stack
del self.stack[ 0 ]
# There is another stack in the chain
if self.chain is not None:
# Pop the top element from the next stack in the chain
bottom = pop( self.chain.stack )
# Add the element to the bottom of this stack
self.stack.append( bottom )
# Return the top of the stack
return element
Recursive call, will cascade to the last stack
and recur backwards moving the top of the
stack to the bottom of the previous stack.
Coding Challenge
• Python Language Constructs Covered:
1. Initializing size of an array
2. Recursive Sub-Solutions
Towers of Hanoi
Towers of Hanoi - Recursion
• Three Towers, stack of disks on start Tower, each disk smaller than
proceeding disk. Move the disks to the end Tower.
1. You move one disc at a time from the top of one tower to the top of another tower.
2. You can not place a larger disc on top of a smaller disc.
Start Intermediate End
Solve for N-1
Discs
Move disc N to End
StartIntermediate End
Move disc N to EndSolve for N-1
Discs
Recursion
Towers of Hanoi
class Hanoi(object):
towers = [ None ] * 3 # Initialize 3 towers with no discs on them
for i in range( 0, 3 ):
towers[ i ] = Stack()
def __init__(self, ndiscs ):
self.ndiscs = ndiscs # the number of discs
# initialize the first tower with discs in ascending order.
for i in range ( ndiscs, 0, -1 ):
self.towers[ 0 ].push( i )
# Recursive method to move ndiscs from start to end
def move( self, ndiscs, start, intermediate, end ):
# if single disk left, move it from start to end
if ndiscs == 1:
end.push( start.pop() )
else:
# move the remainder of the tower to the intermediate tower
self.move( ndiscs - 1, start, end, intermediate )
# move the bottom disc to the end tower
end.push( start.pop() )
# move the remainder of the intermediate tower to the end tower
self.move( ndiscs - 1, intermediate, start, end )
def play( self ):
self.move( self.ndiscs, self.towers[ 0 ], self.towers[ 1 ], self.towers[ 2 ] )
Can initialize class member variables
Outside of the constructor (__init__)
Notation for initializing an array of fixed
size (e.g., 3).
Recursively
solve
sub-problems
Coding Challenge
• Python Language Constructs Covered:
1. Nodes & Subtrees
2. Default Parameters
3. Emulating Method Overloading
Binary Tree
Binary Tree
• A Binary Tree is a type of directed graph tree where each node
contains at most two branches (subtrees), commonly referred to as
the left and right branch.
1. The recursive definition is a binary tree is either empty, a single node, where the left
and right branches are binary subtrees.
A
B C
D E
Left
Left
Root
Right
Right
Nodes
Leaves
Binary
subtree
Binary Tree
class BinaryTree(object):
# Constructor: set the node data and left/right subtrees to null
def __init__(self, key):
self.left = None # left binary subtree
self.right = None # right binary subtree
self.key = key # node data
# Get ot Set Left Binary Subtree
def Left(self, left = None):
if left is None:
return self.left
self.left = left
# Get or Set Right Binary Subtree
def Right(self, right = None):
if right is None:
return self.right
self.right = right
# Get ot Set Node Data
def Key(self, key = None):
if key is None:
return self.key
self.key = key
Good Practice to have
parent classes explicitly
Inherit the object class,
which all classes
implicitly inherit.
Default parameter. If
not specified, will
default to None.
Technique to emulate (fake) method overloading
using default parameter. If parameter not
specified, then it’s a getter[ otherwise (if
specified), it’s a setter.
Coding Challenge
• Python Language Constructs Covered:
1. is operator vs. ==
2. Default Parameters
3. Recursion (more)
4. Returning multiple values and Assignment of multiple
variables
Binary Tree Traversals
Binary Tree Traversals
• Binary Trees can be traversed either breadth first (BFS) or
depth first (DFS).
• Breadth First Search – tree is traversed one level at a time.
• The root node (level 1) is first visited, then the left node, then
the right node (level 2) of the root, and then the left and right
nodes of the these subtrees (level 3), and so forth.
• Depth First Search – tree is searched either inorder,
preorder, or postorder.
• Inorder : left (node), root, right
• Preorder : root, left, right
• Postorder: left, right, root
BFS Traversal
# Breadth First Search
def BFS( root ):
# Check if tree is empty
if root is None:
return
# list of nodes to visit in node level order
visit = []
visit.append( root )
# sequentially visit each node in level order as it is dynamically added to the list
i = 0
while i < len( visit ):
# Add to the list the child siblings of this node
if visit[ i ].Left() is not None:
visit.append( visit[ i ].Left() )
if visit[ i ].Right() is not None:
visit.append( visit[ i ].Right() )
i += 1
Visit is a dynamic array
Good practice when comparing
to None to use ‘is’ instead of ==
Good practice when comparing
to None to use ‘is not’ instead of
!=
DFS Traversal
Recursive Algorithms
# InOrder Traversal
def InOrder(root):
if root is None:
return
InOrder( root.Left() )
root.Action()
InOrder( root.Right() )
# PreOrder Traversal
def PreOrder(root):
if root is None:
return
root.Action()
PreOrder( root.Left() )
PreOrder( root.Right() )
# PostOrder Traversal
def PostOrder(root):
if root is None:
return
PostOrder( root.Left() )
PostOrder( root.Right() )
root.Action() The action to take when a node is visited.
Pre, In and Post refer to when
you visit the root (parent) node:
Pre = First
In = Middle
Post = Last
Binary Tree Max/Min Depth
• Binary Tree – Maximum/Minimum depth algorithm
1. Do a preorder traversal of the tree starting from the root.
2. When a node is visited, increment the depth count by 1.
3. Recursively apply the algorithm to the left and right nodes.
4. When returning from a child to a parent node, pass back the node depth of the child.
5. Return the maximum and minimum depth from the left and right child (or the parent if
there are no children).
A
B C
D E
Left
Left
Root
Right
Right
depth = 3 depth = 3
max = 3,
min = 3
max =2,
min = 2
max = 3,
min = 2
Binary Tree Maximum Depth
class BinaryTree(object):
# Maximum/Minimum depth of a binary tree
def MaxMinDepth( self, max ):
max += 1 # Increment by one level for the node
# Initialize the left and right branch max/min depth to the current max depth
lmax = lmin = max
rmax = rmin = max
# Calculate the maximum depth along the left binary subtree
if self.Left() is not None:
lmax, lmin = self.Left().MaxMinDepth( max )
# Calculate the maximum depth along the left binary subtree
if self.Right() is not None:
rmax , rmin = self.Right().MaxMinDepth( max )
# return the greater (max) and lessor (min) of the left and right subtrees
return ( rmax if rmax > lmax else lmax ), ( rmin if rmin < lmin else lmin )
Ternary conditional operator:
true_clause if condition else false_clause
Visited the root first.
Return max and min as a list
Can assign multiple
values on LHS
when list is returned.
Binary Tree Max/Min Value
• Binary Tree – Maximum/Minimum depth algorithm
1. Use either BFS or DFS/postorder traversal
2. Postorder: Recursively apply the algorithm to the left and right nodes.
3. When returning from a child to a parent node, pass back the max/min of the child.
4. Return the maximum or minimum value from the left and right child and parent.
5
4 3
5 8
Left
Left
Root
Right
Right
max = 5,
min = 5
max = 8,
min = 8
max = 8,
min = 4
max = 5,
min = 3
max = 8,
min = 3
Binary Tree Max/Min Value
class BinaryTree(object):
# Maximum/Minimum of a binary tree
def MaxMinValue( self ):
# Initialize the left and right branch max/min values to +/- infinity
lmax = rmax = -2147483647
lmin = rmin = 2147483648
# Calculate the maximum depth along the left binary subtree
if self.Left() is not None:
lmax, lmin = self.Left().MaxMinValue( )
# Calculate the maximum depth along the left binary subtree
if self.Right() is not None:
rmax , rmin = self.Right().MaxMinValue( )
# Compare max/min of child with parent
if rmax < self.Value():
rmax = self.Value()
if rmin > self.Value():
rmin = self.Value()
# return the greater (max) and lessor (min) of the left and right subtrees
return ( rmax if rmax > lmax else lmax ), ( rmin if rmin < lmin else lmin )
Visited the root last
Coding Challenge
• Python Language Constructs Covered:
1. Ternary Conditional operator
2. Local Variables
3. elif statement
4. Removing Links
Binary Search Tree
Binary Search Tree - Insert
• Binary Search Tree – Insert algorithm
1. A sorted tree where at each node, the data value of the left branch (child) is less than
the data value of the node, and the right node is greater than, and where there are
no duplicate values.
1. Insert: if the root is null (None), add it as the root; otherwise, traverse the tree.
2. If the value is less than the node (branch), traverse left; otherwise traverse right.
3. If there is no node (branch) to traverse, then add it as a new node.
6
4 8
2 5
Left
Left
Root
Right
Right
7
Left
7
Insert
7 > 6, go right
7 < 8, go left
No node, insert
Binary Search Tree - Insert
class BinarySearchTree(object):
root = None # root of the search tree
# Insert a node into a binary search tree
def Insert( self, node ):
# If tree is empty, make the root the first node
if self.root is None:
self.root = node
return
# Follow a path to insert the node
curr = self.root
while True:
# if value is less than node, traverse left branch
if node.value < curr.value:
# if no left branch, set node as left branch
if curr.Left() is None:
curr.Left( node )
return
curr = curr.Left()
# otherwise, traverse right branch :
elif curr.Right() is None:
curr.Right( node )
return
else:
curr = curr.Right()
Local variable, created
on first use.
Loop forever
Format of:
else if statement
Add code here to
check for duplicate
Binary Search Tree - Find
• Binary Search Tree – Find algorithm
1. If the root is null (None), return None.
2. If value is equal to the node, return the node.
3. If the value is less than the node (branch), traverse left; otherwise traverse right.
4. If there is no node (branch) to traverse, then return None.
6
4 8
2 5
Left
Left
Root
Right
Right
7
Left
Find value = 7
7 > 6, go right
7 < 8, go left
Node Found
Binary Search Tree - Find
class BinarySearchTree(object):
root = None # root of the search tree
# Find a node into a binary search tree
def Find( self, value ):
# If tree is empty, return None
if self.root is None:
return None
# Follow a path to find the node
curr = self.root
while True:
# Node Found
if curr.value == value:
return curr
# if value is less than node, traverse left branch
if value < curr.value:
# if no left branch, return not found
if curr.Left() is None:
return None
curr = curr.Left()
# otherwise, traverse right branch :
elif curr.Right() is None:
return None
else:
curr = curr.Right()
Binary Search Tree - Delete
• Binary Search Tree – Delete algorithm
1. If the root is null (None), return.
2. While remembering the parent node, If the value is less than the node (branch),
traverse left; otherwise traverse right.
3. If the value equals the node value, set the parent left branch to null if left branch;
Otherwise set parent right branch to null.
4. Reinsert the left and right branches of the removed node.
6
4 8
2 5
Left
Left
Root
Right
Right
7
Left
Remove value = 8
7 > 6, go right
Parent = 6
Remove Link
6
4
2 5
Left
Left
Right
Right
7
Reinserted
Node
Binary Search Tree - Delete
class BinarySearchTree(object):
root = None # root of the search tree
# Find a node into a binary search tree
def Delete( self, value ):
# If tree is empty, return None
if self.root is None:
return None
# Follow a path to find the node to delete
curr = self.root
prev = self.root
while True:
# Node Found
if curr.value == value:
if left == True: # delete the left branch of the parent
prev.left = None
else: # delete the right branch of the parent
prev.right = None
if curr.Left(): # re-insert left branch of deleted node
self.Insert( curr.left )
if curr.Right(): # re-insert right branch of delete node
self.Insert( curr.right )
return
# if value is less than node, traverse left branch
if value < curr.value:
# if no left branch, return not found
if curr.Left() is None:
return None
curr = curr.Left()
left = True # traversed left branch
# otherwise, traverse right branch :
elif curr.Right() is None:
return None
else:
curr = curr.Right()
left = False # traversed right branch
Coding Challenge
• Python Language Constructs Covered:
1. Recap
Arithmetic Emulation
Arithmetic - Multiply
• Algorithm to implement multiply with only addition
and equality operator.
1. Initialize accumulators for result and repeat to 0.
2. Loop indefinitely for ‘x * y’
1. If repeat accumulator equals zero, stop.
2. Increment the repeat accumulator by one.
3. Add x to the result.
Repeaty ->
y > 0
result
No
Yes y-- result += x
Arithmetic - Multiply
def Mul( x, y ):
# multiple by a negative number
if y < 0:
y = -y # turn y into positive number for loop increment
x = -x # turn x into negative number for result accumulator
# repeat adding x to result y times
result = 0
for i in range( 0, y ):
result += x
return result
Arithmetic - Exponent
• Algorithm to implement exponent with only addition
and equality operator.
1. If the exponent is zero, return 1.
2. Initialize accumulators for result and repeat to 0.
3. Loop indefinitely for 'x power e‘
1. If repeat accumulator equals zero, stop.
2. Increment the repeat accumulator by one.
3. Update the result to Mul( result, x ).
Repeaty ->, result = 1
y > 0
result
No
Yes y-- result = Mul(result, x)
Arithmetic - Exponent
def Exp( x, y ):
# initialize result to 1
result = 1
# repeat multiplying result by x, y times
for i in range( 0, y ):
result = Mul( result, x )
return result
Does not handle negative exponents.
GCD – Iterative Solution
• Euclid’s Algorithm for Greatest Common Denominator
1. Calculate the remainder of dividing the 2nd number by the first number (y % x).
2. Swap the value of the first number (x) with the second number (y).
3. Set the second number (y) to the remainder.
4. Iteratively repeat the process until the 2nd number (y) is zero.
5. Return the value of first number (x) when the 2nd number is zero (y).
Repeatx, y ->
y > 0
x
No
rem = y % x
x = y; y = rem
Yes
Arithmetic – GCD Iterative
def GCD( x, y ):
# continue until the division of of the two numbers does not leave a remainder (evenly divisible)
while y > 0:
# calculate the remainder of the division by between x and y
remainder = ( y % x )
# swap the value of x with y
x = y
# set y to the remainder
y = remainder
return x
GCD – Recursive Solution
• Euclid’s Algorithm for Greatest Common Denominator
1. When the 2nd number (y) is reduced to zero, return the current value of the first
number (x).
2. Otherwise, swap the first number (x) with the second number (y) and set the 2nd
number (y) to the remainder of the division of the 2nd number by the first number (x % y).
3. Recursively call GCD() with the updated first and second numbers.
GCDx, y ->
y > 0
x
No
Yes rem = y % x
x = y; y = rem
Call
GCD(x,
y)
Arithmetic – GCD Recursive
def GCDR( x, y ):
# return the current value of x when y is reduced to zero.
if y == 0:
return x
# recursive call, swapping x with y, and setting y to remainder of y divided by x
return GCDR( y, ( y % x ) )
LCM
• Euclid’s Algorithm for Least Common Multiple
1. Multiple the first and second number.
2. Divide the result by the GCD of the two numbers.
LCMx, y ->
x
mul = x * y
Result = mul / GCD(x,y)
Arithmetic – LCM
def LCM( x, y ):
return ( x / y ) / GCD( x, y )
Coding Challenge
• Python Language Constructs Covered:
1. Bubble Sort
2. Swapping
3. Logical Operators
Sorting
Bubble Sort
• Bubble Sort Algorithm
1. Make a pass through the list of values.
• Compare adjacent values.
• If the first value is less than the second value, swap the values.
2. If one of more values were swapped, repeat the process of making a pass through the
list.
4 2 1 3
Forward Scan
2 4 1 3 2 1 4 3 2 1 3 4
2 1 3 4 1 2 3 4
Repeat Cycle
1 2 3 4 1 2 3 4
Bubble Sort
def BubbleSort( data ):
length = len( data )
swapped = True
# continue to repeat until no more adjacent values are swapped
while swapped:
swapped = False
# Make a scan through the list
for i in range( 0, length - 1 ):
# Compare adjacent values. If the first value > second value, swap the values.
if data[ i ] > data[ i + 1 ]:
swap = data[ i ]
data[ i ] = data[ i + 1 ]
data[ i + 1 ] = swap
swapped = True
return data
Since we are comparing index with
index + 1, we stop one entry short
of the end of the array.
Swap: 1. save the first element in a
temporary variable.
2. Set the first element to the
value of the second element.
3. Set the second element to the
value of the temporary variable
(which was the former value of
first element).
Space Complexity: O(1) – except for swap variable, no extra space needed
Time Complexity : O(n2) – n is number of elements, n scans * n elements.
Coding Challenge
• Python Language Constructs Covered:
1. Insertion, Quick and Merge Sorts
2. Array Scans
3. Swapping
4. Logical Operators
5. Complexity
Sorting
Insertion Sort
• Insertion Sort Algorithm
1. Iterate through the list of elements.
• Scan through the list one element at a time.
• From current element, move backwards to the beginning, swapping adjacent
elements when not sorted.
4 3 2 1
Forward Scan
3 4 2 1 2 3 4 1 1 2 3 4
3 2 4 1Move Backwards 2 3 1 4
2 1 3 4
Insertion Sort
def InsertionSort( data ):
length = len( data )
# iterate through the list for each element except the first element
for i in range( 1, length ):
# starting with the current element, remove/insert proceeding
# elements so they are in sorted order
for j in range( i, 0, -1):
# swap adjacent elements
if data[ j ] < data[ j - 1 ]:
temp = data[ j ]
data[ j ] = data[ j -1 ]
data[ j - 1 ] = temp
return data
Start at position 1,
not 0 – nothing to
swap with at first
element.
Space Complexity: O(1) – except for swap variable, no extra space needed
Time Complexity : O(n2) – n is number of elements, n scans * n elements.
Descending count
in for loop. Loop
from ‘n’ to 0 in -1
(descend) steps.
Quick Sort
• Quick Sort Algorithm
1. Calculate a midpoint in the list. The value at the midpoint is the pivot value.
2. Move all values in the first partition that are not less than the pivot to the second
partition.
3. Move all values in the second partition that are not greater than or equal to the pivot
to the first partition.
4. Recursively apply the algorithm to the two partitions.
3 2 4 5 18 67
3 21 5 8 674
21 3 4 65 7 8
Quick Sort
def QuickSort( data ):
qSort( data, 0, len( data ) - 1 )
return data
def qSort( data, low, high ):
i = low # starting lower index
j = high # starting higher index
mid = int( low + ( high - low ) / 2 ) # midway index
pivot = data[ mid ] # pivot, value at the midway index
# Divide the array into two partitions
while i <= j:
# keep advancing (ascending) the lower index until we find a value that is not less than the pivot
# we will move this value to the right half partition.
while data[ i ] < pivot:
i += 1
# keep advancing (descending) the higher index until we find a value that is not greater than the pivot
# we will move this value to the left half partition.
while data[ j ] > pivot:
j -= 1
# if the lower index has past the higher index, there is no values to swap
# otherwise, swap the values and continue
if i <= j:
# swap the higher than pivot value on the left side with the lower than pivot value on the right side
temp = data[ i ]
data[ i ] = data[ j ]
data[ j ] = temp
# advance the lower and higher indexes accordingly and continue
i += 1
j -= 1
# recursively sort the two partitions if the index has not crossed over the pivot index
if low < j:
qSort( data, low, j )
if i < high:
qSort( data, i, high )
Merge Sort
• Merge Sort Algorithm
1. Allocate space for a temporary copy of the array.
2. Recursively split the data into two partitions (halves), until each partition is a
single element.
3. Merge and sort each pair of partitions.
2 3 4 5 61 87
3 42 1 5 768
83 2 4 51 6 7
Split into
halves
38 2 4 15 7 6
Merge halves
and sort
Merge Sort
def MergeSort( data ):
# allocate space for a temporary copy of the data
tdata = [ 0 ] * len( data );
# sort the data (pass in the temporary copy so routine is thread safe)
mSort( data, 0, len( data ) - 1, tdata )
return data
def mSort( data, low, high, tdata ):
# if the partition has more than one element, then recursively divide the partition and merge the parts back in
if low < high:
mid = int( low + ( high - low ) / 2 ) # midway index
# sort the lower (first) half partition
mSort( data, low, mid, tdata )
# sort the upper (second) half partition
mSort( data, mid + 1, high, tdata )
# merge the partitions together
merge( data, low, mid, high, tdata )
def merge( data, low, mid, high, tdata ):
# make a temporary copy of the two separately sorted partitions
for i in range( low, high + 1 ):
tdata[ i ] = data[ i ]
# starting from the beginning of the first partition, iteratively search for the next lowest
# number from the lower (first) and higher (second) and move into current position in the
# lower (first) partition
i = low
k = low
j = mid + 1
while i <= mid and j <= high:
if tdata[ i ] <= tdata[ j ]:
data[ k ] = tdata[ i ]
i += 1
else:
data[ k ] = tdata[ j ]
j += 1
k += 1
# Copy any remaining elements back into the first partition
while i <= mid:
data[ k ] = tdata[ i ]
k += 1
i += 1
Logical operators are the
keywords:
and
or
Quick / Sort Merge - Complexity
• Merge
Space Complexity: O(n)
Time Complexity : O(n * logn)
• Quick
Space Complexity: O(n)
Time Complexity : O(n * logn)
Coding Challenge
• Python Language Constructs Covered:
1. Modulo Operator
2. Squashing into a range
3. Collision Handling
4. Complexity
Hashing
Hashing
• Hashing is used to solve indexing lookups without the overhead of
sequential scanning and name comparisons. The most basic use of
hashing is insertion and lookup in a key-value(s) dictionary.
• Common Issues:
1. Handling of collisions when two keys mapped to the same index.
2. Efficiency of the hashing algorithm.
3. The frequency of collisions.
4. The sparseness of the memory allocated for the index.
Integer Hash
• Integer Hash Algorithm
1. Map each integer value into a smaller fixed size integer range using the modulo operator.
2. If there is no entry at the index, add the key/value to the index as the first entry in the
chain.
3. If there are entries there, and the key is the same as one of the entries (duplicate),
update the value.
4. If there are entries there, and the key is not the same (collision) as any entry, add the key
to the chain of entries.
0
1
2
3
4
n
***
Range
None (no entry at index)
A
A B
Single Entry (no collision)
Chain of Entries (collisions)
Index = (key % range)
Integer Hash (part 1)
class Hash( object ):
RANGE = 0 # the range of the index.
index = [] # the index
# constructor
def __init__( self, range ):
# set the index range and allocate the index
self.RANGE = range
self.index = [None] * self.RANGE
# Map the key into an index within the set range
def Index( self, key ):
return key % self.RANGE
Module operator, returns the
remainder of an integer division.
Integer Hash (part 2)
class Hash( object ):
# Add a key/value entry to the index
def Add( self, key, value ):
ix = self.Index( key )
# there is no entry at this index, add the key/value
if self.index[ ix ] is None:
self.index[ ix ] = Entry( key, value )
else:
# See if the key already exists in the chain
next = self.index[ ix ]
while next is not None:
# Entry found, update the value
if next.Compare( key ):
next.Value( value )
break
next = next.Next()
# no entry found, add one
if next is None:
# Add the entry to the front of the chain
add = Entry( key, value )
add.Next( self.index[ ix ] )
self.index[ ix ] = add
Class specific implementation
Of comparing two keys.
Integer Hash (part 3)
class Hash( object ):
# Get the value for the key
def Get( self, key ):
ix = self.Index( key )
# See if the key exists in the chain at this entry in the index
next = self.index[ ix ]
while next is not None:
# Entry found, update the value
if next.Compare( key ):
return next.Value()
next = next.Next()
# not found
return None
Time Complexity : O(1) – no collisions (sparse)
O(n) – collisions
String (Object) Hash
• String (Object) Hash Algorithm
1. Convert the key to an integer value, which then can be divided by the range to get the
remainder (modulo).
2. In Python, the equivalent is the builtin function hash().
0
1
2
3
4
n
***
Range
None (no entry at index)
A
A B
Single Entry (no collision)
Chain of Entries (collisions)
Index = hash( value )
“my name”
Hash Table with Linear Probing
• A hash table without linked lists and instead handle collisions with
linear probing. In this case, we assume that the size of the table will
be greater than or equal to the number of keys.
1. Map each value into a fixed size integer range using a hash function.
2. If there is no entry at the index, add the key/value to the index.
3. If there is an entry and the key matches the entry (duplicate), then update the value.
4. If there is an entry and the key does not match the entry, then probe downward in
a linear fashion.
• If the entry is empty, add the key/value pair to the entry.
• If a key matches (duplicate), then update the entry.
• If the key does not match, continue to the next entry.
100 (index = )
202 (index = 2)
302 (index = 2)
n
***
Range
(e.g., 100)
Probe, 302 collides with 202 (index = 2)
Hash Table with Linear Probing
class HashLP( object ):
# Add a key/value entry to the index
def Add( self, key, value ):
# Linear probe the entries for an empty or matching slot.
for ix in range( self.Index( key ), self.RANGE ):
# there is no entry at this index, add the key/value
if self.index[ ix ] is None:
self.index[ ix ] = Entry( key, value )
break
# Entry found, update the value
if self.index[ ix ].Compare( key ):
self.index[ ix ].Value( value )
break
# Get the value for the key
def Get( self, key ):
ix = self.Index( key )
# Linear probe the entries for an empty or matching slot.
for ix in range( self.Index( key ), self.RANGE ):
# there is no entry at this index, return not found
if self.index[ ix ] is None:
return None
# Entry found
if self.index[ ix ].Compare( key ):
return self.index[ ix ].Value();
# not found
return None
Coding Challenge
• Python Language Constructs Covered:
1. Ord() builtin function
2. Bitwise-Mask
String Manipulation
Reverse String
• Reverse String - Iterative
1. Create a StringBuffer (or character array) to hold the reversed string.
2. Starting at the end of the string and moving backwards, append each character to
the reversed string.
• Reverse String – Recursive
1. If the original string is one character, if so then return the string.
2. Otherwise, break the string into two parts: the first character and the remainder of
the string.
3. Make a recursive call with the remaining string and append the first character to the
return from the call.
S t r i n g
g n i r t S
Backward Scan
Forward Copy
Copy Buffer
Original
Iterative
Reverse String
def ReverseString( original ):
reversed = “” # copy for reversed string
length = len( original ) # length of original string
for ix in range( length-1, -1, -1 ):
reversed += original[ ix ]
return reversed
Iterative
def ReverseStringR( original ):
if len( original ) > 1:
return ReverseStringR( original[1:] ) + original[ 0 ]
return original
Recursive
Palindrome - Word
• Palindrome - the same word/phrase spelled forward or backwards,
such as: madam, civic, racecar.
• Solution without making a copy of the string.
1. Iterate through the first half of the string. When the string is an odd number of
characters, skip the middle character.
2. On each iteration, compare the current character at the front of the string to the
same position but from the rear of the string.
3. If they do not much, it is not a palindrome.
r a c e c a
Backward ScanForward Scan
middle
r
Palindrome - Phrase
• Solve the same for phrases, regardless of the positioning of spaces,
punctuation and capitalizing, such as: My gym.
• Solution without making a copy of the string.
1. Iterate simultaneously from the front (forward) and back (backward) of the string,
until the two iterators meet.
2. If current character of either iterator is a punctuation or space character, then
advance the corresponding iterator.
3. Otherwise, if the lowercase value of the current character from both iterators do
not equal, then it is not a palindrome.
4. Advance both iterators and repeat.
M y g y m
Backward ScanForward Scan
middle
.
m
Palindrome
def Palindrome( s ):
length = len( s )
for i in range( 0, int( length / 2 ) ):
if s[ i ] != s[ length - i - 1 ]:
return False
return True
def PalindromeP( s ):
length = len( s )
i = 0
j = length - 1
while i < j:
if isPunctOrSpace( s[ i ] ):
i += 1
continue
if isPunctOrSpace( s[ j ] ):
j -= 1
continue
if s[ i ].lower() != s[ j ].lower():
return False
i += 1
if j != i:
j -= 1
return True
Word
Phrase
Calculate the reverse (backward) distance
Builtin string routine to lowercase a character.
Character Count
• Count all occurrences of every character in a string.
1. Create a counter for the 96 ASCII printable characters.
2. Iterate through the string, incrementing the character specific index in the counter
for each character.
r a c e c a
Forward Scan
r
Counter
Duplicate Character Count
• Count all occurrences of duplicate characters in a string.
1. Make a pass over the string to generate a character count index.
2. Make a pass over the character count index using a bitwise mask to mask out
single character occurrences (leaving only duplicates with non-zero values).
r a c e c a
Forward Scan
r
a=2 c=2 e=1b=0 d=0 r=2***
Counter
a=1 c=1 e=0b=0 d=0 r=1***
Mask &= ~0x01
Duplicates: Non-Zero value
Character and Duplicate Counts
def CharOccur( s ):
counter = [0] * 96 # codes 32 .. 127 are printable (so skip first 32)
length = len(s)
# use counter as an accumulator while we count each character in string
for i in range( 0, length):
counter[ ord( s[ i ] ) - 32 ] += 1 # offset ascii code by 32
return counter
Character Count
Builtin function that returns the ASCII value of the character.
def DupChar( s ):
# Get the character occurrences
dup = CharOccur( s )
# Mask out all single count occurrences
length = len( dup )
for i in range( 0, length):
dup[ i ] &= ~0x01;
return dup
Duplicate Count
A mask is the complement (inverse) of the value to remove
1 de 89

Recomendados

Java Collections Framework por
Java Collections FrameworkJava Collections Framework
Java Collections FrameworkSony India Software Center
4.5K visualizações36 slides
collection framework in java por
collection framework in javacollection framework in java
collection framework in javaMANOJ KUMAR
425 visualizações32 slides
Object Oriented Programming Principles por
Object Oriented Programming PrinciplesObject Oriented Programming Principles
Object Oriented Programming PrinciplesAndrew Ferlitsch
1.6K visualizações8 slides
Python Programming Essentials - M12 - Lists por
Python Programming Essentials - M12 - ListsPython Programming Essentials - M12 - Lists
Python Programming Essentials - M12 - ListsP3 InfoTech Solutions Pvt. Ltd.
2.1K visualizações22 slides
Python Dictionary por
Python DictionaryPython Dictionary
Python DictionarySoba Arjun
251 visualizações7 slides
Python list por
Python listPython list
Python listArchanaBhumkar
1.1K visualizações15 slides

Mais conteúdo relacionado

Mais procurados

Set methods in python por
Set methods in pythonSet methods in python
Set methods in pythondeepalishinkar1
297 visualizações25 slides
Standard template library por
Standard template libraryStandard template library
Standard template libraryJancypriya M
228 visualizações22 slides
Data structure and algorithm notes por
Data structure and algorithm notesData structure and algorithm notes
Data structure and algorithm notessuman khadka
369 visualizações135 slides
Java Stack Data Structure.pptx por
Java Stack Data Structure.pptxJava Stack Data Structure.pptx
Java Stack Data Structure.pptxvishal choudhary
534 visualizações9 slides
Java Queue.pptx por
Java Queue.pptxJava Queue.pptx
Java Queue.pptxvishal choudhary
421 visualizações7 slides
What is Dictionary In Python? Python Dictionary Tutorial | Edureka por
What is Dictionary In Python? Python Dictionary Tutorial | EdurekaWhat is Dictionary In Python? Python Dictionary Tutorial | Edureka
What is Dictionary In Python? Python Dictionary Tutorial | EdurekaEdureka!
466 visualizações16 slides

Mais procurados(20)

Set methods in python por deepalishinkar1
Set methods in pythonSet methods in python
Set methods in python
deepalishinkar1297 visualizações
Standard template library por Jancypriya M
Standard template libraryStandard template library
Standard template library
Jancypriya M228 visualizações
Data structure and algorithm notes por suman khadka
Data structure and algorithm notesData structure and algorithm notes
Data structure and algorithm notes
suman khadka369 visualizações
Java Stack Data Structure.pptx por vishal choudhary
Java Stack Data Structure.pptxJava Stack Data Structure.pptx
Java Stack Data Structure.pptx
vishal choudhary534 visualizações
Java Queue.pptx por vishal choudhary
Java Queue.pptxJava Queue.pptx
Java Queue.pptx
vishal choudhary421 visualizações
What is Dictionary In Python? Python Dictionary Tutorial | Edureka por Edureka!
What is Dictionary In Python? Python Dictionary Tutorial | EdurekaWhat is Dictionary In Python? Python Dictionary Tutorial | Edureka
What is Dictionary In Python? Python Dictionary Tutorial | Edureka
Edureka!466 visualizações
Java Collection framework por ankitgarg_er
Java Collection frameworkJava Collection framework
Java Collection framework
ankitgarg_er14.3K visualizações
A importância de DDD e o Domain Model na construção de APIs! por Isaac de Souza
A importância de DDD e o Domain Model na construção de APIs!A importância de DDD e o Domain Model na construção de APIs!
A importância de DDD e o Domain Model na construção de APIs!
Isaac de Souza166 visualizações
How Hashmap works internally in java por Ramakrishna Joshi
How Hashmap works internally  in javaHow Hashmap works internally  in java
How Hashmap works internally in java
Ramakrishna Joshi908 visualizações
Introduction to elasticsearch por hypto
Introduction to elasticsearchIntroduction to elasticsearch
Introduction to elasticsearch
hypto2.3K visualizações
Stack_Data_Structure.pptx por sandeep54552
Stack_Data_Structure.pptxStack_Data_Structure.pptx
Stack_Data_Structure.pptx
sandeep54552609 visualizações
Linked list por eShikshak
Linked listLinked list
Linked list
eShikshak2.4K visualizações
Prefix, Infix and Post-fix Notations por Afaq Mansoor Khan
Prefix, Infix and Post-fix NotationsPrefix, Infix and Post-fix Notations
Prefix, Infix and Post-fix Notations
Afaq Mansoor Khan4K visualizações
Linked list por FURQAN M LODHI
Linked listLinked list
Linked list
FURQAN M LODHI1.2K visualizações
Data Structures (CS8391) por Elavarasi K
Data Structures (CS8391)Data Structures (CS8391)
Data Structures (CS8391)
Elavarasi K4.9K visualizações
Unit 4 plsql por DrkhanchanaR
Unit 4  plsqlUnit 4  plsql
Unit 4 plsql
DrkhanchanaR1.2K visualizações
Collections in-csharp por Lakshmi Mareddy
Collections in-csharpCollections in-csharp
Collections in-csharp
Lakshmi Mareddy2K visualizações

Similar a Whiteboarding Coding Challenges in Python

data structures and algorithms Unit 3 por
data structures and algorithms Unit 3data structures and algorithms Unit 3
data structures and algorithms Unit 3infanciaj
128 visualizações52 slides
Algorithms with-java-advanced-1.0 por
Algorithms with-java-advanced-1.0Algorithms with-java-advanced-1.0
Algorithms with-java-advanced-1.0BG Java EE Course
3.2K visualizações38 slides
Data types in python por
Data types in pythonData types in python
Data types in pythonRaginiJain21
7.1K visualizações21 slides
Searching, Sorting and Complexity analysis in DS.pdf por
Searching, Sorting and Complexity analysis in DS.pdfSearching, Sorting and Complexity analysis in DS.pdf
Searching, Sorting and Complexity analysis in DS.pdfAkshatMehrotra14
4 visualizações15 slides
Sorting por
SortingSorting
SortingSaurabh Mishra
886 visualizações40 slides
Arrays in C.pptx por
Arrays in C.pptxArrays in C.pptx
Arrays in C.pptxHarsimranKaur362773
7 visualizações52 slides

Similar a Whiteboarding Coding Challenges in Python(20)

data structures and algorithms Unit 3 por infanciaj
data structures and algorithms Unit 3data structures and algorithms Unit 3
data structures and algorithms Unit 3
infanciaj128 visualizações
Algorithms with-java-advanced-1.0 por BG Java EE Course
Algorithms with-java-advanced-1.0Algorithms with-java-advanced-1.0
Algorithms with-java-advanced-1.0
BG Java EE Course 3.2K visualizações
Data types in python por RaginiJain21
Data types in pythonData types in python
Data types in python
RaginiJain217.1K visualizações
Searching, Sorting and Complexity analysis in DS.pdf por AkshatMehrotra14
Searching, Sorting and Complexity analysis in DS.pdfSearching, Sorting and Complexity analysis in DS.pdf
Searching, Sorting and Complexity analysis in DS.pdf
AkshatMehrotra144 visualizações
Sorting por Saurabh Mishra
SortingSorting
Sorting
Saurabh Mishra886 visualizações
ACP-arrays.pptx por MuhammadSubtain9
ACP-arrays.pptxACP-arrays.pptx
ACP-arrays.pptx
MuhammadSubtain94 visualizações
Bca ii dfs u-2 linklist,stack,queue por Rai University
Bca ii  dfs u-2 linklist,stack,queueBca ii  dfs u-2 linklist,stack,queue
Bca ii dfs u-2 linklist,stack,queue
Rai University795 visualizações
Sorting algorithums > Data Structures & Algorithums por Ain-ul-Moiz Khawaja
Sorting algorithums  > Data Structures & AlgorithumsSorting algorithums  > Data Structures & Algorithums
Sorting algorithums > Data Structures & Algorithums
Ain-ul-Moiz Khawaja1K visualizações
Algorithm Design and Complexity - Course 4 - Heaps and Dynamic Progamming por Traian Rebedea
Algorithm Design and Complexity - Course 4 - Heaps and Dynamic ProgammingAlgorithm Design and Complexity - Course 4 - Heaps and Dynamic Progamming
Algorithm Design and Complexity - Course 4 - Heaps and Dynamic Progamming
Traian Rebedea5.8K visualizações
Bsc cs ii dfs u-2 linklist,stack,queue por Rai University
Bsc cs ii  dfs u-2 linklist,stack,queueBsc cs ii  dfs u-2 linklist,stack,queue
Bsc cs ii dfs u-2 linklist,stack,queue
Rai University503 visualizações
Chapter3.pptx por ASMAALWADEE2
Chapter3.pptxChapter3.pptx
Chapter3.pptx
ASMAALWADEE227 visualizações
Selection sort por asra khan
Selection sortSelection sort
Selection sort
asra khan5.3K visualizações
Mca ii dfs u-3 linklist,stack,queue por Rai University
Mca ii dfs u-3 linklist,stack,queueMca ii dfs u-3 linklist,stack,queue
Mca ii dfs u-3 linklist,stack,queue
Rai University901 visualizações
Daa chapter5 por B.Kirron Reddi
Daa chapter5Daa chapter5
Daa chapter5
B.Kirron Reddi35 visualizações
lecture-k-sorting.ppt por SushantRaj25
lecture-k-sorting.pptlecture-k-sorting.ppt
lecture-k-sorting.ppt
SushantRaj2515 visualizações
Lecture k-sorting por Vijayaraj Raj
Lecture k-sortingLecture k-sorting
Lecture k-sorting
Vijayaraj Raj16 visualizações
Data structures arrays por maamir farooq
Data structures   arraysData structures   arrays
Data structures arrays
maamir farooq207 visualizações

Mais de Andrew Ferlitsch

AI - Intelligent Agents por
AI - Intelligent AgentsAI - Intelligent Agents
AI - Intelligent AgentsAndrew Ferlitsch
4.6K visualizações13 slides
Pareto Principle Applied to QA por
Pareto Principle Applied to QAPareto Principle Applied to QA
Pareto Principle Applied to QAAndrew Ferlitsch
1.6K visualizações29 slides
Python - OOP Programming por
Python - OOP ProgrammingPython - OOP Programming
Python - OOP ProgrammingAndrew Ferlitsch
1K visualizações9 slides
Python - Installing and Using Python and Jupyter Notepad por
Python - Installing and Using Python and Jupyter NotepadPython - Installing and Using Python and Jupyter Notepad
Python - Installing and Using Python and Jupyter NotepadAndrew Ferlitsch
352 visualizações6 slides
Natural Language Processing - Groupings (Associations) Generation por
Natural Language Processing - Groupings (Associations) GenerationNatural Language Processing - Groupings (Associations) Generation
Natural Language Processing - Groupings (Associations) GenerationAndrew Ferlitsch
235 visualizações14 slides
Natural Language Provessing - Handling Narrarive Fields in Datasets for Class... por
Natural Language Provessing - Handling Narrarive Fields in Datasets for Class...Natural Language Provessing - Handling Narrarive Fields in Datasets for Class...
Natural Language Provessing - Handling Narrarive Fields in Datasets for Class...Andrew Ferlitsch
224 visualizações24 slides

Mais de Andrew Ferlitsch(20)

AI - Intelligent Agents por Andrew Ferlitsch
AI - Intelligent AgentsAI - Intelligent Agents
AI - Intelligent Agents
Andrew Ferlitsch4.6K visualizações
Pareto Principle Applied to QA por Andrew Ferlitsch
Pareto Principle Applied to QAPareto Principle Applied to QA
Pareto Principle Applied to QA
Andrew Ferlitsch1.6K visualizações
Python - OOP Programming por Andrew Ferlitsch
Python - OOP ProgrammingPython - OOP Programming
Python - OOP Programming
Andrew Ferlitsch1K visualizações
Python - Installing and Using Python and Jupyter Notepad por Andrew Ferlitsch
Python - Installing and Using Python and Jupyter NotepadPython - Installing and Using Python and Jupyter Notepad
Python - Installing and Using Python and Jupyter Notepad
Andrew Ferlitsch352 visualizações
Natural Language Processing - Groupings (Associations) Generation por Andrew Ferlitsch
Natural Language Processing - Groupings (Associations) GenerationNatural Language Processing - Groupings (Associations) Generation
Natural Language Processing - Groupings (Associations) Generation
Andrew Ferlitsch235 visualizações
Natural Language Provessing - Handling Narrarive Fields in Datasets for Class... por Andrew Ferlitsch
Natural Language Provessing - Handling Narrarive Fields in Datasets for Class...Natural Language Provessing - Handling Narrarive Fields in Datasets for Class...
Natural Language Provessing - Handling Narrarive Fields in Datasets for Class...
Andrew Ferlitsch224 visualizações
Machine Learning - Introduction to Recurrent Neural Networks por Andrew Ferlitsch
Machine Learning - Introduction to Recurrent Neural NetworksMachine Learning - Introduction to Recurrent Neural Networks
Machine Learning - Introduction to Recurrent Neural Networks
Andrew Ferlitsch371 visualizações
Machine Learning - Introduction to Convolutional Neural Networks por Andrew Ferlitsch
Machine Learning - Introduction to Convolutional Neural NetworksMachine Learning - Introduction to Convolutional Neural Networks
Machine Learning - Introduction to Convolutional Neural Networks
Andrew Ferlitsch1.4K visualizações
Machine Learning - Introduction to Neural Networks por Andrew Ferlitsch
Machine Learning - Introduction to Neural NetworksMachine Learning - Introduction to Neural Networks
Machine Learning - Introduction to Neural Networks
Andrew Ferlitsch270 visualizações
Python - Numpy/Pandas/Matplot Machine Learning Libraries por Andrew Ferlitsch
Python - Numpy/Pandas/Matplot Machine Learning LibrariesPython - Numpy/Pandas/Matplot Machine Learning Libraries
Python - Numpy/Pandas/Matplot Machine Learning Libraries
Andrew Ferlitsch3.5K visualizações
Machine Learning - Accuracy and Confusion Matrix por Andrew Ferlitsch
Machine Learning - Accuracy and Confusion MatrixMachine Learning - Accuracy and Confusion Matrix
Machine Learning - Accuracy and Confusion Matrix
Andrew Ferlitsch3.3K visualizações
Machine Learning - Ensemble Methods por Andrew Ferlitsch
Machine Learning - Ensemble MethodsMachine Learning - Ensemble Methods
Machine Learning - Ensemble Methods
Andrew Ferlitsch2.2K visualizações
ML - Multiple Linear Regression por Andrew Ferlitsch
ML - Multiple Linear RegressionML - Multiple Linear Regression
ML - Multiple Linear Regression
Andrew Ferlitsch2.5K visualizações
ML - Simple Linear Regression por Andrew Ferlitsch
ML - Simple Linear RegressionML - Simple Linear Regression
ML - Simple Linear Regression
Andrew Ferlitsch3.1K visualizações
Machine Learning - Dummy Variable Conversion por Andrew Ferlitsch
Machine Learning - Dummy Variable ConversionMachine Learning - Dummy Variable Conversion
Machine Learning - Dummy Variable Conversion
Andrew Ferlitsch769 visualizações
Machine Learning - Splitting Datasets por Andrew Ferlitsch
Machine Learning - Splitting DatasetsMachine Learning - Splitting Datasets
Machine Learning - Splitting Datasets
Andrew Ferlitsch4.6K visualizações
Machine Learning - Dataset Preparation por Andrew Ferlitsch
Machine Learning - Dataset PreparationMachine Learning - Dataset Preparation
Machine Learning - Dataset Preparation
Andrew Ferlitsch2K visualizações
Machine Learning - Introduction to Tensorflow por Andrew Ferlitsch
Machine Learning - Introduction to TensorflowMachine Learning - Introduction to Tensorflow
Machine Learning - Introduction to Tensorflow
Andrew Ferlitsch1.2K visualizações
Introduction to Machine Learning por Andrew Ferlitsch
Introduction to Machine LearningIntroduction to Machine Learning
Introduction to Machine Learning
Andrew Ferlitsch284 visualizações
AI - Introduction to Dynamic Programming por Andrew Ferlitsch
AI - Introduction to Dynamic ProgrammingAI - Introduction to Dynamic Programming
AI - Introduction to Dynamic Programming
Andrew Ferlitsch537 visualizações

Último

"Surviving highload with Node.js", Andrii Shumada por
"Surviving highload with Node.js", Andrii Shumada "Surviving highload with Node.js", Andrii Shumada
"Surviving highload with Node.js", Andrii Shumada Fwdays
49 visualizações29 slides
Keynote Talk: Open Source is Not Dead - Charles Schulz - Vates por
Keynote Talk: Open Source is Not Dead - Charles Schulz - VatesKeynote Talk: Open Source is Not Dead - Charles Schulz - Vates
Keynote Talk: Open Source is Not Dead - Charles Schulz - VatesShapeBlue
178 visualizações15 slides
Network Source of Truth and Infrastructure as Code revisited por
Network Source of Truth and Infrastructure as Code revisitedNetwork Source of Truth and Infrastructure as Code revisited
Network Source of Truth and Infrastructure as Code revisitedNetwork Automation Forum
49 visualizações45 slides
Import Export Virtual Machine for KVM Hypervisor - Ayush Pandey - University ... por
Import Export Virtual Machine for KVM Hypervisor - Ayush Pandey - University ...Import Export Virtual Machine for KVM Hypervisor - Ayush Pandey - University ...
Import Export Virtual Machine for KVM Hypervisor - Ayush Pandey - University ...ShapeBlue
48 visualizações17 slides
DRaaS using Snapshot copy and destination selection (DRaaS) - Alexandre Matti... por
DRaaS using Snapshot copy and destination selection (DRaaS) - Alexandre Matti...DRaaS using Snapshot copy and destination selection (DRaaS) - Alexandre Matti...
DRaaS using Snapshot copy and destination selection (DRaaS) - Alexandre Matti...ShapeBlue
69 visualizações29 slides
Migrating VMware Infra to KVM Using CloudStack - Nicolas Vazquez - ShapeBlue por
Migrating VMware Infra to KVM Using CloudStack - Nicolas Vazquez - ShapeBlueMigrating VMware Infra to KVM Using CloudStack - Nicolas Vazquez - ShapeBlue
Migrating VMware Infra to KVM Using CloudStack - Nicolas Vazquez - ShapeBlueShapeBlue
147 visualizações20 slides

Último(20)

"Surviving highload with Node.js", Andrii Shumada por Fwdays
"Surviving highload with Node.js", Andrii Shumada "Surviving highload with Node.js", Andrii Shumada
"Surviving highload with Node.js", Andrii Shumada
Fwdays49 visualizações
Keynote Talk: Open Source is Not Dead - Charles Schulz - Vates por ShapeBlue
Keynote Talk: Open Source is Not Dead - Charles Schulz - VatesKeynote Talk: Open Source is Not Dead - Charles Schulz - Vates
Keynote Talk: Open Source is Not Dead - Charles Schulz - Vates
ShapeBlue178 visualizações
Network Source of Truth and Infrastructure as Code revisited por Network Automation Forum
Network Source of Truth and Infrastructure as Code revisitedNetwork Source of Truth and Infrastructure as Code revisited
Network Source of Truth and Infrastructure as Code revisited
Network Automation Forum49 visualizações
Import Export Virtual Machine for KVM Hypervisor - Ayush Pandey - University ... por ShapeBlue
Import Export Virtual Machine for KVM Hypervisor - Ayush Pandey - University ...Import Export Virtual Machine for KVM Hypervisor - Ayush Pandey - University ...
Import Export Virtual Machine for KVM Hypervisor - Ayush Pandey - University ...
ShapeBlue48 visualizações
DRaaS using Snapshot copy and destination selection (DRaaS) - Alexandre Matti... por ShapeBlue
DRaaS using Snapshot copy and destination selection (DRaaS) - Alexandre Matti...DRaaS using Snapshot copy and destination selection (DRaaS) - Alexandre Matti...
DRaaS using Snapshot copy and destination selection (DRaaS) - Alexandre Matti...
ShapeBlue69 visualizações
Migrating VMware Infra to KVM Using CloudStack - Nicolas Vazquez - ShapeBlue por ShapeBlue
Migrating VMware Infra to KVM Using CloudStack - Nicolas Vazquez - ShapeBlueMigrating VMware Infra to KVM Using CloudStack - Nicolas Vazquez - ShapeBlue
Migrating VMware Infra to KVM Using CloudStack - Nicolas Vazquez - ShapeBlue
ShapeBlue147 visualizações
Backroll, News and Demo - Pierre Charton, Matthias Dhellin, Ousmane Diarra - ... por ShapeBlue
Backroll, News and Demo - Pierre Charton, Matthias Dhellin, Ousmane Diarra - ...Backroll, News and Demo - Pierre Charton, Matthias Dhellin, Ousmane Diarra - ...
Backroll, News and Demo - Pierre Charton, Matthias Dhellin, Ousmane Diarra - ...
ShapeBlue121 visualizações
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLive por Network Automation Forum
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLiveAutomating a World-Class Technology Conference; Behind the Scenes of CiscoLive
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLive
Network Automation Forum49 visualizações
Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ... por ShapeBlue
Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ...Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ...
Live Demo Showcase: Unveiling Dell PowerFlex’s IaaS Capabilities with Apache ...
ShapeBlue52 visualizações
Extending KVM Host HA for Non-NFS Storage - Alex Ivanov - StorPool por ShapeBlue
Extending KVM Host HA for Non-NFS Storage -  Alex Ivanov - StorPoolExtending KVM Host HA for Non-NFS Storage -  Alex Ivanov - StorPool
Extending KVM Host HA for Non-NFS Storage - Alex Ivanov - StorPool
ShapeBlue56 visualizações
Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava... por ShapeBlue
Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava...Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava...
Centralized Logging Feature in CloudStack using ELK and Grafana - Kiran Chava...
ShapeBlue74 visualizações
Igniting Next Level Productivity with AI-Infused Data Integration Workflows por Safe Software
Igniting Next Level Productivity with AI-Infused Data Integration Workflows Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Safe Software373 visualizações
Developments to CloudStack’s SDN ecosystem: Integration with VMWare NSX 4 - P... por ShapeBlue
Developments to CloudStack’s SDN ecosystem: Integration with VMWare NSX 4 - P...Developments to CloudStack’s SDN ecosystem: Integration with VMWare NSX 4 - P...
Developments to CloudStack’s SDN ecosystem: Integration with VMWare NSX 4 - P...
ShapeBlue120 visualizações
Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ... por ShapeBlue
Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ...Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ...
Backup and Disaster Recovery with CloudStack and StorPool - Workshop - Venko ...
ShapeBlue114 visualizações
CloudStack and GitOps at Enterprise Scale - Alex Dometrius, Rene Glover - AT&T por ShapeBlue
CloudStack and GitOps at Enterprise Scale - Alex Dometrius, Rene Glover - AT&TCloudStack and GitOps at Enterprise Scale - Alex Dometrius, Rene Glover - AT&T
CloudStack and GitOps at Enterprise Scale - Alex Dometrius, Rene Glover - AT&T
ShapeBlue81 visualizações
Business Analyst Series 2023 - Week 4 Session 7 por DianaGray10
Business Analyst Series 2023 -  Week 4 Session 7Business Analyst Series 2023 -  Week 4 Session 7
Business Analyst Series 2023 - Week 4 Session 7
DianaGray10110 visualizações
Confidence in CloudStack - Aron Wagner, Nathan Gleason - Americ por ShapeBlue
Confidence in CloudStack - Aron Wagner, Nathan Gleason - AmericConfidence in CloudStack - Aron Wagner, Nathan Gleason - Americ
Confidence in CloudStack - Aron Wagner, Nathan Gleason - Americ
ShapeBlue58 visualizações
Mitigating Common CloudStack Instance Deployment Failures - Jithin Raju - Sha... por ShapeBlue
Mitigating Common CloudStack Instance Deployment Failures - Jithin Raju - Sha...Mitigating Common CloudStack Instance Deployment Failures - Jithin Raju - Sha...
Mitigating Common CloudStack Instance Deployment Failures - Jithin Raju - Sha...
ShapeBlue113 visualizações
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas... por Bernd Ruecker
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
Bernd Ruecker50 visualizações

Whiteboarding Coding Challenges in Python

  • 1. Whiteboarding Coding Challenges in Python Portland Data Science Group Created by Andrew Ferlitsch Community Outreach Officer August, 2017
  • 3. Coding Challenge • Python Language Constructs Covered: 1. Main body 2. Indentation 3. Print 4. Line Comments 5. For loop – Range and Steps 6. If / else 7. Integer conversion Prime Numbers
  • 4. Prime Numbers • Prime numbers are numbers that are only divisible by one and itself. • Iterative Algorithm 1. For each number, we attempt to divide it by every number less than it, except for one. 2. The integer modulo operator is used to test if there is a remainder from the integer division. 3. If there is no remainder, it is divisible by the number and therefore not a prime. 4. If each of the numbers it is divided by has a remainder, it is a prime. print(“1) print(“2”) # Primes for numbers above 2 for number in range(3, 101): # Attempt to divide this number by every number between 2 and one less than itself for div in range(2, number): if (number % div) == 0: break else: print(number) Range is always one less than the endpoint Else clause is triggered when for loop does not complete all loops (i.e., break)
  • 5. Prime Numbers – Skip Even Numbers • Improvement: 1. Skip all even numbers, since they are divisible by two. 2. Odd numbers are not divisible by two, so skip dividing by even numbers. print(“1) print(“2”) Print(“3”) # Primes for numbers above 5 for number in range(5, 101, 2): # Attempt to divide this number by every number between 3 and one less than itself for div in range(3, number, 2): if (number % div) == 0: break else: print(number) Step thru range in increments of 2 (odd numbers)
  • 6. Prime Numbers – Skip Even Numbers, Divide by only 1/3 of range • Improvement: 1. Since we are skipping evens, each prime must be divisible by at least the number 3. 2. So a prime must be divisible by 1/3 of less of itself. print(“1) print(“2”) Print(“3”) # Primes for numbers above 5 for number in range(5, 101, 2): third = int(number / 3) + 1 # Attempt to divide this number by every number between 3 and 1/3 of itself for div in range(3, third, 2): if (number % div) == 0: break else: print(number) Round result to an integer
  • 7. Coding Challenge • Python Language Constructs Covered: 1. Function Definition 2. Iterative vs. Recursion 3. Variable Initialization 4. Return values Fibonacci Sequence
  • 8. Fibonacci Sequence – Recursive • A Fibonacci sequence is F(n) = F(n-1) + F(n-2) • Recursive Algorithm 1. Where F(0) = 0, F(1) = 1 2. F(n) = F(n-1) + F(n-2), where n >= 2 def fibonacci(n): # Where F(0) = 0, F(1) = 1 if n == 0: return 0 if n == 1: return 1 # Recursion when n >= 2 return fibonacci(n – 1) + fibonacci(n – 2) Recursion Function Definition
  • 9. Fibonacci Sequence - Iterative • Iterative Algorithm 1. Where F(0) = 0, F(1) = 1 2. F(n) = F(n-1) + F(n-2), where n >= 2 def fibonacci(n): # Where F(0) = 0, F(1) = 1 if n == 0: return 0 if n == 1: return 1 fn = 0 # current value for F(n) f_minus_1 = 1 # current value for F(n-1) f_minus_2 = 0 # current value for F(n-2) for i in range(2, n+1): # F(n) = F(n-1) + F(n-2) for current iteration fn = f_minus_1 + f_minus_2 # Calculate F(n-1) and F(n-2) for next iteration f_minus_2 = f_minus_1 f_minus_1 = fn return fn Initialize accumulators with n = 2 Range is always one less than the endpoint Next F(n-1), F(n-2) would equal the current F(n), F(n-1)
  • 10. Coding Challenge • Python Language Constructs Covered: 1. Static vs. Dynamic Array 2. Linked Lists 3. Class Definition 4. Class Constructor 5. Class Methods 6. Null (None) pointer 7. List Traversal Dynamic Arrays
  • 11. Dynamic Array • An Array which can dynamically resize itself (i.e., linked list). 1. Add or Insert into the array (i.e., expand). 2. Remove any element in the array (i.e., shorten). Static Array 0 Dynamically added element 3 1 2 3 Array is a contiguous block of memory, with each element of fixed size. Index of Element Address of element is: Address of start of array + ( index * element_size ) Dynamic Array 0 1 2 Link Link Link Array is a non-contiguous block of memory, With each element chained together by a link.
  • 12. Dynamic Array class Entry(object): # Definition for an array element def __init__(self, data): self.data = data # Entry data self.link = None # Link to next Entry in Array class Array(object): def __init__(self): self.array= None # initialize array to empty # Add element an element to the end of the array def add(self, data): # Empty Array if self.array is None: self.array = Entry(data) # Non-empty array else: # Find the last entry in the array prev = self.array while prev.link is not None: prev = prev.link # Add the element to the end of the list prev.link = Entry( data ) Definition for an entry in the dynamic array to hold the entry data and link. None is the null pointer. Set array to a single entry Remember last entry visited In the linked list of entries. When the link member is None (null), you are at the end of the linked list.
  • 13. Dynamic Array - Improvement class Array(object): last = None # last entry in array def __init__( self ): self.array= None # initialize array to empty # Add element an element to the end of the array def add( self, data ): entry = Entry( data ) # Empty Array if self.last is None: self.array = entry # Non-empty array else: self.last.link = entry # Set last entry to the newly added entry self.last = entry Keep location of last entry in array.
  • 14. Dynamic Array – Time Complexity • Add 1. By maintaining pointer to the end, does not need to traverse the array O(1) • Find 1. Must traverse the links in the array (index-1) times for the index, where 0 < index < n O(n/2) = O(n) • Delete 1. Must traverse the links in the array (index-1) times for the index, where 0 < index < n O(n/2) = O(n) In complexity notation (Omega), multiplication and division by a constant is removed Omega In complexity notation (Omega), 1 is used to represent constant time. In complexity notation (Omega), n is the number of elements.
  • 15. Coding Challenge • Python Language Constructs Covered: 1. First In, First Out 2. Python Dynamic (builtin) Arrays 3. append() array method 4. len() object method 5. Copying elements 6. del operator Queue
  • 16. Queue • FIFO (First In, First Out) – Data Structure 1. Enqueue – add an element to the back of the list 2. Dequeue – remove an element from the front of the list x1 x2 Enqueue Each element is added to the end of the queue x2 Dequeue x3 x3 Each element is removed from the front of the queue x3 x1
  • 17. Queue class Queue(object): def __init__(self): self.queue = [] # initialize queue to empty dynamic array # Add element to queue def enqueue( self, element ): self.queue.append( element ) # Remove element from front of the queue def dequeue( self ): # Empty Queue condition if len( self.queue ) == 0: return None # Get (remember) the first element from the queue element = self.queue[ 0 ] # Remove (drop) the first element in the queue del self.queue[ 0 ] # Return the first element return element append() method adds an element to end of array/list. len() function returns the number of elements in an array/list. Makes a local copy of the first element. The del operator will remove an element in an array/list at the specified location. Notation for empty list/array.
  • 18. Coding Challenge • Python Language Constructs Covered: 1. Last In, Last Out 2. insert() array method Stack
  • 19. Stack • LIFO (Last In, First Out) – Data Structure 1. Push – add an element to the front of the list 2. Pop – remove an element from the front of the list x3 x2 Push Each element is added to the front of the stack x2 Pop x1 x3 Each element is removed from the front of the stack x3 x3
  • 20. Stack class Stack(object): def __init__( self ): self.stack = [] # initialize stack to empty dynamic array # Add element to the stack def push( self, element ): self.stack.insert( 0, element ) # Remove element from front of the stack def pop( self ): # Empty Stack condition if len( self.stack ) == 0: return None # Get (remember) the first element from the stack element = self.stack[ 0 ] # Remove (drop) the first element in the stack del self.stack[ 0 ] # Return the first element return element insert() method inserts an element to an array/list at the specified index.
  • 21. Coding Challenge • Python Language Constructs Covered: 1. Importing a library 2. Prioritized Queue : heappush(), heappop() Heap
  • 22. Heap • Prioritized Queue (Sorted by value) – Data Structure 1. Push – add an element to the sorted position in the list 2. Pop – remove an element from the front of the list x3 x3 Push Each element is added at it’s sorted location In the queue x2 Pop x1 x3 Each element is removed from the front of the queue x3 x3
  • 23. Heap from heapq import heappush, heappop class Heap(object): def __init__( self ): self.heap = [] # initialize heap to empty dynamic array # Add element to the (sorted) heap def push( self, element ): heappush( self.heap, element ) # Remove element from front of the (sorted) heap def pop( self ): # Empty Heap condition if len( self.heap ) == 0: return None # Get the first element from the heap element = heappop( self.heap ) # Return the first element return element heappush() function inserts an element to a sorted array/list. Heappop() function removes the first element from a sorted array/list. Import the classes heappush and heappop from the library heapq.
  • 24. Queue, Stack, Heap -Time Complexity • Queue Enqueue O(1) Dequeue O(1) • Stack Push O(1) Pop O(1) • Heap Push O(n) Pop O(1) Must traverse array to find location to insert.
  • 25. Coding Challenge • Python Language Constructs Covered: 1. Arithmetic Assignment 2. Recurring back in Recursion StackChain
  • 26. StackChain • Chain of Stacks of Fixed Size 1. When an element is pushed to a stack that has reached its maximum (fixed) size, the bottom of the stack is removed and pushed to the top of the next stack on the chain. 2. Likewise, when an element is popped from the stack, the top of the next stack that is chained to it is popped and added to the bottom of the stack, and so forth. x4 x3 Push x2 x4 x1 Fixed Size (e.g., 3) Removed from the bottom and pushed to top of the next stack. x3 Pop x2 x3 x1 Removed from the top and pushed to top of the previous stack.
  • 27. StackChain class StackChain(object): def __init__( self, max ): self.max = max # maximum size of a stack self.stack = [] # initialize this stack to empty list/array. self.chain = None # next stack in chain # Add element to the stack chain def push( self, element ): self.stack.insert( 0, element ) # stack is less than full if len( self.stack ) < self.max: self.max += 1 # stack is full else: # Allocate the next stack in chain, if there is not one already. if self.chain == None: self.chain = stackChain( self.max ) # Get (remember) the element from the bottom of the stack element = self.stack[ self.max - 1 ] # Remove the element del self.stack[ self.max - 1 ] # push the element to the next stack in the chain self.chain.stack.push( element ) No increment/decrement in Python. Recursive call, will cascade until the last stack in chain is less than full.
  • 28. StackChain class StackChain(object): # Remove element from the stack chain def pop( self ): # stack is empty if len( self.stack ) == 0: return None # Get (Remember) top element in stack element = self.stack[ 0 ] # Remove the element from the stack del self.stack[ 0 ] # There is another stack in the chain if self.chain is not None: # Pop the top element from the next stack in the chain bottom = pop( self.chain.stack ) # Add the element to the bottom of this stack self.stack.append( bottom ) # Return the top of the stack return element Recursive call, will cascade to the last stack and recur backwards moving the top of the stack to the bottom of the previous stack.
  • 29. Coding Challenge • Python Language Constructs Covered: 1. Initializing size of an array 2. Recursive Sub-Solutions Towers of Hanoi
  • 30. Towers of Hanoi - Recursion • Three Towers, stack of disks on start Tower, each disk smaller than proceeding disk. Move the disks to the end Tower. 1. You move one disc at a time from the top of one tower to the top of another tower. 2. You can not place a larger disc on top of a smaller disc. Start Intermediate End Solve for N-1 Discs Move disc N to End StartIntermediate End Move disc N to EndSolve for N-1 Discs Recursion
  • 31. Towers of Hanoi class Hanoi(object): towers = [ None ] * 3 # Initialize 3 towers with no discs on them for i in range( 0, 3 ): towers[ i ] = Stack() def __init__(self, ndiscs ): self.ndiscs = ndiscs # the number of discs # initialize the first tower with discs in ascending order. for i in range ( ndiscs, 0, -1 ): self.towers[ 0 ].push( i ) # Recursive method to move ndiscs from start to end def move( self, ndiscs, start, intermediate, end ): # if single disk left, move it from start to end if ndiscs == 1: end.push( start.pop() ) else: # move the remainder of the tower to the intermediate tower self.move( ndiscs - 1, start, end, intermediate ) # move the bottom disc to the end tower end.push( start.pop() ) # move the remainder of the intermediate tower to the end tower self.move( ndiscs - 1, intermediate, start, end ) def play( self ): self.move( self.ndiscs, self.towers[ 0 ], self.towers[ 1 ], self.towers[ 2 ] ) Can initialize class member variables Outside of the constructor (__init__) Notation for initializing an array of fixed size (e.g., 3). Recursively solve sub-problems
  • 32. Coding Challenge • Python Language Constructs Covered: 1. Nodes & Subtrees 2. Default Parameters 3. Emulating Method Overloading Binary Tree
  • 33. Binary Tree • A Binary Tree is a type of directed graph tree where each node contains at most two branches (subtrees), commonly referred to as the left and right branch. 1. The recursive definition is a binary tree is either empty, a single node, where the left and right branches are binary subtrees. A B C D E Left Left Root Right Right Nodes Leaves Binary subtree
  • 34. Binary Tree class BinaryTree(object): # Constructor: set the node data and left/right subtrees to null def __init__(self, key): self.left = None # left binary subtree self.right = None # right binary subtree self.key = key # node data # Get ot Set Left Binary Subtree def Left(self, left = None): if left is None: return self.left self.left = left # Get or Set Right Binary Subtree def Right(self, right = None): if right is None: return self.right self.right = right # Get ot Set Node Data def Key(self, key = None): if key is None: return self.key self.key = key Good Practice to have parent classes explicitly Inherit the object class, which all classes implicitly inherit. Default parameter. If not specified, will default to None. Technique to emulate (fake) method overloading using default parameter. If parameter not specified, then it’s a getter[ otherwise (if specified), it’s a setter.
  • 35. Coding Challenge • Python Language Constructs Covered: 1. is operator vs. == 2. Default Parameters 3. Recursion (more) 4. Returning multiple values and Assignment of multiple variables Binary Tree Traversals
  • 36. Binary Tree Traversals • Binary Trees can be traversed either breadth first (BFS) or depth first (DFS). • Breadth First Search – tree is traversed one level at a time. • The root node (level 1) is first visited, then the left node, then the right node (level 2) of the root, and then the left and right nodes of the these subtrees (level 3), and so forth. • Depth First Search – tree is searched either inorder, preorder, or postorder. • Inorder : left (node), root, right • Preorder : root, left, right • Postorder: left, right, root
  • 37. BFS Traversal # Breadth First Search def BFS( root ): # Check if tree is empty if root is None: return # list of nodes to visit in node level order visit = [] visit.append( root ) # sequentially visit each node in level order as it is dynamically added to the list i = 0 while i < len( visit ): # Add to the list the child siblings of this node if visit[ i ].Left() is not None: visit.append( visit[ i ].Left() ) if visit[ i ].Right() is not None: visit.append( visit[ i ].Right() ) i += 1 Visit is a dynamic array Good practice when comparing to None to use ‘is’ instead of == Good practice when comparing to None to use ‘is not’ instead of !=
  • 38. DFS Traversal Recursive Algorithms # InOrder Traversal def InOrder(root): if root is None: return InOrder( root.Left() ) root.Action() InOrder( root.Right() ) # PreOrder Traversal def PreOrder(root): if root is None: return root.Action() PreOrder( root.Left() ) PreOrder( root.Right() ) # PostOrder Traversal def PostOrder(root): if root is None: return PostOrder( root.Left() ) PostOrder( root.Right() ) root.Action() The action to take when a node is visited. Pre, In and Post refer to when you visit the root (parent) node: Pre = First In = Middle Post = Last
  • 39. Binary Tree Max/Min Depth • Binary Tree – Maximum/Minimum depth algorithm 1. Do a preorder traversal of the tree starting from the root. 2. When a node is visited, increment the depth count by 1. 3. Recursively apply the algorithm to the left and right nodes. 4. When returning from a child to a parent node, pass back the node depth of the child. 5. Return the maximum and minimum depth from the left and right child (or the parent if there are no children). A B C D E Left Left Root Right Right depth = 3 depth = 3 max = 3, min = 3 max =2, min = 2 max = 3, min = 2
  • 40. Binary Tree Maximum Depth class BinaryTree(object): # Maximum/Minimum depth of a binary tree def MaxMinDepth( self, max ): max += 1 # Increment by one level for the node # Initialize the left and right branch max/min depth to the current max depth lmax = lmin = max rmax = rmin = max # Calculate the maximum depth along the left binary subtree if self.Left() is not None: lmax, lmin = self.Left().MaxMinDepth( max ) # Calculate the maximum depth along the left binary subtree if self.Right() is not None: rmax , rmin = self.Right().MaxMinDepth( max ) # return the greater (max) and lessor (min) of the left and right subtrees return ( rmax if rmax > lmax else lmax ), ( rmin if rmin < lmin else lmin ) Ternary conditional operator: true_clause if condition else false_clause Visited the root first. Return max and min as a list Can assign multiple values on LHS when list is returned.
  • 41. Binary Tree Max/Min Value • Binary Tree – Maximum/Minimum depth algorithm 1. Use either BFS or DFS/postorder traversal 2. Postorder: Recursively apply the algorithm to the left and right nodes. 3. When returning from a child to a parent node, pass back the max/min of the child. 4. Return the maximum or minimum value from the left and right child and parent. 5 4 3 5 8 Left Left Root Right Right max = 5, min = 5 max = 8, min = 8 max = 8, min = 4 max = 5, min = 3 max = 8, min = 3
  • 42. Binary Tree Max/Min Value class BinaryTree(object): # Maximum/Minimum of a binary tree def MaxMinValue( self ): # Initialize the left and right branch max/min values to +/- infinity lmax = rmax = -2147483647 lmin = rmin = 2147483648 # Calculate the maximum depth along the left binary subtree if self.Left() is not None: lmax, lmin = self.Left().MaxMinValue( ) # Calculate the maximum depth along the left binary subtree if self.Right() is not None: rmax , rmin = self.Right().MaxMinValue( ) # Compare max/min of child with parent if rmax < self.Value(): rmax = self.Value() if rmin > self.Value(): rmin = self.Value() # return the greater (max) and lessor (min) of the left and right subtrees return ( rmax if rmax > lmax else lmax ), ( rmin if rmin < lmin else lmin ) Visited the root last
  • 43. Coding Challenge • Python Language Constructs Covered: 1. Ternary Conditional operator 2. Local Variables 3. elif statement 4. Removing Links Binary Search Tree
  • 44. Binary Search Tree - Insert • Binary Search Tree – Insert algorithm 1. A sorted tree where at each node, the data value of the left branch (child) is less than the data value of the node, and the right node is greater than, and where there are no duplicate values. 1. Insert: if the root is null (None), add it as the root; otherwise, traverse the tree. 2. If the value is less than the node (branch), traverse left; otherwise traverse right. 3. If there is no node (branch) to traverse, then add it as a new node. 6 4 8 2 5 Left Left Root Right Right 7 Left 7 Insert 7 > 6, go right 7 < 8, go left No node, insert
  • 45. Binary Search Tree - Insert class BinarySearchTree(object): root = None # root of the search tree # Insert a node into a binary search tree def Insert( self, node ): # If tree is empty, make the root the first node if self.root is None: self.root = node return # Follow a path to insert the node curr = self.root while True: # if value is less than node, traverse left branch if node.value < curr.value: # if no left branch, set node as left branch if curr.Left() is None: curr.Left( node ) return curr = curr.Left() # otherwise, traverse right branch : elif curr.Right() is None: curr.Right( node ) return else: curr = curr.Right() Local variable, created on first use. Loop forever Format of: else if statement Add code here to check for duplicate
  • 46. Binary Search Tree - Find • Binary Search Tree – Find algorithm 1. If the root is null (None), return None. 2. If value is equal to the node, return the node. 3. If the value is less than the node (branch), traverse left; otherwise traverse right. 4. If there is no node (branch) to traverse, then return None. 6 4 8 2 5 Left Left Root Right Right 7 Left Find value = 7 7 > 6, go right 7 < 8, go left Node Found
  • 47. Binary Search Tree - Find class BinarySearchTree(object): root = None # root of the search tree # Find a node into a binary search tree def Find( self, value ): # If tree is empty, return None if self.root is None: return None # Follow a path to find the node curr = self.root while True: # Node Found if curr.value == value: return curr # if value is less than node, traverse left branch if value < curr.value: # if no left branch, return not found if curr.Left() is None: return None curr = curr.Left() # otherwise, traverse right branch : elif curr.Right() is None: return None else: curr = curr.Right()
  • 48. Binary Search Tree - Delete • Binary Search Tree – Delete algorithm 1. If the root is null (None), return. 2. While remembering the parent node, If the value is less than the node (branch), traverse left; otherwise traverse right. 3. If the value equals the node value, set the parent left branch to null if left branch; Otherwise set parent right branch to null. 4. Reinsert the left and right branches of the removed node. 6 4 8 2 5 Left Left Root Right Right 7 Left Remove value = 8 7 > 6, go right Parent = 6 Remove Link 6 4 2 5 Left Left Right Right 7 Reinserted Node
  • 49. Binary Search Tree - Delete class BinarySearchTree(object): root = None # root of the search tree # Find a node into a binary search tree def Delete( self, value ): # If tree is empty, return None if self.root is None: return None # Follow a path to find the node to delete curr = self.root prev = self.root while True: # Node Found if curr.value == value: if left == True: # delete the left branch of the parent prev.left = None else: # delete the right branch of the parent prev.right = None if curr.Left(): # re-insert left branch of deleted node self.Insert( curr.left ) if curr.Right(): # re-insert right branch of delete node self.Insert( curr.right ) return # if value is less than node, traverse left branch if value < curr.value: # if no left branch, return not found if curr.Left() is None: return None curr = curr.Left() left = True # traversed left branch # otherwise, traverse right branch : elif curr.Right() is None: return None else: curr = curr.Right() left = False # traversed right branch
  • 50. Coding Challenge • Python Language Constructs Covered: 1. Recap Arithmetic Emulation
  • 51. Arithmetic - Multiply • Algorithm to implement multiply with only addition and equality operator. 1. Initialize accumulators for result and repeat to 0. 2. Loop indefinitely for ‘x * y’ 1. If repeat accumulator equals zero, stop. 2. Increment the repeat accumulator by one. 3. Add x to the result. Repeaty -> y > 0 result No Yes y-- result += x
  • 52. Arithmetic - Multiply def Mul( x, y ): # multiple by a negative number if y < 0: y = -y # turn y into positive number for loop increment x = -x # turn x into negative number for result accumulator # repeat adding x to result y times result = 0 for i in range( 0, y ): result += x return result
  • 53. Arithmetic - Exponent • Algorithm to implement exponent with only addition and equality operator. 1. If the exponent is zero, return 1. 2. Initialize accumulators for result and repeat to 0. 3. Loop indefinitely for 'x power e‘ 1. If repeat accumulator equals zero, stop. 2. Increment the repeat accumulator by one. 3. Update the result to Mul( result, x ). Repeaty ->, result = 1 y > 0 result No Yes y-- result = Mul(result, x)
  • 54. Arithmetic - Exponent def Exp( x, y ): # initialize result to 1 result = 1 # repeat multiplying result by x, y times for i in range( 0, y ): result = Mul( result, x ) return result Does not handle negative exponents.
  • 55. GCD – Iterative Solution • Euclid’s Algorithm for Greatest Common Denominator 1. Calculate the remainder of dividing the 2nd number by the first number (y % x). 2. Swap the value of the first number (x) with the second number (y). 3. Set the second number (y) to the remainder. 4. Iteratively repeat the process until the 2nd number (y) is zero. 5. Return the value of first number (x) when the 2nd number is zero (y). Repeatx, y -> y > 0 x No rem = y % x x = y; y = rem Yes
  • 56. Arithmetic – GCD Iterative def GCD( x, y ): # continue until the division of of the two numbers does not leave a remainder (evenly divisible) while y > 0: # calculate the remainder of the division by between x and y remainder = ( y % x ) # swap the value of x with y x = y # set y to the remainder y = remainder return x
  • 57. GCD – Recursive Solution • Euclid’s Algorithm for Greatest Common Denominator 1. When the 2nd number (y) is reduced to zero, return the current value of the first number (x). 2. Otherwise, swap the first number (x) with the second number (y) and set the 2nd number (y) to the remainder of the division of the 2nd number by the first number (x % y). 3. Recursively call GCD() with the updated first and second numbers. GCDx, y -> y > 0 x No Yes rem = y % x x = y; y = rem Call GCD(x, y)
  • 58. Arithmetic – GCD Recursive def GCDR( x, y ): # return the current value of x when y is reduced to zero. if y == 0: return x # recursive call, swapping x with y, and setting y to remainder of y divided by x return GCDR( y, ( y % x ) )
  • 59. LCM • Euclid’s Algorithm for Least Common Multiple 1. Multiple the first and second number. 2. Divide the result by the GCD of the two numbers. LCMx, y -> x mul = x * y Result = mul / GCD(x,y)
  • 60. Arithmetic – LCM def LCM( x, y ): return ( x / y ) / GCD( x, y )
  • 61. Coding Challenge • Python Language Constructs Covered: 1. Bubble Sort 2. Swapping 3. Logical Operators Sorting
  • 62. Bubble Sort • Bubble Sort Algorithm 1. Make a pass through the list of values. • Compare adjacent values. • If the first value is less than the second value, swap the values. 2. If one of more values were swapped, repeat the process of making a pass through the list. 4 2 1 3 Forward Scan 2 4 1 3 2 1 4 3 2 1 3 4 2 1 3 4 1 2 3 4 Repeat Cycle 1 2 3 4 1 2 3 4
  • 63. Bubble Sort def BubbleSort( data ): length = len( data ) swapped = True # continue to repeat until no more adjacent values are swapped while swapped: swapped = False # Make a scan through the list for i in range( 0, length - 1 ): # Compare adjacent values. If the first value > second value, swap the values. if data[ i ] > data[ i + 1 ]: swap = data[ i ] data[ i ] = data[ i + 1 ] data[ i + 1 ] = swap swapped = True return data Since we are comparing index with index + 1, we stop one entry short of the end of the array. Swap: 1. save the first element in a temporary variable. 2. Set the first element to the value of the second element. 3. Set the second element to the value of the temporary variable (which was the former value of first element). Space Complexity: O(1) – except for swap variable, no extra space needed Time Complexity : O(n2) – n is number of elements, n scans * n elements.
  • 64. Coding Challenge • Python Language Constructs Covered: 1. Insertion, Quick and Merge Sorts 2. Array Scans 3. Swapping 4. Logical Operators 5. Complexity Sorting
  • 65. Insertion Sort • Insertion Sort Algorithm 1. Iterate through the list of elements. • Scan through the list one element at a time. • From current element, move backwards to the beginning, swapping adjacent elements when not sorted. 4 3 2 1 Forward Scan 3 4 2 1 2 3 4 1 1 2 3 4 3 2 4 1Move Backwards 2 3 1 4 2 1 3 4
  • 66. Insertion Sort def InsertionSort( data ): length = len( data ) # iterate through the list for each element except the first element for i in range( 1, length ): # starting with the current element, remove/insert proceeding # elements so they are in sorted order for j in range( i, 0, -1): # swap adjacent elements if data[ j ] < data[ j - 1 ]: temp = data[ j ] data[ j ] = data[ j -1 ] data[ j - 1 ] = temp return data Start at position 1, not 0 – nothing to swap with at first element. Space Complexity: O(1) – except for swap variable, no extra space needed Time Complexity : O(n2) – n is number of elements, n scans * n elements. Descending count in for loop. Loop from ‘n’ to 0 in -1 (descend) steps.
  • 67. Quick Sort • Quick Sort Algorithm 1. Calculate a midpoint in the list. The value at the midpoint is the pivot value. 2. Move all values in the first partition that are not less than the pivot to the second partition. 3. Move all values in the second partition that are not greater than or equal to the pivot to the first partition. 4. Recursively apply the algorithm to the two partitions. 3 2 4 5 18 67 3 21 5 8 674 21 3 4 65 7 8
  • 68. Quick Sort def QuickSort( data ): qSort( data, 0, len( data ) - 1 ) return data def qSort( data, low, high ): i = low # starting lower index j = high # starting higher index mid = int( low + ( high - low ) / 2 ) # midway index pivot = data[ mid ] # pivot, value at the midway index # Divide the array into two partitions while i <= j: # keep advancing (ascending) the lower index until we find a value that is not less than the pivot # we will move this value to the right half partition. while data[ i ] < pivot: i += 1 # keep advancing (descending) the higher index until we find a value that is not greater than the pivot # we will move this value to the left half partition. while data[ j ] > pivot: j -= 1 # if the lower index has past the higher index, there is no values to swap # otherwise, swap the values and continue if i <= j: # swap the higher than pivot value on the left side with the lower than pivot value on the right side temp = data[ i ] data[ i ] = data[ j ] data[ j ] = temp # advance the lower and higher indexes accordingly and continue i += 1 j -= 1 # recursively sort the two partitions if the index has not crossed over the pivot index if low < j: qSort( data, low, j ) if i < high: qSort( data, i, high )
  • 69. Merge Sort • Merge Sort Algorithm 1. Allocate space for a temporary copy of the array. 2. Recursively split the data into two partitions (halves), until each partition is a single element. 3. Merge and sort each pair of partitions. 2 3 4 5 61 87 3 42 1 5 768 83 2 4 51 6 7 Split into halves 38 2 4 15 7 6 Merge halves and sort
  • 70. Merge Sort def MergeSort( data ): # allocate space for a temporary copy of the data tdata = [ 0 ] * len( data ); # sort the data (pass in the temporary copy so routine is thread safe) mSort( data, 0, len( data ) - 1, tdata ) return data def mSort( data, low, high, tdata ): # if the partition has more than one element, then recursively divide the partition and merge the parts back in if low < high: mid = int( low + ( high - low ) / 2 ) # midway index # sort the lower (first) half partition mSort( data, low, mid, tdata ) # sort the upper (second) half partition mSort( data, mid + 1, high, tdata ) # merge the partitions together merge( data, low, mid, high, tdata ) def merge( data, low, mid, high, tdata ): # make a temporary copy of the two separately sorted partitions for i in range( low, high + 1 ): tdata[ i ] = data[ i ] # starting from the beginning of the first partition, iteratively search for the next lowest # number from the lower (first) and higher (second) and move into current position in the # lower (first) partition i = low k = low j = mid + 1 while i <= mid and j <= high: if tdata[ i ] <= tdata[ j ]: data[ k ] = tdata[ i ] i += 1 else: data[ k ] = tdata[ j ] j += 1 k += 1 # Copy any remaining elements back into the first partition while i <= mid: data[ k ] = tdata[ i ] k += 1 i += 1 Logical operators are the keywords: and or
  • 71. Quick / Sort Merge - Complexity • Merge Space Complexity: O(n) Time Complexity : O(n * logn) • Quick Space Complexity: O(n) Time Complexity : O(n * logn)
  • 72. Coding Challenge • Python Language Constructs Covered: 1. Modulo Operator 2. Squashing into a range 3. Collision Handling 4. Complexity Hashing
  • 73. Hashing • Hashing is used to solve indexing lookups without the overhead of sequential scanning and name comparisons. The most basic use of hashing is insertion and lookup in a key-value(s) dictionary. • Common Issues: 1. Handling of collisions when two keys mapped to the same index. 2. Efficiency of the hashing algorithm. 3. The frequency of collisions. 4. The sparseness of the memory allocated for the index.
  • 74. Integer Hash • Integer Hash Algorithm 1. Map each integer value into a smaller fixed size integer range using the modulo operator. 2. If there is no entry at the index, add the key/value to the index as the first entry in the chain. 3. If there are entries there, and the key is the same as one of the entries (duplicate), update the value. 4. If there are entries there, and the key is not the same (collision) as any entry, add the key to the chain of entries. 0 1 2 3 4 n *** Range None (no entry at index) A A B Single Entry (no collision) Chain of Entries (collisions) Index = (key % range)
  • 75. Integer Hash (part 1) class Hash( object ): RANGE = 0 # the range of the index. index = [] # the index # constructor def __init__( self, range ): # set the index range and allocate the index self.RANGE = range self.index = [None] * self.RANGE # Map the key into an index within the set range def Index( self, key ): return key % self.RANGE Module operator, returns the remainder of an integer division.
  • 76. Integer Hash (part 2) class Hash( object ): # Add a key/value entry to the index def Add( self, key, value ): ix = self.Index( key ) # there is no entry at this index, add the key/value if self.index[ ix ] is None: self.index[ ix ] = Entry( key, value ) else: # See if the key already exists in the chain next = self.index[ ix ] while next is not None: # Entry found, update the value if next.Compare( key ): next.Value( value ) break next = next.Next() # no entry found, add one if next is None: # Add the entry to the front of the chain add = Entry( key, value ) add.Next( self.index[ ix ] ) self.index[ ix ] = add Class specific implementation Of comparing two keys.
  • 77. Integer Hash (part 3) class Hash( object ): # Get the value for the key def Get( self, key ): ix = self.Index( key ) # See if the key exists in the chain at this entry in the index next = self.index[ ix ] while next is not None: # Entry found, update the value if next.Compare( key ): return next.Value() next = next.Next() # not found return None Time Complexity : O(1) – no collisions (sparse) O(n) – collisions
  • 78. String (Object) Hash • String (Object) Hash Algorithm 1. Convert the key to an integer value, which then can be divided by the range to get the remainder (modulo). 2. In Python, the equivalent is the builtin function hash(). 0 1 2 3 4 n *** Range None (no entry at index) A A B Single Entry (no collision) Chain of Entries (collisions) Index = hash( value ) “my name”
  • 79. Hash Table with Linear Probing • A hash table without linked lists and instead handle collisions with linear probing. In this case, we assume that the size of the table will be greater than or equal to the number of keys. 1. Map each value into a fixed size integer range using a hash function. 2. If there is no entry at the index, add the key/value to the index. 3. If there is an entry and the key matches the entry (duplicate), then update the value. 4. If there is an entry and the key does not match the entry, then probe downward in a linear fashion. • If the entry is empty, add the key/value pair to the entry. • If a key matches (duplicate), then update the entry. • If the key does not match, continue to the next entry. 100 (index = ) 202 (index = 2) 302 (index = 2) n *** Range (e.g., 100) Probe, 302 collides with 202 (index = 2)
  • 80. Hash Table with Linear Probing class HashLP( object ): # Add a key/value entry to the index def Add( self, key, value ): # Linear probe the entries for an empty or matching slot. for ix in range( self.Index( key ), self.RANGE ): # there is no entry at this index, add the key/value if self.index[ ix ] is None: self.index[ ix ] = Entry( key, value ) break # Entry found, update the value if self.index[ ix ].Compare( key ): self.index[ ix ].Value( value ) break # Get the value for the key def Get( self, key ): ix = self.Index( key ) # Linear probe the entries for an empty or matching slot. for ix in range( self.Index( key ), self.RANGE ): # there is no entry at this index, return not found if self.index[ ix ] is None: return None # Entry found if self.index[ ix ].Compare( key ): return self.index[ ix ].Value(); # not found return None
  • 81. Coding Challenge • Python Language Constructs Covered: 1. Ord() builtin function 2. Bitwise-Mask String Manipulation
  • 82. Reverse String • Reverse String - Iterative 1. Create a StringBuffer (or character array) to hold the reversed string. 2. Starting at the end of the string and moving backwards, append each character to the reversed string. • Reverse String – Recursive 1. If the original string is one character, if so then return the string. 2. Otherwise, break the string into two parts: the first character and the remainder of the string. 3. Make a recursive call with the remaining string and append the first character to the return from the call. S t r i n g g n i r t S Backward Scan Forward Copy Copy Buffer Original Iterative
  • 83. Reverse String def ReverseString( original ): reversed = “” # copy for reversed string length = len( original ) # length of original string for ix in range( length-1, -1, -1 ): reversed += original[ ix ] return reversed Iterative def ReverseStringR( original ): if len( original ) > 1: return ReverseStringR( original[1:] ) + original[ 0 ] return original Recursive
  • 84. Palindrome - Word • Palindrome - the same word/phrase spelled forward or backwards, such as: madam, civic, racecar. • Solution without making a copy of the string. 1. Iterate through the first half of the string. When the string is an odd number of characters, skip the middle character. 2. On each iteration, compare the current character at the front of the string to the same position but from the rear of the string. 3. If they do not much, it is not a palindrome. r a c e c a Backward ScanForward Scan middle r
  • 85. Palindrome - Phrase • Solve the same for phrases, regardless of the positioning of spaces, punctuation and capitalizing, such as: My gym. • Solution without making a copy of the string. 1. Iterate simultaneously from the front (forward) and back (backward) of the string, until the two iterators meet. 2. If current character of either iterator is a punctuation or space character, then advance the corresponding iterator. 3. Otherwise, if the lowercase value of the current character from both iterators do not equal, then it is not a palindrome. 4. Advance both iterators and repeat. M y g y m Backward ScanForward Scan middle . m
  • 86. Palindrome def Palindrome( s ): length = len( s ) for i in range( 0, int( length / 2 ) ): if s[ i ] != s[ length - i - 1 ]: return False return True def PalindromeP( s ): length = len( s ) i = 0 j = length - 1 while i < j: if isPunctOrSpace( s[ i ] ): i += 1 continue if isPunctOrSpace( s[ j ] ): j -= 1 continue if s[ i ].lower() != s[ j ].lower(): return False i += 1 if j != i: j -= 1 return True Word Phrase Calculate the reverse (backward) distance Builtin string routine to lowercase a character.
  • 87. Character Count • Count all occurrences of every character in a string. 1. Create a counter for the 96 ASCII printable characters. 2. Iterate through the string, incrementing the character specific index in the counter for each character. r a c e c a Forward Scan r Counter
  • 88. Duplicate Character Count • Count all occurrences of duplicate characters in a string. 1. Make a pass over the string to generate a character count index. 2. Make a pass over the character count index using a bitwise mask to mask out single character occurrences (leaving only duplicates with non-zero values). r a c e c a Forward Scan r a=2 c=2 e=1b=0 d=0 r=2*** Counter a=1 c=1 e=0b=0 d=0 r=1*** Mask &= ~0x01 Duplicates: Non-Zero value
  • 89. Character and Duplicate Counts def CharOccur( s ): counter = [0] * 96 # codes 32 .. 127 are printable (so skip first 32) length = len(s) # use counter as an accumulator while we count each character in string for i in range( 0, length): counter[ ord( s[ i ] ) - 32 ] += 1 # offset ascii code by 32 return counter Character Count Builtin function that returns the ASCII value of the character. def DupChar( s ): # Get the character occurrences dup = CharOccur( s ) # Mask out all single count occurrences length = len( dup ) for i in range( 0, length): dup[ i ] &= ~0x01; return dup Duplicate Count A mask is the complement (inverse) of the value to remove