Stacks and optimization - example from hackerrank - python

I have a question concerning stacks in Python. I tried to solve a Maximum Element task in Hackerrank:
You have an empty sequence, and you will be given N queries. Each query
is one of these three types:
1 x -Push the element x into the stack.
2 -Delete the element present at the top of the stack.
3 -Print the maximum element in the stack.
The first line of input contains an integer, N. The next N lines each
contain an above mentioned query. (It is guaranteed that each query is
valid.)
To solve it I wrote something like this:
class Stack:
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def maxEl(self):
return max(self.items)
s = Stack()
for i in range(int(input())):
n = input().split()
if n[0] == '1':
s.push(int(n[1]))
elif n[0] == '2':
s.pop()
else:
print(s.maxEl())
It works, but too slow apparently and I pass only 18 out of 28 testcases (because of timeout). I have found a similar solution, and it is fast enough, but I don't understand why:
class Stack:
def __init__(self):
self.arr = [0]
self.max = [0]
def push(self, data):
self.arr.append(data)
if self.max[-1] <= data:
self.max.append(data)
def pop(self):
if self.arr[-1] == self.max[-1]:
self.max.pop()
self.arr.pop()
N = int(input())
s = Stack()
for _ in range(N):
x = str(input())
if x[0] == '1':
s.push(int(x[2:]))
elif x[0] == '2':
s.pop()
else:
print(s.max[-1])
Can somebody explain me why my code isn't performing well? Thank you.

The two solutions are pretty similar, except for the code that returns the maximum element in the stack.
In your solution you use the max() function:
def maxEl(self):
return max(self.items)
This runs in O(n) time, since max() must check every element in the worst case.
In the other solution maximum values are stored in yet another stack, so getting the current maximum value is just an index operation, which runs in O(1) time:
s.max[-1]
There's also some cost associated with updating the stack of maximums on each push/pop, but those operations are still constant time.

Given the definition of the problem even the working solution is doing way too much. More specifically you need to remember ONLY the max in the stack; something like
s = []
for _ in range(N):
x = str(input())
if x[0] == '1':
v = int(x[2:])
s.append(v if len(s) == 0 else max(v, s[-1]))
elif x[0] == '2':
s.pop()
else:
print(s[-1])
should be sufficient.

Related

how to Find the largest element in a list using recursion python?

i = 0
def find_max(seq):
if i == len(seq) - 1:
return seq[0]
else:
first = seq[i]
i = i + 1
max_of_rest = find_max(seq)
return max(first, max_of_rest)
I do not know what is wrong with this function? It is a infinite loop.
Please check out the following solution and follow comments:
def find_biggest(_list, max_element, first_run):
"""
_list is a list of floats or integers or both,
max element is used to store max value,
first run checks if _list is not empty
"""
if first_run and not _list: # check if _list is not empty
raise ValueError("_list should have float or integer values inside")
first_run = False
if not _list: # exit from recursion, we checked all elements
return max_element
element = _list.pop() # take one element
if type(element) not in (int, float,): # check element type
raise TypeError("_list should contain only int or float values")
if element >= max_element: # check if it is more than max
max_element = element
return find_biggest(_list, max_element, first_run) # next step of recursion
if __name__ == "__main__":
# test
print(find_biggest([-1, 4, 2, 3, 1, 0, 10, 3, 1, 7], 0, True))
# print(find_biggest([], 0, True)) # empty case
# print(find_biggest([-1, 4, 2, 3, "1", 0, 10, 3, 1, 7], 0, True)) # string in list
You can check this:
def find_max(seq):
if len(seq) == 1:
return seq[0]
else:
if seq[0] > seq[1]:
seq.pop(1)
else:
seq.pop(0)
return find_max(seq)
Your code has a lot of indentation issues, that may skip execution of some lines.
Your code should look like this:
i = 0
def find_max(seq):
global i
if i == len(seq) - 1:
return seq[0]
else:
first = seq[i]
i = i + 1
max_of_rest = find_max(seq)
return max(first, max_of_rest)
You missed the global, and thus there is no definition of i inside the function.
Your code contains an IndentationError and does not reduce its data on recursive calls - hence data never getting shorter - hence never ending recursion:
def find_max(seq):
if i == len(seq) - 1: # fixed indentation here and below
return seq[0]
else:
first = seq[i]
i = i + 1
max_of_rest = find_max(seq) # never reducing your data size, hence endless
return max(first, max_of_rest)
This would be a fixed recursive solution:
def find_max(seq):
if not seq:
return None # or raise ValueError if you want find_max([]) to crash
if len(seq) == 1:
return seq[0]
else:
return max(seq[0], find_max(seq[1:]))
The problem is inheritently bad for recursive solutions, it is far better to solve it linearly (no max(..) calls needed):
def find_max_lin(seq):
if not seq:
return None
m = seq[0]
for value in seq[1:]:
m = m if value < m else value
return m
or even better simply use the built in max(sequence):
def find_max_builtin(seq):
# no need to create your own function for that though
return max(seq)
See ternary operator for an explanation of what m = m if value < m else value does.
You are using uneeded i variable, in recursion you have base case (your first if), and recursion case, which in this case would be accessing first and second element of your list. As you already checked that the list seq has more than 1 element, you can confidently access positions 0 and 1 of the list.
In your specific case, you are not really using recursion because you never reduce your case, but instead you increment an i variable, whilst recursion is based on always calling the same function with a "simpler" or reduced problem.
With that in mind, several things can be improved in your solution.
i = 0 # Not adviced
def find_max(seq):
# Here you want to check length, making it
# depend on i = problems
if i == len(seq) - 1:
return seq[0]
else:
first = seq[i] # Remove all references to i
i = i + 1 # Remove
# Here you want to call the function with the list
# except the element you know is lower, making the problem
# smaller until you get to the base case
# Instead you are calling find_max with the same
# sequence you had (infinite loop) and returning a
# totally different result.
max_of_rest = find_max(seq)
return max(first, max_of_rest)
A complete solution based on your code would look like this
def find_max(seq):
if len(seq) == 0:
return None
if len(seq) <= 1:
return seq[0]
else:
current_max = max(seq[0], seq[1])
reduced_seq = [current_max] + seq[2:]
return find_max(reduced_seq)
i = 0
def find_max(seq):
global i
if i == len(seq) :
return seq[0]
else:
first = seq[i]
i = i + 1
max_of_rest = find_max(seq)
return max(first, max_of_rest)
print(find_max([-10,2,4,-5]))
thank me later

Anybody know how to use pyresttest's 'fixed_sequence' generator?

I'm trying to use pyresttest's benchmarking framework to generate a sequence of entries in my flask_sqlalchemy-based database. I would like to read input values from a pre-defined list as advertised by this framework's benchmarking generator type 'fixed_sequence', but it's only picking up the first element of the list.
Here is the issue that explains my problem in detail, with an example: https://github.com/svanoort/pyresttest/issues/264
Any pointer in the right direction will be greatly appreciated
I looked into the code, it is jsut a bug, this feature was never used by anyone.
https://github.com/svanoort/pyresttest/blob/master/pyresttest/generators.py#L100
instead of:
```
def factory_fixed_sequence(values):
""" Return a generator that runs through a list of values in order, looping after end """
def seq_generator():
my_list = list(values)
i = 0
while(True):
yield my_list[i]
if i == len(my_list):
i = 0
return seq_generator
It should be:
def factory_fixed_sequence(values):
""" Return a generator that runs through a list of values in order, looping after end """
def seq_generator():
my_list = list(values)
i = 0
while(True):
yield my_list[i]
i += 1
if i == len(my_list):
i = 0
return seq_generator
```
The i += 1 is missing

Python binary search recursive if possible

class SortedList:
theList = []
def add(self, number):
self.theList.append(number)
return self.theList
def remove(self, number):
self.theList.remove(number)
return self.theList
def printList(self):
return print(self.theList)
def binarSearch(self, number):
middle = (len(self.theList)//2)
end = len(self.theList)
if end != 0:
if int(self.theList[middle]) == int(number):
return print("The number is found in the list at place",middle+1)
elif int(self.theList[middle]) < int(number):
self.theList = self.theList[middle:]
return self.binarSearch(number)
elif int(self.theList[middle]) > int(number):
self.theList = self.theList[:middle]
return self.binarSearch(number)
else:
return print("The list is empty")
sorted = SortedList() #create a SortedList object
sorted.add("1")
sorted.add("2")
sorted.add("3")
sorted.add("4")
sorted.add("5")
sorted.add("6")
sorted.printList()
sorted.binarSearch(3)
I cannot use additional parameters I mut use only self and number. I want to make it recursive but if it is hard you can answer as normal.
This code works good until the number 4. When I give 4 for searching it says it is in place 2 and it continues saying two after 4. I have tried adding other numbers but it is same
Python already has a great module bisect which performs a binary search for sorted lists:
import bisect
l = [2,3,1,5,6,7,9,8,4]
print(bisect.bisect(l, 4)) # Output: 3
Familiarize yourself with this library:
https://docs.python.org/3.5/library/bisect.html
Just a hint: You can use additional parameters if you give them default values. Your method signature would look like this:
def binarSearch(self, number, start=0, end=len(self.theList)):
So it could still be called like sorted.binarySearch(5) but would internally be able to pass the state correctly.

Creating chains that loop on themselves

I want to have a number that breaks into 2 other numbers and checks for end conditions, breaking off each number until the conditions are met.
I came up with the following example to try to figure it out. Take a number, and break it into 2 more numbers: one is the original number multiplied by 2 and the other number is the original number divided by 3 without a remainder (//). This continues until a number is either greater than 100, equal to 6, or a square.
I want to record every chain that is made to be returned and printed out at the end. I can only do this by checking the second number in a chain currently and am not clever enough to figure out how to check both numbers. I want a new chain to be created every time the number is broken into 2 new numbers.
Currently, here is what I have:
import numpy as np
def check_conditions(number):
if number > 100:
return False
if number == 6:
return False
if np.sqrt(number) % 1 == 0:
return False
return True
def find_decay(number):
'''
Rule: Number is broken into two chains. First chain is
mulitplied by 2. Seconds chain is // 3. Same thing happens
to both chains unless end condition is met:
1. number is greater than 100
2. number is equal to 6
3. number is a perfect square
'''
master_chain = []
while check_conditions(number):
new_chain1 = [number * 2]
master_chain.append(new_chain1)
new_chain2 = [number // 3]
master_chain.append(new_chain2)
number = new_chain2[-1]
return master_chain
if __name__ == '__main__':
print find_decay(int(raw_input('Number: ')))
Does anyone have any ideas of ways to check conditions in a while loop for 2 separate numbers like?
This sort of problem typically lends itself to trees and/or recursion. However, the rate at which you're spawning new work is quite high compared to the rate at which you're going to satisfy the conditions. (ie while it won't take too many operations to exceed 100 for one product of each value, but low chances of finding a perfect square or exactly 6 on either fork)
Therefore, you'll want to set a max recursion depth for your implementation else you'll come up against the interpreter's limit (sys.getrecursionlimit()) and fail ugly.
I've provided a simple example of how you might do it below, recursively building a tree.
This is not particularly efficient though, and if you are interested in very long 'chains' then you may need to consider addressing this another way.
import sys
import numpy as np
class Node(object):
def __init__(self,number,parent):
self._parent = parent
self._number = number
self._satisfied = number > 100 or number == 6 or np.sqrt(number) % 1 == 0
self._left = None
self._right = None
self._depth = parent.depth + 1 if parent != None else 1
#property
def parent(self):
return self._parent
#property
def number(self):
return self._number
#property
def satisfied(self):
return self._satisfied
#property
def depth(self):
return self._depth
#property
def left(self):
return self._left
#left.setter
def left(self,value):
self._left = value
#property
def right(self):
return self._right
#right.setter
def right(self,value):
self._right = value
def print_all_chains(node,chain=[]):
if node.left is None:
chain.append(node.number)
print '{0}: {1}'.format(node.satisfied, chain)
else:
print_all_chains(node.left, chain[:] + [node.number])
print_all_chains(node.right, chain[:] + [node.number])
def build_tree(node, maxDepth):
if not node.satisfied and node.depth<maxDepth:
node.left = Node(node.number*2, node)
build_tree(node.left,maxDepth)
node.right = Node(node.number//3, node)
build_tree(node.right,maxDepth)
def find_decay(number):
root = Node(number,None)
build_tree(root,maxDepth=10)
print_all_chains(root)
if __name__ == '__main__':
find_decay(int(raw_input('Number: ')))
Using a simple Node class, this can give you an idea of the tree structure. This traverses the tree in level-order (which guarantees to find the shortest chain):
from collections import deque
import numpy as np
def check_conditions(number):
return number > 100 or number == 6 or np.sqrt(number) % 1 == 0
class Node():
def __init__(self, value, parent=None):
self.value, self.parent = value, parent
def chain(self):
node = self
while node:
yield node.value
node = node.parent
def find_decay(number):
agenda = deque([Node(number)])
while agenda:
node = agenda.popleft() # use pop() for depth-first
num = node.value
if check_conditions(num):
return list(node.chain())
agenda.append(Node(num//3, parent=node))
agenda.append(Node(num*2, parent=node))
if __name__ == '__main__':
for x in find_decay(int(raw_input('Number: '))):
print x,
37: 37 12 4

Count the number of times an item occurs in a sequence using recursion Python

I'm trying to count the number of times an item occurs in a sequence whether it's a list of numbers or a string, it works fine for numbers but i get an error when trying to find a letter like "i" in a string:
def Count(f,s):
if s == []:
return 0
while len(s) != 0:
if f == s[0]:
return 1 + Count(f,s[1:])
else:
return 0 + Count(f,s[1:])
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
There's a far more idiomatic way to do it than using recursion: use the built-in count method to count occurrences.
def count(str, item):
return str.count(item)
>>> count("122333444455555", "4")
4
However, if you want to do it with iteration, you can apply a similar principle. Convert it to a list, then iterate over the list.
def count(str, item):
count = 0
for character in list(str):
if character == item:
count += 1
return count
The problem is your first if, which explicitly checks if the input is an empty list:
if s == []:
return 0
If you want it to work with strs and lists you should simply use:
if not s:
return s
In short any empty sequence is considered false according to the truth value testing in Python and any not-empty sequence is considered true. If you want to know more about it I added a link to the relevant documentation.
You can also omit the while loop here because it's unnecessary because it will always return in the first iteration and therefore leave the loop.
So the result would be something along these lines:
def count(f, s):
if not s:
return 0
elif f == s[0]:
return 1 + count(f, s[1:])
else:
return 0 + count(f, s[1:])
Example:
>>> count('i', 'what is it')
2
In case you're not only interested in making it work but also interested in making it better there are several possibilities.
Booleans subclass from integers
In Python booleans are just integers, so they behave like integers when you do arithmetic:
>>> True + 0
1
>>> True + 1
2
>>> False + 0
0
>>> False + 1
1
So you can easily inline the if else:
def count(f, s):
if not s:
return 0
return (f == s[0]) + count(f, s[1:])
Because f == s[0] returns True (which behaves like a 1) if they are equal or False (behaves like a 0) if they aren't. The parenthesis are not necessary but I added them for clarity. And because the base case always returns an integer this function itself will always return an integer.
Avoiding copies in the recursive approach
Your approach will create a lot of copies of the input because of the:
s[1:]
This creates a shallow copy of the whole list (or string, ...) except for the first element. That means you actually have an operation that uses O(n) (where n is the number of elements) time and memory in every function call and because you do this recursively the time and memory complexity will be O(n**2).
You can avoid these copies, for example, by passing the index in:
def _count_internal(needle, haystack, current_index):
length = len(haystack)
if current_index >= length:
return 0
found = haystack[current_index] == needle
return found + _count_internal(needle, haystack, current_index + 1)
def count(needle, haystack):
return _count_internal(needle, haystack, 0)
Because I needed to pass in the current index I added another function that takes the index (I assume you probably don't want the index to be passed in in your public function) but if you wanted you could make it an optional argument:
def count(needle, haystack, current_index=0):
length = len(haystack)
if current_index >= length:
return 0
return (haystack[current_index] == needle) + count(needle, haystack, current_index + 1)
However there is probably an even better way. You could convert the sequence to an iterator and use that internally, at the start of the function you pop the next element from the iterator and if there is no element you end the recursion, otherwise you compare the element and then recurse into the remaining iterator:
def count(needle, haystack):
# Convert it to an iterator, if it already
# is an (well-behaved) iterator this is a no-op.
haystack = iter(haystack)
# Try to get the next item from the iterator
try:
item = next(haystack)
except StopIteration:
# No element remained
return 0
return (item == needle) + count(needle, haystack)
Of course you could also use an internal method if you want to avoid the iter call overhead that is only necessary the first time the function is called. However that's a micro-optimization that may not result in noticeably faster execution:
def _count_internal(needle, haystack):
try:
item = next(haystack)
except StopIteration:
return 0
return (item == needle) + _count_internal(needle, haystack)
def count(needle, haystack):
return _count_internal(needle, iter(haystack))
Both of these approaches have the advantage that they don't use (much) additional memory and can avoid the copies. So it should be faster and take less memory.
However for long sequences you will run into problems because of the recursion. Python has a recursion-limit (which is adjustable but only to some extend):
>>> count('a', 'a'*10000)
---------------------------------------------------------------------------
RecursionError Traceback (most recent call last)
<ipython-input-9-098dac093433> in <module>()
----> 1 count('a', 'a'*10000)
<ipython-input-5-5eb7a3fe48e8> in count(needle, haystack)
11 else:
12 add = 0
---> 13 return add + count(needle, haystack)
... last 1 frames repeated, from the frame below ...
<ipython-input-5-5eb7a3fe48e8> in count(needle, haystack)
11 else:
12 add = 0
---> 13 return add + count(needle, haystack)
RecursionError: maximum recursion depth exceeded in comparison
Recursion using divide-and-conquer
There are ways to mitigate (you cannot solve the recursion depth problem as long as you use recursion) that problem. An approach used regularly is divide-and-conquer. It basically means you divide whatever sequence you have into 2 (sometimes more) parts and do call the function with each of these parts. The recursion sill ends when only one item remained:
def count(needle, haystack):
length = len(haystack)
# No item
if length == 0:
return 0
# Only one item remained
if length == 1:
# I used the long version here to avoid returning True/False for
# length-1 sequences
if needle == haystack[0]:
return 1
else:
return 0
# More than one item, split the sequence in
# two parts and recurse on each of them
mid = length // 2
return count(needle, haystack[:mid]) + count(needle, haystack[mid:])
The recursion depth now changed from n to log(n), which allows to make the call that previously failed:
>>> count('a', 'a'*10000)
10000
However because I used slicing it will again create lots of copies. Using iterators will be complicated (or impossible) because iterators don't have a size (generally) but it's easy to use indices:
def _count_internal(needle, haystack, start_index, end_index):
length = end_index - start_index
if length == 0:
return 0
if length == 1:
if needle == haystack[start_index]:
return 1
else:
return 0
mid = start_index + length // 2
res1 = _count_internal(needle, haystack, start_index, mid)
res2 = _count_internal(needle, haystack, mid, end_index)
return res1 + res2
def count(needle, haystack):
return _count_internal(needle, haystack, 0, len(haystack))
Using built-in methods with recursion
It may seem stupid to use built-in methods (or functions) in this case because there is already a built-in method to solve the problem without recursion but here it is and it uses the index method that both strings and lists have:
def count(needle, haystack):
try:
next_index = haystack.index(needle)
except ValueError: # the needle isn't present
return 0
return 1 + count(needle, haystack[next_index+1:])
Using iteration instead of recursion
Recursion is really powerful but in Python you have to fight against the recursion limit and because there is not tail call optimization in Python it is often rather slow. This can be solved by using iterations instead of recursion:
def count(needle, haystack):
found = 0
for item in haystack:
if needle == item:
found += 1
return found
Iterative approaches using built-ins
If you're more advantageous, one can also use a generator expression together with sum:
def count(needle, haystack):
return sum(needle == item for item in haystack)
Again this relies on the fact that booleans behave like integers and so sum adds all the occurrences (ones) with all non-occurrences (zeros) and thus gives the number of total counts.
But if one is already using built-ins it would be a shame not to mention the built-in method (that both strings and lists have): count:
def count(needle, haystack):
return haystack.count(needle)
At that point you probably don't need to wrap it inside a function anymore and could simply use just the method directly.
In case you even want to go further and count all elements you can use the Counter in the built-in collections module:
>>> from collections import Counter
>>> Counter('abcdab')
Counter({'a': 2, 'b': 2, 'c': 1, 'd': 1})
Performance
I often mentioned copies and their effect on memory and performance and I actually wanted to present some quantitative results to show that it actually makes a difference.
I used a fun-project of mine simple_benchmarks here (it's a third-party package so if you want to run it you have to install it):
def count_original(f, s):
if not s:
return 0
elif f == s[0]:
return 1 + count_original(f, s[1:])
else:
return 0 + count_original(f, s[1:])
def _count_index_internal(needle, haystack, current_index):
length = len(haystack)
if current_index >= length:
return 0
found = haystack[current_index] == needle
return found + _count_index_internal(needle, haystack, current_index + 1)
def count_index(needle, haystack):
return _count_index_internal(needle, haystack, 0)
def _count_iterator_internal(needle, haystack):
try:
item = next(haystack)
except StopIteration:
return 0
return (item == needle) + _count_iterator_internal(needle, haystack)
def count_iterator(needle, haystack):
return _count_iterator_internal(needle, iter(haystack))
def count_divide_conquer(needle, haystack):
length = len(haystack)
if length == 0:
return 0
if length == 1:
if needle == haystack[0]:
return 1
else:
return 0
mid = length // 2
return count_divide_conquer(needle, haystack[:mid]) + count_divide_conquer(needle, haystack[mid:])
def _count_divide_conquer_index_internal(needle, haystack, start_index, end_index):
length = end_index - start_index
if length == 0:
return 0
if length == 1:
if needle == haystack[start_index]:
return 1
else:
return 0
mid = start_index + length // 2
res1 = _count_divide_conquer_index_internal(needle, haystack, start_index, mid)
res2 = _count_divide_conquer_index_internal(needle, haystack, mid, end_index)
return res1 + res2
def count_divide_conquer_index(needle, haystack):
return _count_divide_conquer_index_internal(needle, haystack, 0, len(haystack))
def count_index_method(needle, haystack):
try:
next_index = haystack.index(needle)
except ValueError: # the needle isn't present
return 0
return 1 + count_index_method(needle, haystack[next_index+1:])
def count_loop(needle, haystack):
found = 0
for item in haystack:
if needle == item:
found += 1
return found
def count_sum(needle, haystack):
return sum(needle == item for item in haystack)
def count_method(needle, haystack):
return haystack.count(needle)
import random
import string
from functools import partial
from simple_benchmark import benchmark, MultiArgument
funcs = [count_divide_conquer, count_divide_conquer_index, count_index, count_index_method, count_iterator, count_loop,
count_method, count_original, count_sum]
# Only recursive approaches without builtins
# funcs = [count_divide_conquer, count_divide_conquer_index, count_index, count_iterator, count_original]
arguments = {
2**i: MultiArgument(('a', [random.choice(string.ascii_lowercase) for _ in range(2**i)]))
for i in range(1, 12)
}
b = benchmark(funcs, arguments, 'size')
b.plot()
It's log-log scaled to display the range of values in a meaningful way and lower means faster.
One can clearly see that the original approach gets very slow for long inputs (because it copies the list it performs in O(n**2)) while the other approaches behave linearly. What may seem weird is that the divide-and-conquer approaches perform slower, but that is because these need more function calls (and function calls are expensive in Python). However they can process much longer inputs than the iterator and index variants before they hit the recursion limit.
It would be easy to change the divide-and-conquer approach so that it runs faster, a few possibilities that come to mind:
Switch to non-divide-and-conquer when the sequence is short.
Always process one element per function call and only divide the rest of the sequence.
But given that this is probably just an exercise in recursion that goes a bit beyond the scope.
However they all perform much worse than using iterative approaches:
Especially using the count method of lists (but also the one of strings) and the manual iteration are much faster.
The error is because sometimes you just have no return Value. So return 0 at the end of your function fixes this error. There are a lot better ways to do this in python, but I think it is just for training recursive programming.
You are doing things the hard way in my opinion.
You can use Counter from collections to do the same thing.
from collections import Counter
def count(f, s):
if s == None:
return 0
return Counter(s).get(f)
Counter will return a dict object that holds the counts of everything in your s object. Doing .get(f) on the dict object will return the count for the specific item you are searching for. This works on lists of numbers or a string.
If you're bound and determined to do it with recursion, whenever possible I strongly recommend halving the problem rather than whittling it down one-by-one. Halving allows you to deal with much larger cases without running into stack overflow.
def count(f, s):
l = len(s)
if l > 1:
mid = l / 2
return count(f, s[:mid]) + count(f, s[mid:])
elif l == 1 and s[0] == f:
return 1
return 0

Categories