initial and final commit

This commit is contained in:
steinkirch 2013-09-10 04:14:02 -04:00
parent 4061fa6df1
commit 227a0efc0e
272 changed files with 11976 additions and 4 deletions

View file

@ -0,0 +1,29 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' give all the combinations of a str or list:
>>> l1 = (1, 2, 3)
>>> comb_str(l1)
[[1], [1, [2]], [1, [2, 3]], [1, [3]], [2], [2, 3], [3]]
>>> comb_str([])
[]
'''
def comb_str(l1):
if len(l1) < 2: return l1
result = []
for i in range(len(l1)):
result.append([l1[i]])
for comb in comb_str(l1[i+1:]):
result.append([l1[i], comb])
return result
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,68 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' two routines to convert str to int and int to str:
- bc: negative str, zero, exp numbers (ex. 1e5), other bases, NAN
>>> conv_str2int('367')
367
>>> conv_str2int('0')
0
>>> conv_str2int('-10')
-10
>>> conv_str2int('1e5')
100000
>>> conv_int2str(0)
'0'
>>> conv_int2str(1e5)
'100000'
>>> conv_int2str(367)
'367'
>>> conv_int2str(-10)
'-10'
'''
def conv_int2str(int1):
aux_dict = {key:value for key in range(10) for value in '0123456789'[key]}
if int1 == 0: return '0' # REMEMBER TO HANDLE 0
if int1 < 0: # REMEMBER TO HANDLE NEGATIVE
sign = '-'
int1 = int1*(-1)
else:
sign = ''
aux_ls = []
while int1 > 0:
c = int1%10
int1 = int1//10
cadd = aux_dict[c]
aux_ls.append(cadd)
aux_ls.reverse() # REMEMBER TO REVERSE
return sign + ''.join(aux_ls)
def conv_str2int(str1):
if not str1: return None
aux_dict = {key:value for value in range(10) for key in '0123456789'[value]}
if str1[0] == '-':
sign = -1
str1 = str1[1:] # REMEMBER TO CUT THE SIGN FROM THE STR
else:
sign = 1
dec, result = 1, 0
for i in range(len(str1)-1, -1, -1): # REMEMBER TO FINISH IN -1, NOT 0, AND
aux = str1[i] # AND DO THE STEPS -1
if aux == 'e':
exp_num = conv_str2int(str1[i+1:])
number = conv_str2int(str1[:i])
result = number*10**exp_num
break
result += aux_dict[aux]*dec
dec *= 10
return result*sign
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,33 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def find_0_MxN(m):
''' find 0s in a matrix and replace the col and row to 0s:
>>> m1 = [[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16]]
>>> find_0_MxN(m1)
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
>>> m2 = [[1, 2, 3, 4], [0, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
>>> find_0_MxN(m2)
[[0, 2, 3, 4], [0, 0, 0, 0], [0, 10, 11, 12], [0, 14, 15, 16]]
'''
index = []
for row in range(len(m)):
for col in range(len(m[0])):
if m[row][col] == 0:
index.append((row, col))
for i in index:
row = i[0]
col = i[1]
for i in range(len(m)):
m[row][i] = 0
for i in range(len(m[0])):
m[i][col] = 0
return m
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,30 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' find the first non-repetead char in a str.
---> we use a dict to count occurences
>>> find_non_rep_char("cut")
'c'
>>> s1 = 'google'
>>> find_non_rep_char(s1)
'l'
>>> find_non_rep_char('ccc')
>>> find_non_rep_char('')
'''
from collections import Counter
def find_non_rep_char(s1):
aux_dict = Counter()
for i in s1:
aux_dict[i] += 1
for i in s1:
if aux_dict[i] < 2: return i # remember it's <2
# not handling anything else: return None
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,38 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Find if a s2 is a substring of a s1
>>> s1 = 'buffy is a vampire slayer'
>>> s2 = 'vampire'
>>> s3 = 'angel'
>>> isSubstr(s1, s2)
True
>>> isSubstr(s1, s3)
False
>>> s4 = 'pirevam'
>>> find_substr(s2, s4)
True
>>> find_substr(s1, s4)
False
'''
def isSubstr(s1, s2):
if s1 in s2 or s2 in s1: return True
return False
def find_substr(s1, s2):
if s1 == '' or s2 == '': return True #empty str is always substr
for i, c in enumerate(s1):
if c == s2[0]:
test_s1 = s1[i:]+s1[:i]
return isSubstr(s2, test_s1)
return False
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,41 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def unique_char(s):
if len(s) > 256: return False
set_chars = set()
for i in s:
if i in set_chars:
return False
else:
set_chars.add(i)
return True
def unique_char_no_add(s):
if len(s) < 2: return True
for i, c in enumerate(s):
for j in s[i+1:]:
if j == c:
return False
return True
def main():
s1 = 'abcdefg'
s2 = 'buffy'
s3 = ''
print(unique_char(s1))
print(unique_char(s2))
print(unique_char(s3))
print(unique_char_no_add(s1) )
print(unique_char_no_add(s2))
print(unique_char_no_add(s3))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,24 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' give all the permutation of a str:
>>> str1 = 'hat'
>>> perm_str(str1)
['hat', 'hta', 'aht', 'ath', 'tha', 'tah']
>>> perm_str('')
''
'''
def perm_str(str1):
if len(str1) < 2: return str1
result = []
for i in range(len(str1)):
for perm in perm_str(str1[:i] + str1[i+1:]):
result.append(str1[i] + perm)
return result
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,29 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' remove the chars in a list from a string
---> handle whitespaces!!!!
>>> remove_char_str('I love google', 'oe')
'I lv ggl'
>>> remove_char_str('google', '')
'google'
>>> remove_char_str('google', 'google')
''
'''
def remove_char_str(s1, charlist):
set_aux = set(charlist)
lt_aux = [] # we use list intead of concat. strs because it's more efficient
for c in s1:
if c not in set_aux:
lt_aux.append(c)
return ''.join(lt_aux) # IF NON CHARS, RETURN '' not NONE!
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,26 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def reverse_str(s):
''' in place '''
sr_ls = []
for i in range(len(s)-1, -1, -1):
sr_ls.append(s[i])
return ''.join(sr_ls)
def main():
s1 = 'abcdefg'
s2 = 'buffy'
s3 = ''
print(reverse_str(s1))
print(reverse_str(s2))
print(reverse_str(s3))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,44 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' reverse words in a setence, keeping the words right
>>> str1 = 'I love Google and Python!'
>>> reverse_words(str1)
'Python! and Google love I'
>>> reverse_words('bla')
'bla'
>>> reverse_words('')
''
>>> reverse_words_brute(str1)
'Python! and Google love I'
>>> reverse_words_brute('bla')
'bla'
>>> reverse_words_brute('')
''
'''
def reverse_words(str1):
l1 = str1.split(' ')
l1.reverse()
return ' '.join(l1)
def reverse_words_brute(str1):
aux_lt = []
aux_str = ''
for i, c in enumerate(str1):
if c != ' ':
aux_str += c # WE COULD HAVE USED LT HERE, MORE EFFICIENT
elif c == ' ':
aux_lt.append(aux_str) # WE COULD HAVE USED STR BUT NOT EFFICIENT!
aux_str = ''
aux_lt.append(aux_str) # REMEMBER THAT THE LAST ONE DOEN'T HAVE SPACE!
aux_lt.reverse()
return ' '.join(aux_lt)
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,31 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def rotate_NxN(m):
n = len(m)
for layer in range(n//2):
first = layer
last = n - 1 - layer
for i in range(first, last):
offset = i - first
top = m[first][i]
m[first][i] = m[last-offset][first]
m[last-offset][first] = m[last][last-offset]
m[last][last-offset] = m[i][last]
m[i][last] = top
return m
def main():
m = [[1,2],[3,4]]
mr = [[3,1],[4,2]]
assert(rotate_NxN(m) == mr)
m2 = [[1,2,3],[4,5,6],[7,8,9]]
print(rotate_NxN(m2))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,32 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
from collections import Counter
def str_comp(s):
''' basic str compression with counts of repeated char'''
count, last = 1, ''
list_aux = []
for i, c in enumerate(s):
if last == c:
count += 1
else:
if i != 0:
list_aux.append(str(count))
list_aux.append(c)
count = 1
last = c
list_aux.append(str(count))
return ''.join(list_aux)
def main():
s1 = 'aabcccccaaa'
s2 = ''
print(str_comp(s1)) # 'a2b1c5a3'
print(str_comp(s2))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,49 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def ver_perm(s1, s2):
''' worst case O(nlogn + mlogm) = O(NlogN) '''
if len(s1) != len(s2): return False
s1 = sorted(s1)
s2 = sorted(s2)
return s1 == s2
from collections import Counter
def ver_perm_dict(s1, s2):
''' worst case O(n + n +2n) = O(n)'''
if len(s1) != len(s2): return False
dict_aux = Counter()
for c in s1:
dict_aux[c] += 1
for c in s2:
dict_aux[c] -= 1
for item in dict_aux:
if dict_aux[item]:
return False
return True
import time
def main():
s1 = 'ufyfbufyfb'
s2 = 'buffybuffy'
s3 = 'uuyfbuuyfb'
s4 = ''
start = time.time()
print(ver_perm(s1, s2))
print(ver_perm(s1, s3))
print(ver_perm(s1, s4))
final1 = time.time() - start
start = time.time()
print(ver_perm_dict(s1, s2))
print(ver_perm_dict(s1, s3))
print(ver_perm_dict(s1, s4))
final2 = time.time() - start
print(final2-final1)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,32 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Example of how to use a bit array in python as a "counter" dict:
>>> l1 = [0, 1, 2, 3, 4, 2, 6, 7, 8, 9]
>>> print_dupl_ba(l1)
2
'''
def print_dupl_ba(l1):
bs = bytearray(10)
for i in range(len(l1)):
if i == l1[i]:
bs[i] = 1
for index, bit in enumerate(bs):
if bit == 0:
return l1[index]
return None
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,40 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Clear a bit in a binary number. It is almost like the reverse of set bit:
1) first create a number filled of 1s, with 0 at i (can create 0001000 and ~)
2) AND the number so it clears the ith bit
>>> num = int('10010000', 2)
>>> clear_bit(num, 4)
'0b10000000'
>>> num = int('10010011', 2)
>>> clear_all_bits_from_i_to_0(num, 2)
'0b10010000'
>>> num = int('1110011', 2)
>>> clear_all_bits_from_most_sig_to_1(num, 2)
'0b11'
'''
def clear_bit(num, i):
mask = ~ (1 << i) # -0b10001
return bin(num & mask)
def clear_all_bits_from_i_to_0(num, i):
mask = ~ ( (1 << (i+1)) - 1)
return bin(num & mask)
def clear_all_bits_from_most_sig_to_1(num, i):
mask = ( 1 << i) -1
return bin(num & mask)
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,28 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Find how many bits a int has:
1) Start with a mask of 1
2) Mask with AND
3) if result (if true): count += 1
(obs: to find the int of a bin do int('1001', 2)) and to show in bin do bin(int))
>>> for i in range(17): print(find_bit_len(i))
'''
def find_bit_len(int_num):
lenght = 0
while int_num:
int_num >>= 1
lenght += 1
return lenght
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,34 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Find how many 1s in the binary:
1) Start with a mask of 1
2) Mask with AND
3) if result (if true): count += 1
(obs: to find the int of a bin do int('1001', 2)) and to show in bin do bin(int))
>>> find_how_many_1_in_a_binary(9)
2
'''
def find_how_many_1_in_a_binary(n):
counter = 0
while n:
if n & 1:
counter += 1
n >>= 1
return counter
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,41 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Get a bit in a binary number:
1) Shifts 1 over by i bits
2) make an AND with the number
3) all the other than the bit at i are clean, now compare to 0
4) if the new value is not 0, bit i is 1
>>> num = int('0100100', 2)
>>> get_bit(num, 0)
0
>>> get_bit(num, 1)
0
>>> get_bit(num, 2)
1
>>> get_bit(num, 3)
0
>>> get_bit(num, 4)
0
>>> get_bit(num, 5)
1
>>> get_bit(num, 6)
0
'''
def get_bit(num, i):
mask = 1 << i
return num & mask != 0
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,35 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Given a real number between 0 and 1 (eg: 0.72), this method print the binary
representation. If the Number cannot be represented accurately in binary, with at
most 32 chars, print error:
>>> get_float_rep(0.72)
('Error 2', '.1011100001010001111010111000010')
>>> get_float_rep(0.1)
('Error 2', '.0001100110011001100110011001100')
>>> get_float_rep(0.5)
'.1'
'''
def get_float_rep(num):
if num >= 1 or num <= 0: return 'Error 1'
result = '.'
while num:
if len(result) >= 32: return 'Error 2', result
r = num*2
if r >= 1:
result += '1'
num = r - 1
else:
result += '0'
num = r
return result
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,35 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Given two 32-bit numbers, N and M, and two bit positions, i and j, this
method insert M into N such that M starts at bit j and ends at bit i:
1) clear the bits j thru i in N'
2) shift M so that it lines up with bits j thru i
3) merge M and N
>>> N = 0b10000000000
>>> M = 0b10011
>>> j = 6
>>> i = 2
>>> insert_small_bin_into_big_bin(M, N, i, j)
'0b10001001100'
'''
def insert_small_bin_into_big_bin(M, N, i, j):
allOnes = ~0
left = allOnes << (j+1) # 1110000
right = ( (1 << i) - 1) # 0000111
mask = left | right # 1110111
N_cleared = N & mask
M_shifted = M << i
return bin( N_cleared | M_shifted)
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,64 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Give a positive int, print the next smallest and next largest ints with
same number of 1 bits.
The brute force is:
1) find number of 1 bits
2) loop above and down until find same, checking for each
>>> num = 0b1001
>>> next = '0b1010'
>>> prev = '0b110'
>>> print_prev_same_1s(num) == prev
True
>>> print_next_same_1s(num) == next
True
'''
def print_prev_same_1s(num):
n1s = find_num_1s(num)
# find prev
i = num-1
while True:
n1s_here = find_num_1s(i)
if n1s_here == n1s:
return bin(i)
i -= 1
if i < 0:
return None
def print_next_same_1s(num):
n1s = find_num_1s(num)
# find next
i = num+1
while True:
n1s_here = find_num_1s(i)
if n1s_here == n1s:
return bin(i)
i += 1
if i < 0:
return None
def find_num_1s(num):
counter = 0
while num:
if num & 1:
counter += 1
num >>= 1
return counter
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,45 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' This method returns the number of bits that are necessary to change to convert two
numbers A and B:
1) XOR
2) count 1s
>>> a = int('10010000', 2)
>>> b = int('01011010', 2)
>>> count_bits_swap(a, b)
4
>>> count_bits_swap2(a, b)
4
'''
def count_bits_swap2(a, b):
count = 0
m = a^b
while m:
count +=1
m = m & (m-1)
return count
def count_bits_swap(a, b):
m = a^b
return count_1s(m)
def count_1s(m):
count = 0
while m:
if m& 1 :
count +=1
m >>= 1
return count
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,38 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Set a bit in a binary number:
1) Shifts 1 over by i bits
2) make an OR with the number, only the value at bit i will change and all the others bit
of the mask are zero so will not affect the num
>>> num = int('0100100', 2)
>>> set_bit(num, 0)
'0b100101'
>>> set_bit(num, 1)
'0b100110'
>>> set_bit(num, 2) # nothing change
'0b100100'
>>> set_bit(num, 3)
'0b101100'
>>> set_bit(num, 4)
'0b110100'
>>> set_bit(num, 5) # nothing change
'0b100100'
'''
def set_bit(num, i):
mask = 1 << i
return bin( num | mask )
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,38 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Swap odd and even bits in a smart way in a binary:
1) first for odds, take n and move the odd:
(a) Mask all odd bits with 10101010 (0xAA)
(b) shift by right by 1
2) do the same to ints with 01010101
3) merge
>>> num = 0b11011101
>>> result = '0b1101110'
>>> swap_odd_even(num) == result
True
'''
def swap_odd_even(num):
mask_odd = 0xAA # 0b10101010
mask_even = 0x55 # 0b1010101
odd = num & mask_odd
odd >>= 1
even = num & mask_even
even >>= 1
return bin(odd | even)
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,26 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' This method merges set bit and clean bit:
1) first clear the bit at i using a mask such as 1110111
2) then shift the intended value v by i bits
3) this will create a number with bit i to v and all other to 0
4) finally update the ith bit with or
>>> num = int('10010000', 2)
>>> update_bit(num, 2, 1)
'0b10010100'
'''
def update_bit(num, i, v):
mask = ~ (1 << i)
return bin( (num & mask) | (v << i) )
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,40 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Given a linked list, check if the nodes form a palindrome '''
from linked_list_fifo import LinkList, Node
def isPal(l1):
if len(l1) < 2: return True
if l1[0] != l1[-1]: return False
return isPal(l1[1:-1])
def checkllPal(ll):
node = ll.head
l1 = []
while node:
l1.append(node.value)
node = node.next
return isPal(l1)
def main():
ll = LinkList()
l1 = [1, 2, 3, 2, 1]
for i in l1:
ll.addNode(i)
print(checkllPal(ll))
ll.addNode(2)
ll.addNode(3)
print(checkllPal(ll))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,72 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Build a class for a circular linked list and implement a function to see whether
a linked list is circular'''
from linked_list_fifo import Node, LinkList
class Node(object):
def __init__(self, value = None, next = None):
self.value = value
self.next = next
class CircLinkList(object):
def __init__(self):
self.head = None
self.tail = None
self.lenght = 0
def addNode(self, value):
node = Node(value, self.head)
if not self.head:
self.head = node
if self.tail:
self.tail.next = node
self.tail = node
self.lenght += 1
def printList(self):
size = self.lenght
node = self.head
i = 0
while i < size:
print(node.value)
node = node.next
i += 1
def isCircularll(ll):
p1 = ll.head
p2 = ll.head
while p2 and p2.next:
p1 = p1.next
p2 = p2.next.next
if p1 == p2:
return True
return False
def main():
ll = CircLinkList()
for i in range(10):
ll.addNode(i)
ll.printList()
print(isCircularll(ll))
ll2 = LinkList()
for i in range(10):
ll2.addNode(i)
ll2.printList()
print(isCircularll(ll2))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,53 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Implement a double-linked list, which is very simple, we just need inherets from a Linked List Class and add an attribute for prev.'''
from linked_list_fifo import LinkList
class dNode(object):
def __init__(self, value = None, next = None):
self.value = value
self.next = next
self.prev = None # THIS IS THE EXTRA ATTRIBUTE FOR DOUBLE L
self.children = None # THIS IS NOT USED HERE, IS EXAMPLES WITH MANY LL INSIDE LLs
class dLinkList(LinkList):
def addNode(self, value):
node = dNode(value)
if not self.head:
self.head = node
if self.tail:
node.prev = self.tail # ADD THIS WHEN DOUBLE L
self.tail.next = node
self.tail = node
self.length += 1
def printListInverse(self): # THIS IS THE EXTRA METHOD FOR DOUBLE L
node = self.tail
while node:
print(node.value)
node = node.prev
from collections import Counter
def main():
ll = dLinkList()
for i in range(1, 10):
ll.addNode(i)
print('Printing the list...')
ll.printList()
print('Now, printing the list inversely...')
ll.printListInverse()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,105 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Find the mth-to-last element of a linked list.
One option is having two pointers, separated by m. P1 start at the roots (p1 = self.root) and p2 is m-behinf pointer, which is created when p1 is at m. When p1 reach the end, p2 is the node. '''
from linked_list_fifo import Node
class LinkList(object):
def __init__(self):
self.head = None
self.tail = None
self.lenght = 0
def addNode(self, value):
node = Node(value)
if not self.head:
self.head = node
if self.tail:
self.tail.next = node
self.tail = node
self.lenght += 1
def removeNode(self, index):
prev = None
node = self.head
i = 0
while node and i < index:
prev = node
node = node.next
i += 1
if i == index:
if not prev:
self.head = node.next
else:
prev.next = node.next
self.lenght -= 1
else:
print('Index not found')
def findkth_from_begin(self, k):
node = self.head
i = 0
while node and i < k:
node = node.next
i += 1
while node:
print(node.value)
node = node.next
def findkth_to_last(self, k):
node = self.head
key = self.lenght - k
i = 0
while node and i < key:
node = node.next
i += 1
print(node.value)
def findkth_to_last_2pointers(self, k):
node = self.head
pointer = self.head
i = 0
while pointer and i < k:
pointer = pointer.next
i += 1
while pointer:
node = node.next
pointer = pointer.next
print(node.value)
def findkth_to_last_2pointers2(self, k):
p1 = self.head
p2 = self.head
i = 0
while p1:
if i >= k: # ---> notice >= not >!
p2 = p2.next
p1 = p1.next
i += 1
print(p2.value)
def main():
ll = LinkList()
for i in range(1, 11):
ll.addNode(i)
# list is 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
# so 0th from last is 11, 1th to last is 10,
# 2th from last is 9!
print('Finding from begin...')
ll.findkth_from_begin(2)
print('Finding to last, case 1...')
ll.findkth_to_last(2) #9
print('Finding to last, case 2...')
ll.findkth_to_last_2pointers(2)
print('Finding to last, case 3...')
ll.findkth_to_last_2pointers2(2)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,65 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' The first example design a Hash table using chaining to avoid collisions. The second
uses two lists.'''
from linked_list_fifo import Node, LinkList
class HashTableLL(object):
def __init__(self, size):
self.size = size
self.slots = []
self._createHashTable()
def _createHashTable(self):
for i in range(self.size) :
self.slots.append(LinkList())
def findIndex(self, item):
return item%self.size
def addItem(self, item):
index = self.findIndex(item)
self.slots[index].addNode(item)
return self
def delItem(self, item):
index = self.findIndex(item)
self.slots[index].deleteNode(item)
return self
def printHashTable(self):
for i in range(self.size):
print('\nSlot {}:'.format(i))
print(self.slots[i].printList())
def test_hash_tables():
H1 = HashTableLL(3)
for i in range (0, 20):
H1.addItem(i)
H1.printHashTable()
print('\n\nNow deleting:')
H1.delItem(0)
H1.delItem(0)
H1.delItem(0)
H1.delItem(0)
H1.printHashTable()
'''
H2 = HashTable2L(3)
H2[54]="buffy"
H2[26]="xander"
H2[17]="giles"
print(H.2slots)
'''
if __name__ == '__main__':
test_hash_tables()

View file

@ -0,0 +1,183 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' A class for a linked list that has the nodes in a FIFO order (such as a queue)'''
class Node(object):
def __init__(self, value = None, next = None):
self.value = value
self.next = next
class LinkList(object):
def __init__(self):
self.head = None
self.tail = None
self.length = 0
def addNode(self, value):
node = Node(value)
if not self.head:
self.head = node
if self.tail:
self.tail.next = node
self.tail = node
self.length += 1
def printList(self):
node = self.head
while node:
print(node.value)
node = node.next
def addInOrder(self, item):
new_node = Node(item)
node = self.head
previous = None
stop = False
while node and not stop:
if node.value > item:
stop = True
else:
previous = node
node = node.next
if not previous:
new_node.next = self.head
self.head = new_node
else:
new_node.next = node
previous.next = new_node
def deleteNode(self, index):
prev = None
node = self.head
i = 0
while node and i < index:
prev = node
node = node.next
i += 1
if i == index:
if not prev:
self.head = node.next
else:
prev.next = node.next
self.length -= 1
else:
print('Index not found!')
def deleteNodeIfOrdered(self, item):
node = self.head
previous = None
found = False
while node and not found:
if node.value == item:
found = True
else:
previous = node
node = node.next
if found:
if not previous:
self.head = node.next
else:
previous.next = node.next
else:
print('Node not found!')
def removeDupl(self):
prev = None
node = self.head
aux_dict = Counter()
while node:
value_here = node.value
if aux_dict[value_here] == 0:
aux_dict[value_here] = 1
else:
if prev == None:
self.head = node.next
else:
prev.next = node.next
self.length -= 1
prev = node
node = node.next
def removeDupl_no_buf(self):
node = self.head
while node:
pivot = node.value
pointer = node.next
prev = node
while pointer:
value_here = pointer.value
if value_here == pivot:
prev.next = pointer.next
self.length -= 1
prev = pointer
pointer = pointer.next
node = node.next
def searchIfOrdered(self, item):
node = self.head
found = False
stop = False
while node and not found and not stop:
if node.value == item:
found = True
else:
if node.value > item:
stop = True
else:
node = node.next
return found
from collections import Counter
def main():
ll = LinkList()
for i in range(1, 10):
ll.addNode(i)
ll.addNode(i+1)
print('Linked List with duplicates:')
ll.printList()
print('Length before deleting duplicate is: ', ll.length)
ll.removeDupl()
ll.printList()
print('Lenght after deleting duplicates is: ', ll.length)
ll = LinkList()
for i in range(1, 10):
ll.addNode(i)
ll.addNode(i+1)
print('Linked List with duplicates:')
ll.printList()
print('Length before deleting duplicate is: ', ll.length)
ll.removeDupl_no_buf()
ll.printList()
print('Lenght after deleting duplicates is: ', ll.length)
ll = LinkList()
l1 = [4, 2, 5, 7, 1, 9]
for i in l1:
ll.addInOrder(i)
ll.printList()
print(ll.searchIfOrdered(7))
print(ll.searchIfOrdered(3))
ll.deleteNodeIfOrdered(7)
ll.printList()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,82 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Implement a unordered linked list, i.e. a LIFO linked list (like a stack) '''
class Node(object):
def __init__(self, value = None, next = None):
self.value = value
self.next = next
class LinkList(object):
def __init__(self):
self.head = None
self.lenght = 0
def addNode(self, value):
node = Node(value)
node.next = self.head
self.head = node
self.lenght += 1
def printList(self):
node = self.head
while node:
print(node.value)
node = node.next
def deleteNode(self, index):
prev = None
node = self.head
i = 0
while node and i < index:
prev = node
node = node.next
i += 1
if index == i:
self.lenght -= 1
if prev == None:
self.head = node.next
else:
prev.next = node.next
else:
print('Node with index {} not found'.format(index))
def deleteNodeByValue(self, item):
prev = None
node = self.head
found = False
while node and not found:
if node.value == item:
found = True
else:
prev = node
node = node.next
if found:
self.lenght -= 1
if prev == None:
self.head = node.next
else:
prev.next = node.next
else:
print('Node with value {} not found'.format(item))
def main():
ll = LinkList()
for i in range(1, 11):
ll.addNode(i)
print('The list is:')
ll.printList()
print('The list after deleting node with index 2 (value 8):')
ll.deleteNode(2)
ll.printList()
print('The list after deleting node with value 2 (index 7):')
ll.deleteNodeByValue(2)
ll.printList()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,45 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' This function partionate a linked list in a value, where everything smaller than this value
goes to the front, and everything large goes to the back:'''
from linked_list_fifo import LinkList, Node
def partList(ll, n):
more = LinkList()
less = LinkList()
node_old = ll.head
while node_old:
item = node_old.value
if item < n:
less.addNode(item)
elif item > n:
more.addNode(item)
node_old = node_old.next
less.addNode(n)
nodemore = more.head
while nodemore:
less.addNode(nodemore.value)
nodemore = nodemore.next
return less
def main():
ll = LinkList()
l1 = [6, 7, 3, 4, 9, 5, 1, 2, 8]
for i in l1:
ll.addNode(i)
print('Before Part')
ll.printList()
print('After Part')
newll = partList(ll, 6)
newll.printList()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,70 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Supposing two linked lists represening numbers, such that in each of their
nodes they carry one digit. This function sums the two numbers that these
two linked lists represent, returning a third list representing the sum:'''
from linked_list_fifo import Node, LinkList
def sumlls(l1, l2):
lsum = LinkList()
dig1 = l1.head
dig2 = l2.head
next = 0
while dig1 and dig2:
d1 = dig1.value
d2 = dig2.value
sum_d = d1 + d2 + next
if sum_d > 9:
next = sum_d//10
lsum.addNode(sum_d%10)
else:
lsum.addNode(sum_d)
next = 0
dig1 = dig1.next
dig2 = dig2.next
if dig1:
sum_d = next + dig1.value
if sum_d > 9:
lsum.addNode(sum_d%10)
else:
lsum.addNode(sum_d)
dig1 = dig1.next
if dig2:
sum_d = next + dig2.value
if sum_d > 9:
lsum.addNode(sum_d%10)
else:
lsum.addNode(sum_d)
dig2 = dig2.next
return lsum
def main():
l1 = LinkList() # 2671
l1.addNode(1)
l1.addNode(7)
l1.addNode(6)
l1.addNode(2)
l2 = LinkList() # 455
l2.addNode(5)
l2.addNode(5)
l2.addNode(4)
lsum = sumlls(l1, l2)
lsum.printList()# 3126
if __name__ == '__main__':
main()

View file

@ -0,0 +1,87 @@
class Node(object):
def __init__(self, name, which):
self.name = name
self.which = which
self.next = next
self.timestamp = 0
class AnimalShelter(object):
def __init__(self):
self.first_cat = None
self.first_dog = None
self.last_cat = None
self.last_dog = None
self.counter = 0
def enqueue(self, name, which):
self.counter += 1
node = Node(name, which)
node.timestamp = self.counter
if which == 'cat':
if not self.first_cat:
self.first_cat = node
if self.last_cat:
self.last_cat.next = node
self.last_cat = node
if which == 'dog':
if not self.first_dog:
self.first_dog = node
if self.last_dog:
self.last_dog.next = node
self.last_dog = node
def dequeueDog(self):
if self.first_dog:
node = self.first_dog
self.first_dog = node.next
return str(node.name)
raise Exception('No Dogs!')
def dequeueCat(self):
if self.first_cat:
node = self.first_cat
self.first_cat = node.next
return str(node.name)
raise Exception('No Cats!')
def dequeueAny(self):
nodecat = self.first_cat
nodedog = self.first_dog
if nodecat and not nodedog:
return self.dequeueCat()
elif nodedog and not nodecat:
return self.dequeueDog()
elif nodedog and nodecat:
if nodedog.timestamp < nodecat.timestamp:
return self.dequeueDog()
else:
return self.dequeueCat()
raise Exception('No Animals!')
def main():
qs = AnimalShelter()
qs.enqueue('bob', 'cat')
qs.enqueue('mia', 'cat')
qs.enqueue('yoda', 'dog')
qs.enqueue('wolf', 'dog')
assert(qs.dequeueDog() == 'yoda')
assert(qs.dequeueCat() == 'bob')
print(qs.dequeueAny() == 'mia')
if __name__ == '__main__':
main()

View file

@ -0,0 +1,60 @@
class MyQueue(object):
def __init__(self):
self.enq = []
self.deq = []
def enqueue(self, item):
self.enq.append(item)
def _addStacks(self):
aux = []
if self.enq:
while self.enq:
aux.append(self.enq.pop())
aux.extend(self.deq)
self.deq = aux
def dequeue(self):
self._addStacks()
if self.deq:
return self.deq.pop()
raise Exception('Cannot "deque": Queue is empty')
def peek(self):
if self.deq:
return self.deq[-1]
elif self.enq:
return self.enq[0]
raise Exception('Cannot "peek": Queue is empty')
def isEmpty(self):
return not (bool(self.enq) or bool(self.deq))
def size(self):
return len(self.enq) + len(self.deq)
def printQueue(self):
self._addStacks()
if self.deq:
aux = str(self.deq).strip('[]')
return 'Front --> ' + aux +' <-- Back'
else:
raise Exception('Cannot "printQueue": Queue is empty')
def main():
q = MyQueue()
for i in range(1, 11):
q.enqueue(i)
print(q.printQueue())
assert(q.peek() == 1)
assert(q.isEmpty() == False)
assert(q.size() == 10)
for i in range (1, 10):
q.dequeue()
print(q.printQueue())
if __name__ == '__main__':
main()

View file

@ -0,0 +1,165 @@
from stack import Stack, Node
class SetOfStacks(object):
def __init__(self, capacity):
assert(capacity > 1)
self.capacity = capacity
self.stack_now = None
self.stack_now_size = 0
self.old_stacks = []
def _checkIfFull(self):
return self.stack_now_size == self.capacity
def _addStack(self):
self.stack_now = Stack()
self.stack_now_size = 0
def _archiveStack(self):
self.old_stacks.append(self.stack_now)
self.stack_now = None
self.stack_now_size = 0
def _popItem(self):
if self.stack_now.top:
value = self.stack_now.top.value
if self.stack_now.top.next:
node = self.stack_now.top
self.stack_now.top = self.stack_now.top.next
else:
self.stack_now = []
return value
raise Exception('Stack is empty.')
def numberOfStacksUsed(self):
if self.stack_now:
return len(self.old_stacks) + 1
else:
return len(self.old_stacks)
def seeTop(self):
if self.stack_now:
return self.stack_now.top.value
elif self.old_stacks:
return self.old_stacks[-1].top.value
raise Exception('Stack is Empty')
def isEmpty(self):
return not (bool(self.stack_now) or bool(self.old_stacks))
def _sizeStackInUse(self):
return self.stack_now_size
def size(self):
return self._sizeStackInUse() + self.capacity*len(self.old_stacks)
def push(self, item):
if not self.stack_now:
self._addStack()
node = Node(item)
node.next = self.stack_now.top
self.stack_now.top = node
self.stack_now_size += 1
if self._checkIfFull():
self._archiveStack()
def pop(self):
if not self.stack_now:
if not self.old_stacks:
raise Exception('Stack is empty')
else:
self.stack_now = self.old_stacks.pop()
self.stack_now_size = self.capacity - 1
self._popItem()
else:
self._popItem()
if self.stack_now:
self.stack_now_size -= 1
else:
self.stack_now_size = 0
def main():
s1 = SetOfStacks(3)
print(s1.numberOfStacksUsed())
print(s1.isEmpty())
print(s1.size())
s1.push(1)
print('Push item 1')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.push(2)
s1.push(3)
print('Push item 2 and 3')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.push(4)
print('Push item 4')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.push(5)
print('Push item 5')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.pop()
print('Pop item 5')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.pop()
print('Pop item 4')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.pop()
s1.pop()
print('Pop item 3 e 2')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.pop()
print('Pop item 1')
print(s1.numberOfStacksUsed())
print(s1.isEmpty())
print(s1.size())
if __name__ == '__main__':
main()

View file

@ -0,0 +1,154 @@
from stack import StackList
class SetOfStacksList(object):
def __init__(self, capacity):
assert(capacity > 1)
self.capacity = capacity
self.stack_now = []
self.old_stacks = []
def _checkIfFull(self):
return len(self.stack_now) == self.capacity
def _archiveStack(self):
self.old_stacks.append(self.stack_now)
self.stack_now = []
def _popItem(self):
if self.stack_now:
return self.stack_now.pop()
raise Exception('Stack is empty.')
def _sizeStackInUse(self):
return len(self.stack_now)
def numberOfStacksUsed(self):
if self.stack_now:
return len(self.old_stacks) + 1
else:
return len(self.old_stacks)
def seeTop(self):
if self.stack_now:
return self.stack_now[-1]
elif self.old_stacks:
return self.old_stacks[-1][-1]
raise Exception('Stack is Empty')
def isEmpty(self):
return not(bool(self.stack_now) or bool(self.old_stacks))
def size(self):
return len(self.stack_now) + self.capacity*len(self.old_stacks)
def push(self, item):
self.stack_now.append(item)
if self._checkIfFull():
self._archiveStack()
def pop(self):
if not self.stack_now:
if not self.old_stacks:
raise Exception('Stack is empty')
else:
self.stack_now = self.old_stacks.pop()
return self.stack_now.pop()
def popAt(self, index):
number_of_stacks = self.size()
if index < number_of_stacks:
if index == number_of_stacks - 1 and self.stack_now:
return self.stack_now.pop()
if index < number_of_stacks - 1:
stack_here = self.old_stacks[index]
return stack_here.pop()
raise Exception('Stack at index {} is empty.'.format(index))
raise Exception('Index larger than the number of stacks.')
def printStacks(self):
return str(self.old_stacks), str(self.stack_now)
def main():
s1 = SetOfStacksList(3)
print(s1.numberOfStacksUsed())
print(s1.isEmpty())
print(s1.size())
s1.push(1)
print('Push item 1')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.push(2)
s1.push(3)
print('Push item 2 and 3')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.push(4)
print('Push item 4')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.push(5)
print('Push item 5')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.pop()
print('Pop item 5')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.pop()
print('Pop item 4')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.pop()
s1.pop()
print('Pop item 3 e 2')
print(s1.numberOfStacksUsed())
print(s1.seeTop())
print(s1.isEmpty())
print(s1.size())
s1.pop()
print('Pop item 1')
print(s1.numberOfStacksUsed())
print(s1.isEmpty())
print(s1.size())
s2 = SetOfStacksList(3)
for i in range(1, 11):
s2.push(i)
print(s2.printStacks())
print(s2.popAt(2))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,21 @@
def sortStack(s):
bufs = []
while s:
item = s.pop()
count, i = 0, 0
while bufs and bufs[-1] > item:
s.append(bufs.pop())
count += 1
bufs.append(item)
while i < count:
bufs.append(s.pop())
i += 1
return bufs
def main():
s = [3, 5, 1, 2, 6, 7, 8]
print(sortStack(s))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,107 @@
from stack import Stack, Node, StackList
class StackMinElen(Stack):
def __init__(self):
self.top = None
self.mins = []
def printMin(self):
if self.mins:
return self.mins[-1]
raise Exception('Stack is empty.')
def pop(self):
if self.top:
self.mins.pop()
node = self.top
self.top = node.next
return node.value
raise Exception('Stack is empty.')
def push(self, item):
if self.top:
min_so_far = self.mins[-1]
if min_so_far > item:
self.mins.append(item)
else:
self.mins.append(min_so_far)
else:
self.mins.append(item)
node = Node(item)
node.next = self.top
self.top = node
class StackListMinElen(StackList):
def __init__(self):
self.items = []
self.mins = []
def printMin(self):
if self.mins:
return self.mins[-1]
raise Exception('Stack is Empty')
def push(self, item):
self.items.append(item)
if self.mins:
if self.mins[-1] > item:
self.mins.append(item)
else:
self.mins.append(self.mins[-1])
else:
self.mins.append(item)
def pop(self):
if self.items:
self.mins.pop()
return self.items.pop()
raise Exception('Stack is Empty')
def main():
s1 = StackListMinElen()
l1 = [4, 2, 6, 3, 1, 5]
for i in l1:
s1.push(i)
print('Min: ', s1.printMin())
print('Pop: ', s1.pop())
print('Min: ', s1.printMin())
print('Pop: ', s1.pop())
print('Min: ', s1.printMin())
print('Pop: ', s1.pop())
print('Min: ', s1.printMin())
print('Pop: ', s1.pop())
print('Min: ', s1.printMin())
print('Pop: ', s1.pop())
print('Min: ', s1.printMin())
s2 = StackMinElen()
l1 = [4, 2, 6, 3, 1, 5]
for i in l1:
s2.push(i)
print('Min: ', s2.printMin())
print('Pop: ', s2.pop())
print('Min: ', s2.printMin())
print('Pop: ', s2.pop())
print('Min: ', s2.printMin())
print('Pop: ', s2.pop())
print('Min: ', s2.printMin())
print('Pop: ', s2.pop())
print('Min: ', s2.printMin())
print('Pop: ', s2.pop())
print('Min: ', s2.printMin())
if __name__ == '__main__':
main()

View file

@ -0,0 +1,94 @@
#!/usr/bin/python3
# steinkirch at gmail.com
# astro.sunysb.edu/steinkirch
class Node(object):
def __init__(self, value=None):
self.value = value
self.next = None
class Stack(object):
def __init__(self):
self.top = None
def push(self, item):
node = Node(item)
node.next = self.top
self.top = node
def pop(self):
if self.top:
node = self.top
self.top = node.next
return node.value
raise Exception('Stack is empty.')
def isEmpty(self):
return bool(self.top)
def seeTop(self):
if self.top:
return self.top.value
raise Exception('Stack is empty.')
def size(self):
node = self.top
count = 0
while node:
count +=1
node = node.next
return count
class StackList(list):
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
def pop(self):
if self.items:
return self.items.pop()
raise Exception('Stack is empty.')
def seeTop(self):
if self.items:
return self.items[-1]
raise Exception('Stack is empty.')
def size(self):
return len(self.items)
def isEmpty(self):
return bool(self.items)
def main():
s1 = StackList()
print(s1.isEmpty())
for i in range(1, 10):
s1.push(i)
print(s1.isEmpty())
print(s1.size())
print(s1.seeTop())
s1.pop()
print(s1.size())
print(s1.seeTop())
s2 = Stack()
print(s2.isEmpty())
for i in range(1, 10):
s2.push(i)
print(s2.isEmpty())
print(s2.size())
print(s2.seeTop())
s2.pop()
print(s2.size())
print(s2.seeTop())
if __name__ == '__main__':
main()

View file

@ -0,0 +1,26 @@
from stack import Stack, Node
def moveTop(s1, s3):
s3.append(s1.pop())
def moveDisks(n, s1, s3, s2):
if n < 1: return
moveDisks(n - 1, s1, s2, s3)
moveTop(s1, s3)
moveDisks(n -1, s2, s3, s1)
def towersOfHanoi(n):
s1 = [x+1 for x in range(n)]
s2 = []
s3 = []
print('The first stick is {0} and the third stick has {1}'.format(s1, s3))
moveDisks(n, s1, s3, s2)
print('The first stick is {0} and the third stick has {1}'.format(s1, s3))
return s3
if __name__ == '__main__':
towersOfHanoi(6)

View file

@ -0,0 +1,112 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' A recursive and an iterative example of binary search in Python.
Remember: sequence must be sorted! You can return True/False or the index:
>>> l1 = [1, 2, 3, 4, 5, 6, 7]
>>> binary_search_rec(l1, 1)
0
>>> binary_search_rec(l1, 2)
1
>>> binary_search_rec(l1, 3)
2
>>> binary_search_rec(l1, 4)
3
>>> binary_search_rec(l1, 5)
4
>>> binary_search_rec(l1, 6)
5
>>> binary_search_rec(l1, 7)
6
>>> binary_search_rec(l1, 8)
>>> l1 = [1, 2, 3, 4, 5, 6]
>>> binary_search_rec(l1, 1)
0
>>> binary_search_rec(l1, 2)
1
>>> binary_search_rec(l1, 3)
2
>>> binary_search_rec(l1, 4)
3
>>> binary_search_rec(l1, 5)
4
>>> binary_search_rec(l1, 6)
5
>>> binary_search_rec(l1, 7)
>>> l1 = [1, 2, 3, 4, 5, 6, 7]
>>> binary_search_iter(l1, 1)
0
>>> binary_search_iter(l1, 2)
1
>>> binary_search_iter(l1, 3)
2
>>> binary_search_iter(l1, 4)
3
>>> binary_search_iter(l1, 5)
4
>>> binary_search_iter(l1, 6)
5
>>> binary_search_iter(l1, 7)
6
>>> binary_search_iter(l1, 8)
>>> l1 = [1, 2, 3, 4, 5, 6]
>>> binary_search_iter(l1, 1)
0
>>> binary_search_iter(l1, 2)
1
>>> binary_search_iter(l1, 3)
2
>>> binary_search_iter(l1, 4)
3
>>> binary_search_iter(l1, 5)
4
>>> binary_search_iter(l1, 6)
5
>>> binary_search_iter(l1, 7)
'''
def binary_search_iter(seq, key):
hi, lo = len(seq), 0
while lo < hi: # here is <!
mid = (hi+lo)//2
if key == seq[mid]: return mid
elif key < seq[mid]: hi = mid
else: lo = mid + 1
return None
def bool_binary_search_iter(seq, key):
hi, lo = len(seq), 0
while lo < hi:
mid = (hi+lo)//2
if key == seq[mid]: return True
elif key < seq[mid]: hi = mid
else: lo = mid + 1
return False
def binary_search_rec(seq, key, lo=0, hi=None):
hi = hi or len(seq)
if hi <= lo: return None # base case: <= for odd and even numbers!
mid = (hi + lo) // 2
if key == seq[mid]: return mid
elif key < seq[mid] : return binary_search_rec(seq, key, lo, mid) # include until mid-1
else: return binary_search_rec(seq, key, mid+1, hi)
def bool_binary_search_rec(seq, key, lo=0, hi=None):
hi = hi or len(seq)
if hi <= lo: return False # base case: <= for odd and even numbers!
mid = (hi + lo) // 2
if key == seq[mid]: return True
elif key < seq[mid] : return bool_binary_search_rec(seq, key, lo, mid)
else: return bool_binary_search_rec(seq, key, mid+1, hi)
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,76 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Searches an element in a matrix where in every row, the values are increasing from left to right, but the last number in a row is smaller than the first number in the next row.
(1) The naive brute force solution (sequential search) scan all numbers and cost O(nm). However, since the numbers are already sorted, the matrix can be viewed as a 1D sorted array. The binary search algorithm is suitable. The efficiency is O(logmn).
>>> m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> binary_search_matrix_rec(m, 6)
(1, 2)
>>> binary_search_matrix_rec(m, 12)
>>> binary_search_matrix_iter(m, 6)
(1, 2)
>>> binary_search_matrix_iter(m, 12)
>>> binary_search_matrix_iter(m, 1)
(0, 0)
(2) Another solution is "discarding" arrays in the way. The efficiency is O(logm).
>>> m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> searching_matrix(m, 6)
(1, 2)
>>> searching_matrix(m, 12)
'''
def binary_search_matrix_rec(m, key, lo=0, hi=None):
if not m: return None
rows = len(m)
cols = len(m[0])
hi = hi or rows*cols
if hi > lo: # -----> REMEMBER THIS OR INDEX WILL EXPLODE!!!!!!!!
mid = (hi + lo)//2
row = mid//cols
col = mid%cols
item = m[row][col]
if key == item: return row, col
elif key < item: return binary_search_matrix_rec(m, key, lo, mid-1)
else: return binary_search_matrix_rec(m, key, mid+1, hi)
return None
def binary_search_matrix_iter(m, key):
if not m: return None
rows = len(m)
cols = len(m[0])
lo, hi = 0, rows*cols
while lo < hi:
mid = (hi + lo)//2
row = mid//rows
col = mid%rows
item = m[row][col]
if key == item: return (row, col)
elif key < item: hi = mid
else: lo = mid +1
return None
def searching_matrix(m, key):
if not m: return None
rows = len(m)
cols = len(m[0])
i, j = 0, cols -1
while i < rows and j > 0:
item = m[i][j]
if key == item: return (i, j)
elif key < item: j -= 1
else: i += 1
return None
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,56 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Given a sorted array that was rotated, find an item with binary search:
>>> l1 = [3, 4, 5, 6, 7, 1, 2]
>>> find_element_rot_array(l1, 7)
4
>>> find_element_rot_array(l1, 3)
0
>>> find_element_rot_array(l1, 4)
1
>>> find_element_rot_array(l1, 5)
2
>>> find_element_rot_array(l1, 6)
3
>>> find_element_rot_array(l1, 1)
5
>>> find_element_rot_array(l1, 2)
6
>>> find_element_rot_array(l1, 8)
'''
def find_element_rot_array(seq, key, lo=0, hi=None):
hi = hi or len(seq)
if hi <= lo: return None # base case: <= for odd and even numbers!
mid = (hi + lo) // 2
if key == seq[mid]: return mid
# if left is ordered --> we work here
if seq[lo] <= seq[mid]:
# now, is the key there?
if key < seq[mid] and key >= seq[lo]:
return find_element_rot_array(seq, key, lo, mid)
else:
# all the other cases
return find_element_rot_array(seq, key, mid+1, hi)
# right is ordered --> we work here
else:
# now, is the key there?
if key > seq[mid] and key <= seq[hi-1]: # stupid hi-1!!!
return find_element_rot_array(seq, key, mid+1, hi)
else:
# all the other cases
return find_element_rot_array(seq, key, lo, mid)
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,52 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Given a sorted an array with empty strings, we use binary search to find some string (since
the list is sorted):
--> we deal with the empty strings with strip and then run to left and right, or move
mid to the closed non-empty str (remember that the index must be conserved):
>>> l1 = ['acre', 'ball', '', 'coach', '', 'cut', '']
>>> find_str_array_with_empty_str(l1, l1[0])
0
>>> find_str_array_with_empty_str(l1, l1[1])
1
>>> find_str_array_with_empty_str(l1, l1[3])
3
>>> find_str_array_with_empty_str(l1, l1[5])
5
>>> find_str_array_with_empty_str(l1, 'bla')
'''
def find_str_array_with_empty_str(seq, s1):
if not seq or not s1: return None
hi = len(seq)
lo = 0
while hi > lo:
mid = (hi+lo)//2
if seq[mid] == '':
while True:
left = mid-1
right = mid+1
if left < lo or right > hi: return None
elif right < hi and seq[right]:
mid = right
break
elif left > lo and seq[left]:
mid = left
break
right += 1
left -= 1
if s1 == seq[mid] == s1: return mid
elif s1 < seq[mid]: hi = mid
else: lo = mid + 1
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,5 @@
1
2
3
4
5

View file

@ -0,0 +1,4 @@
3
5
6
7

View file

@ -0,0 +1,4 @@
1
3
5
8

View file

@ -0,0 +1,70 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Some examples of how to implement Merge Sort in Python
--> RUNTIME: WORST/BEST/AVERAGE Is O(nlogn)
--> space complexity is O(n) for arrays
--> not in place, good for large arrays
>>> seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2]
>>> merge_sort(seq) == sorted(seq)
True
>>> seq2 = [3, 3, 3, 3, 3, 3, 3, 3]
>>> merge_sort(seq2) == sorted(seq2)
True
>>> seq3 = []
>>> merge_sort(seq3) == sorted(seq3)
True
'''
''' This is the main function that keep dividing the seq '''
def merge_sort(seq):
if len(seq) < 2 : return seq # base case
mid = len(seq)//2
left, right = None, None # we could have declared the arrays here,
# but this would allocate unecessary extra space
if seq[:mid]: left = merge_sort(seq[:mid])
if seq[mid:]: right = merge_sort(seq[mid:]) # notice that mid is included!
return merge(left, right) # merge iteratively
''' The two following merge functions are O(2n)=O(n) and O(n) respectively. They
illustrate many features in Python that '''
def merge_2n(left, right):
if not left or not right: return left or right # nothing to be merged
result = []
while left and right:
if left[-1] >= right[-1]:
result.append(left.pop())
else:
result.append(right.pop())
result.reverse()
return (left or right) + result
def merge(left, right):
if not left or not right: return left or right # nothing to be merged
result = []
i, j = 0, 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
if left[i:] : result.extend(left[i:]) # REMEMBER TO TO ENXTEND NOT APPEND
if right[j:] : result.extend(right[j:])
return result
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,95 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' --> In the case of two arrays: we can merge two arrays using the merge function from the merge sort
--> we can do this for files too, merging each two
1) If we can modify the arrays (pop) we can use:
def merge(left, right):
if not left or not right: return left or right # nothing to be merged
result = []
while left and right:
if left[-1] >= right[-1]:
result.append(left.pop())
else:
result.append(right.pop())
result.reverse()
return (left or right) + result
2) If we can't modify or we want to in place, we need two pointers:
>>> l1 = [1, 2, 3, 4, 5, 6, 7]
>>> l2 = [2, 4, 5, 8]
>>> merge(l1, l2)
[1, 2, 2, 3, 4, 4, 5, 5, 6, 7, 8]
3) For example, in the case we have a big array filled 0s in the end, and another array with the size of the number of 0s:
>>> l1 = [1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0]
>>> l2 = [2, 4, 5, 8]
>>> merge_two_arrays_inplace(l1, l2)
[1, 2, 2, 3, 4, 4, 5, 5, 6, 7, 8]
4) If we want to merge sorted files (and we have plenty of RAM to load all files):
>>> list_files = ['1.dat', '2.dat', '3.dat']
>>> merge_files(list_files)
[1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 6, 7, 8]
'''
def merge(left, right):
if not left or not right: return left or right # nothing to be merged
result = []
i, j = 0, 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
if left[i:] : result.extend(left[i:]) # REMEMBER TO TO ENXTEND NOT APPEND
if right[j:] : result.extend(right[j:])
return result
def merge_two_arrays_inplace(l1, l2):
if not l1 or not l2: return l1 or l2 # nothing to be merged
p2 = len(l2) - 1
p1 = len(l1) - len(l2) - 1
p12 = len(l1) - 1
while p2 >= 0 and p1 >= 0:
item_to_be_merged = l2[p2]
item_bigger_array = l1[p1]
if item_to_be_merged < item_bigger_array:
l1[p12] = item_bigger_array
p1 -= 1
else:
l1[p12] = item_to_be_merged
p2 -= 1
p12 -= 1
return l1
def merge_files(list_files):
result = []
final = []
for filename in list_files:
aux = []
with open(filename, 'r') as file:
for line in file:
aux.append(int(line))
result.append(aux)
final.extend(result.pop())
for l in result:
final = merge(l, final)
return final
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,74 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' Some examples of how to implement Quick Sort in Python
--> RUNTIME: BEST/AVERAGE Is O(nlogn), WORST is O(n2)
--> the first example is not in place, the second is in place
--> test with two element arrays, identical values
Quick sort in place:
1) select pivot as the index = 0
2) start pointer1 at index = 1 and pointer2 in the last element
3) while pointer1 < pointer2:
if value in pointer1 <= pivot
swap value in pointer1 with value in pointer2 and advanced pointer2
else
advance pointer1
4) now the array is like this:
[pivot, larger than pivot, smaller than pivot]
5) swap the pivot where pointer 1 stop
6) do recursively for [smaller] + [pivot] + [larger]
>>> seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2]
>>> quick_sort(seq) == sorted(seq)
True
>>> quick_sort([3, 3, 3, 3, 3, 3]) == [3, 3, 3, 3, 3, 3]
True
>>> quick_sort([]) == []
True
>>> quick_sort([2,1]) == [1, 2]
True
>>> quick_sort_in(seq) == sorted(seq)
True
>>> quick_sort_in([3, 3, 3, 3, 3, 3]) == [3, 3, 3, 3, 3, 3]
True
>>> quick_sort_in([]) == []
True
>>> quick_sort_in([2,1]) == [1, 2]
True
'''
def quick_sort(seq):
if len(seq) < 2 : return seq
mid = len(seq)//2
pi = seq[mid]
seq = seq[:mid] + seq[mid+1:]
left = quick_sort([x for x in seq if x <= pi]) # REMEMBER TO INCLUDE X (OR IN RIGHT)
right = quick_sort([x for x in seq if x > pi])
return left + [pi] + right
def quick_sort_in(seq):
if len(seq) < 2 : return seq
if len(seq) == 2 and seq[0] > seq[1]:
seq[0], seq[1] = seq[1], seq[0] # problems when only 2 elements because of swap
pivot = seq[0] # start at the ends because we don't know how many elements
p1, p2 = 1, len(seq) -1 # set pointers at both ends
while p1 < p2: # must be < or out of range
if seq[p1] <= pivot: # must be <= because of pivot swap
seq[p1], seq[p2] = seq[p2], seq[p1]
p2 -= 1
else:
p1 += 1
seq[0], seq[p1] = seq[p1], pivot
return quick_sort_in(seq[p1+1:]) + [seq[p1]] + quick_sort_in(seq[:p1])
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,35 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
''' A method to sort an array so that all the anagrams are together. Since we only
want the anagrams to be grouped, we can use a dictionary for this task. This
algorithm is O(n).
>>> l1 = ['hat', 'ball', 'tha', 'cut', 'labl', 'hta', 'cool', 'cuy', 'uct']
>>> sort_anagrams_together(l1)
['cut', 'uct', 'cool', 'ball', 'labl', 'hat', 'tha', 'hta', 'cuy']
'''
from collections import defaultdict
def sort_anagrams_together(l1):
result = []
# step 1 save the anagrams together
dict_aux = defaultdict(list) # rememebr to indicate the type
for word in l1:
key = ''.join(sorted(word)) # need to sort the strings and join it
dict_aux[key].append(word) # because only sorted give a list of each char
# step 2 print the anagrams. Note that if you want everything
# sorted you would have to sort the keys and insert the angrams after that
for key in dict_aux:
result.extend(dict_aux[key])
return result
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,102 @@
#!/usr/bin/python3
# mari von steinkirch 2013
from binary_tree import BinaryTree, NodeBT
''' Implementation of a binary search tree and its properties.
We use the Binary Tree class and its Node class as superclasses, and we modify the methods
that are needeed to create a BST (polymorphism). For example, the following bst:
7 ---> level 0
4 9 ---> level 1
2 5 8 10 ---> level 2
1 6 ---> level 3
has the following properties:
- SIZE OR NUMBER OF NODES: n = 10
- NUMBER OF BRANCHES OR INTERNAL NODES: b = n-1 = 9
- VALUE OF ROOT = 7
- MAX_DEPTH OR HEIGHT: h = 3
- IS BALANCED? YES
- IS BST? YES
- INORDER DFT: 1, 2, 4, 5, 6, 7, 8, 9, 10
- POSTORDER DFT: 1, 2, 6, 5, 4, 8, 10, 9, 7
- PREORDER DFT: 7, 4, 2, 1, 5, 6, 9, 8, 10
- BFT: 7, 4, 9, 2, 5, 8, 10, 1, 6
'''
class NodeBST(NodeBT):
def _addNextNode(self, value, level_here=1):
''' Aux for self.addNode(value): for BST, best O(1), worst O(log n) '''
self.traversal = []
new_node = NodeBST(value, level_here)
if not self.item:
self.item = new_node
elif value < self.item:
self.left = self.left and self.left._addNextNode(value, level_here+1) or new_node
else:
self.right = self.right and self.right._addNextNode(value, level_here+1) or new_node
return self
def _searchForNode(self, value):
''' Traverse the tree looking for the node. For BST it is O(logn) if the
tree is balanced, otherwise it can be O(n) '''
if self.item == value: return self
elif value > self.item and self.right: return self.right._findNode(value)
elif value < self.item and self.left: return self.left._findNode(value)
return None
class BinarySearchTree(BinaryTree):
'''
>>> bst = BinarySearchTree()
>>> l1 = [7, 4, 5, 9, 2, 8, 1, 6, 10]
>>> for i in l1: bst.addNode(i)
>>> bst.hasNode(3)
False
>>> bst.hasNode(10)
True
>>> bst.printTree('pre')
[7, 4, 2, 1, 5, 6, 9, 8, 10]
>>> bst.printTree('post')
[1, 2, 6, 5, 4, 8, 10, 9, 7]
>>> bst.printTree('in')
[1, 2, 4, 5, 6, 7, 8, 9, 10]
>>> bst.printTree('bft')
[7, 4, 9, 2, 5, 8, 10, 1, 6]
>>> bst.getHeight()
3
>>> bst.isBST()
True
>>> bst.isBalanced()
False
>>> bst.isBalanced(2)
False
>>> bst.getAncestor(2, 9)
7
>>> bst.getAncestor(2, 9, 'bst')
7
>>> bst.getAncestor(2, 9, 'pre-post')
7
>>> bst.getAncestor(2, 9, 'post-in')
7
'''
def addNode(self, value):
''' Add new node to the tree, by the left first, O(n).
The only difference from the Binary Tree class is the node class is
NodeBST and not NodeBT '''
if not self.root: self.root = NodeBST(value)
else: self.root._addNextNode(value)
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,464 @@
#!/usr/bin/python3
# mari von steinkirch 2013
# http://astro.sunysb.edu/steinkirch
''' Implementation of a binary tree and its properties. For example, the following bt:
1 ---> level 0
2 3 ---> level 1
4 5 ---> level 2
6 7 ---> level 3
8 9 ---> level 4
has the following properties:
- SIZE OR NUMBER OF NODES: n = 9
- NUMBER OF BRANCHES OR INTERNAL NODES: b = n-1 = 8
- VALUE OF ROOT = 1
- MAX_DEPTH OR HEIGHT: h = 4
- IS BALANCED? NO
- IS BST? NO
- INORDER DFT: 8, 6, 9, 4, 7, 2, 5, 1, 3
- POSTORDER DFT: 8, 9, 6, 7, 4, 5, 2, 3, 1
- PREORDER DFT: 1, 2, 4, 6, 8, 9, 7, 5, 3
- BFT: 1, 2, 3, 4, 5, 6, 7, 8, 9
'''
from collections import deque
class NodeBT(object):
def __init__(self, item=None, level=0):
''' Construtor for a Node in the Tree '''
self.item = item
self.level = level
self.left = None
self.right = None
self.traversal = []
#self.parent = None # not used here but can be necessary for some problems
'''
METHODS TO MODIFY NODES
'''
def _addNextNode(self, value, level_here=1):
''' Aux for self.addNode(value)'''
self.traversal = []
new_node = NodeBT(value, level_here)
if not self.item:
self.item = new_node
elif not self.left:
self.left = new_node
elif not self.right:
self.right = new_node
else:
self.left = self.left._addNextNode(value, level_here+1)
return self
'''
METHODS TO PRINT/SHOW NODES' ATTRIBUTES
'''
def __repr__(self):
''' Private method for this class'string representation'''
return '{}'.format(self.item)
def _getDFTpreOrder(self, node):
''' Traversal Pre-Order, O(n)'''
if node:
if node.item: self.traversal.append(node.item)
self._getDFTpreOrder(node.left)
self._getDFTpreOrder(node.right)
return self
def _printDFTpreOrder(self, noderoot):
''' Fill the pre-order traversal array '''
self.traversal = []
self._getDFTpreOrder(noderoot)
return self.traversal
def _getDFTinOrder(self, node):
''' Traversal in-Order, O(n)'''
if node:
self._getDFTinOrder(node.left)
if node.item: self.traversal.append(node.item)
self._getDFTinOrder(node.right)
return self
def _printDFTinOrder(self, noderoot):
''' Fill the in-order traversal array '''
self.traversal = []
self._getDFTinOrder(noderoot)
return self.traversal
def _getDFTpostOrder(self, node):
''' Traversal post-Order, O(n)'''
if node:
self._getDFTpostOrder(node.left)
self._getDFTpostOrder(node.right)
if node.item: self.traversal.append(node.item)
return self
def _getBFT(self, node):
''' Traversal bft, O(n)'''
if node:
queue = deque()
queue.append(node)
while len(queue) > 0:
current = queue.popleft()
if current.item: self.traversal.append(current)
if current.left: queue.append(current.left)
if current.right: queue.append(current.right)
return self
def _printBFT(self, noderoot):
''' Fill the in-order traversal array '''
self.traversal = []
self._getBFT(noderoot)
return self.traversal
def _printDFTpostOrder(self, noderoot):
''' Fill the post-order traversal array '''
self.traversal = []
self._getDFTpostOrder(noderoot)
return self.traversal
def _searchForNode(self, value):
''' Traverse the tree looking for the node'''
if self.item == value: return self
else:
found = None
if self.left: found = self.left._searchForNode(value)
if self.right: found = found or self.right._searchForNode(value)
return found
def _findNode(self, value):
''' Find whether a node is in the tree.
if the traversal was calculated, it is just a membership
checking, which is O(1), otherwise it is necessary to traverse
the binary tree, so best case is O(1) and worst is O(n). '''
if self.traversal: return value in self.traversal
else: return self._searchForNode(value)
def _isLeaf(self):
''' Return True if the node is a leaf '''
return not self.right and not self.left
def _getMaxHeight(self):
''' Get the max height at the node, O(n)'''
levelr, levell = 0, 0
if self.right:
levelr = self.right._getMaxHeight() + 1
if self.left:
levell = self.left._getMaxHeight() + 1
return max(levelr, levell)
def _getMinHeight(self, level=0):
''' Get the min height at the node, O(n)'''
levelr, levell = -1, -1
if self.right:
levelr = self.right._getMinHeight(level +1)
if self.left:
levell = self.left._getMinHeight(level +1)
return min(levelr, levell) + 1
def _isBalanced(self):
''' Find whether the tree is balanced, by calculating heights first, O(n2) '''
if self._getMaxHeight() - self._getMinHeight() < 2:
return False
else:
if self._isLeaf():
return True
elif self.left and self.right:
return self.left._isBalanced() and self.right._isBalanced()
elif not self.left and self.right:
return self.right._isBalanced()
elif not self.right and self.left:
return self.right._isBalanced()
def _isBalancedImproved(self):
''' Find whehter the tree is balanced in each node, O(n) '''
return 'To Be written'
''' There are two solutions to check whether a bt is a bst:
(1) Do an inorder, check if the inorder is sorted. However inorder
can't handle the difference between duplicate values on the left
or on the right (if it is in the right, the tree is not bst).
'''
def _isBST(self):
''' Find whether the tree is a BST, inorder '''
if self.item:
if self._isLeaf(): return True
elif self.left:
if self.left.item < self.item: return self.left._isBST()
else: return False
elif self.right:
if self.right.item > self.item: return self.right._isBST()
else: return False
else:
raise Exception('Tree is empty')
def _getAncestorBST(self, n1, n2):
''' Return the ancestor of two nodes if it is a bst.
we are supposing the values in the tree are unique.'''
if n1 == self.item or n2 == self.item : return self.item
elif self.item < n1 and self.item < n2:
self.right.getAncestorBST(n1, n2)
elif self.item > n1 and self.item > n2:
self.left.getAncestorBST(n1, n2)
else:
return self.item
class BinaryTree(object):
'''
>>> bt = BinaryTree()
>>> for i in range(1, 10): bt.addNode(i)
>>> bt.hasNode(7)
True
>>> bt.hasNode(12)
False
>>> bt.printTree()
[1, 2, 4, 6, 8, 9, 7, 5, 3]
>>> bt.printTree('pre')
[1, 2, 4, 6, 8, 9, 7, 5, 3]
>>> bt.printTree('bft')
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> bt.printTree('post')
[8, 9, 6, 7, 4, 5, 2, 3, 1]
>>> bt.printTree('in')
[8, 6, 9, 4, 7, 2, 5, 1, 3]
>>> bt.hasNode(9)
True
>>> bt.hasNode(11)
False
>>> bt.isLeaf(8)
True
>>> bt.getNodeLevel(1)
0
>>> bt.getNodeLevel(8)
4
>>> bt.getSizeTree()
9
>>> bt.isRoot(10)
False
>>> bt.isRoot(1)
True
>>> bt.getHeight()
4
>>> bt.isBST(1)
False
>>> bt.isBalanced()
False
>>> bt.isBalanced(2)
False
>>> bt.getAncestor(8, 5)
2
>>> bt.getAncestor(8, 5, 'pre-post')
2
>>> bt.getAncestor(8, 5, 'post-in')
2
'''
def __init__(self):
''' Construtor for the Binary Tree, which is a container of Nodes'''
self.root = None
'''
METHODS TO MODIFY THE TREE
'''
def addNode(self, value):
''' Add new node to the tree, by the left first, O(n) '''
if not self.root: self.root = NodeBT(value)
else: self.root._addNextNode(value)
'''
METHODS TO PRINT/SHOW TREES' ATTRIBUTES
'''
def __repr__(self):
''' Private method for this class'string representation'''
return '{}'.format(self.item)
def printTree(self, order = 'pre'):
''' Print Tree in the chosen order '''
if self.root:
if order == 'pre': return self.root._printDFTpreOrder(self.root)
elif order == 'in': return self.root._printDFTinOrder(self.root)
elif order == 'post': return self.root._printDFTpostOrder(self.root)
elif order == 'bft': return self.root._printBFT(self.root)
else: raise Exception('Tree is empty')
def hasNode(self, value):
''' Verify whether the node is in the Tree '''
return bool(self.root._findNode(value))
def isLeaf(self, value):
''' Return True if the node is a Leaf '''
node = self.root._searchForNode(value)
return node._isLeaf()
def getNodeLevel(self, item):
''' Return the level of the node, best O(1), worst O(n) '''
node = self.root._searchForNode(item)
if node: return node.level
else: raise Exception('Node not found')
def getSizeTree(self):
''' Return how many nodes in the tree, O(n) '''
return len(self.root._printDFTpreOrder(self.root))
def isRoot(self, value):
'''Return the root of the tree '''
return self.root.item == value
def getHeight(self):
''' Returns the height/depth of the tree, best/worst O(n) '''
return self.root._getMaxHeight()
def isBalanced(self, method=1):
''' Return True if the tree is balanced'''
if method == 1:
''' O(n2)'''
return self.root._isBalanced()
else:
''' O(n)'''
return self.root._isBalancedImproved()
''' The followin methods are for searching the lowest common ancestor
in a BT. Since a simple BT does not have ordering, it can be O(n). If
we have a link for the ancestors, the steps are:
(1) search both trees in order to find the nodes separately
(2) list all ancestors
(3) find first that mach
obs: if we do this too many times we can do a pre and use the methods here'''
def isBST(self, method=1):
''' Return True if the tree is BST'''
if method == 1:
inorder = self.root._printDFTinOrder(self.root)
return inorder == sorted(inorder)
elif method == 2:
return self.root._isBST()
def _getAncestorPreIn(self, preorder, inorder, value1, value2):
''' Return the ancestor of two nodes with pre and in'''
root = preorder[0]
preorder = preorder[1:]
i = 0
item = inorder[0]
value1left, value2left = False, False
while item != root and i < len(inorder):
if item == value1: value1left = True
elif item == value2: value2left = True
i += 1
item = inorder[i]
if (value1left and not value2left) or (value2left and not value1left):
return root
else:
return self._getAncestorPreIn(preorder, inorder[:i] + inorder[i+1:], value1, value2)
def _getAncestorPrePost(self, preorder, postorder, value1, value2):
''' Return the ancestor of two nodes with pre and post'''
root = preorder[0]
preorder = preorder[1:]
postorder = postorder[:-1]
value1right, value2right = False, False
i = len(postorder)-1
itempre = preorder[0]
itempos = postorder[i]
while itempre != itempos and i > 0:
if itempos == value1: value1right = True
elif itempos == value2: value2right = True
i -= 1
itempos = postorder[i]
if (value1right and not value2right) or (value2right and not value1right):
return root
else:
return self._getAncestorPrePost(preorder, postorder[:i] + postorder[i+1:], value1, value2)
def _getAncestorInPost(self, inorder, postorder, value1, value2):
''' Return the ancestor of two nodes with in and post'''
root = postorder[-1]
postorder = postorder[:-1]
value1left, value2left = False, False
i = 0
item = inorder[i]
while item != root and i < len(inorder):
if item == value1: value1left = True
elif item == value2: value2left = True
i += 1
item = inorder[i]
if (value1left and not value2left) or (value2left and not value1left):
return root
else:
return self._getAncestorInPost(postorder, inorder[:i] + inorder[i+1:], value1, value2)
def _getAncestorBST2(self, preorder, value1, value2):
''' Return the ancestor of two nodes if it is a bst, using traversal'''
while preorder:
current = preorder[0]
if current < value1:
try: preorder = preorder[2:]
except: return current
elif current > value2:
try: preorder = preorder[1:]
except: return current
elif value1 <= current <= value2:
return current
return None
def getAncestor(self, value1, value2, method='pre-in'):
''' Return the commom ancestor for two nodes'''
if method == 'pre-in':
''' Using pre and inorder, best/worst O(n)'''
preorder = self.root._printDFTpreOrder(self.root)
inorder = self.root._printDFTinOrder(self.root)
return self._getAncestorPreIn(preorder, inorder, value1, value2)
if method == 'pre-post':
''' Using pre and postorder, best/worst O(n)'''
preorder = self.root._printDFTpreOrder(self.root)
postorder = self.root._printDFTpostOrder(self.root)
return self._getAncestorPrePost(preorder, postorder, value1, value2)
if method == 'post-in':
''' Using in and postorder, best/worst O(n)'''
inorder = self.root._printDFTinOrder(self.root)
postorder = self.root._printDFTpostOrder(self.root)
return self._getAncestorInPost(inorder, postorder, value1, value2)
if method == 'bst':
if self.isBST():
return self.root._getAncestorBST(value1, value2)
#preorder = self.root._printDFTpreOrder(self.root)
#return self._getAncestorBST2(preorder, value1, value2)
else:
return Exception('The tree is not a BST')
if __name__ == '__main__':
import doctest
doctest.testmod()

View file

@ -0,0 +1,131 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
from BST import BST
from collections import deque
class TranversalBST(object):
def __init__(self):
self.bst = BST(None)
self.nodes = []
def insert(self, value):
if not self.bst.value:
self.bst.value = value
else:
self.bst.insert(value)
def contains(self, value):
return bool(self.bst.find(value))
def get(self, index):
for i, value in enumerate(self.inorder()):
if i == index:
return value
def inorder(self):
current = self.bst
self.nodes = []
stack = []
while len(stack) > 0 or current is not None:
if current is not None:
stack.append(current)
current = current.left
else:
current = stack.pop()
self.nodes.append(current.value)
current = current.right
return self.nodes
def preorder(self):
self.nodes = []
stack = [self.bst]
while len(stack) > 0:
curr = stack.pop()
if curr is not None:
self.nodes.append(curr.value)
stack.append(curr.right)
stack.append(curr.left)
return self.nodes
def preorder2(self):
self.nodes = []
current = self.bst
stack = []
while len(stack) > 0 or current is not None:
if current is not None:
self.nodes.append(current.value)
stack.append(current)
current = current.left
else:
current = stack.pop()
current = current.right
return self.nodes
def preorder3(self):
self.nodes = []
node = self.bst
if not node: return None
stack = []
stack.append(node)
while stack:
node = stack.pop()
self.nodes.append(node.value)
if node.right: stack.append(node.right) # RIGHT FIRST!
if node.left: stack.append(node.left)
return self.nodes
def BFT(self):
self.nodes = []
node = self.bst
if not node: return None
queue = deque()
queue.append(node)
while queue:
node = queue.popleft()
self.nodes.append(node.value)
if node.left: queue.append(node.left) # LEFT FIRST!
if node.right: queue.append(node.right)
return self.nodes
def main():
"""
10
5 15
1 6 11 50
"""
t = TranversalBST()
t.insert(10)
t.insert(5)
t.insert(15)
t.insert(1)
t.insert(6)
t.insert(11)
t.insert(50)
print(t.preorder())
print(t.preorder2())
print(t.preorder3())
print(t.inorder())
print(t.BFT())
'''
[10, 5, 1, 6, 15, 11, 50]
[10, 5, 1, 6, 15, 11, 50]
[10, 5, 1, 6, 15, 11, 50]
[1, 5, 6, 10, 11, 15, 50]
[10, 5, 15, 1, 6, 11, 50]
'''
if __name__ == '__main__':
main()

View file

@ -0,0 +1,44 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
'''
Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n).
If d(a) = b and d(b) = a, where a b, then a and b are an amicable pair and each of a and b are called amicable numbers.
For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110; therefore d(220) = 284. The proper divisors of 284 are 1, 2, 4, 71 and 142; so d(284) = 220.
Evaluate the sum of all the amicable numbers under 10000.
'''
def find_sum_proper_divisors(n):
sum_proper_div = 0
for i in range(1, n):
if n%i == 0:
sum_proper_div += i
return sum_proper_div
def amicable_numbers(N):
sum_div_list = [find_sum_proper_divisors(i) for i in range(1, N+1)]
sum_amicable_numbers = 0
set_div = set()
for a in range(1, N):
da = sum_div_list[a-1]
if da < N:
b = da
db = sum_div_list[b-1]
if a != b and db == a and a not in set_div and b not in set_div:
sum_amicable_numbers += a + b
set_div.add(a)
set_div.add(b)
return sum_amicable_numbers
def main():
print(amicable_numbers(10000))
print('Tests Passed!')
if __name__ == '__main__':
main()

View file

@ -0,0 +1,91 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def isPrime(n):
n = abs(int(n))
if n < 2:
return False
if n == 2:
return True
for x in range(2, int(n**0.5)+1):
if n%x == 0:
return False
return True
def findPermutations(s):
res = []
if len(s) == 1:
res.append(s)
else:
for i, c in enumerate(s):
for perm in findPermutations(s[:i] + s[i+1:]):
res.append(c + perm)
return res
def isCircular(n):
n_str = str(n)
permutations = findPermutations(n_str)
for perm in permutations:
if not isPrime(perm):
return False
return True
def generatePrimes(n):
if n == 2: return [2]
elif n < 2: return []
s = [i for i in range(3, n+1, 2)]
mroot = n ** 0.5
half = (n+1)//2 - 1
i, m = 0, 3
while m <= mroot:
if s[i]:
j = (m*m-3)//2
s[j] = 0
while j < half:
s[j] = 0
j += m
i = i+1
m = 2*i+3
return [2]+[x for x in s if x]
def generate_n_Primes(n):
primes = []
chkthis = 2
while len(primes) < n:
ptest = [chkthis for i in primes if chkthis%i == 0]
primes += [] if ptest else [chkthis]
chkthis += 1
return primes
def circular_primes(n):
primes = generatePrimes(n)
count = 0
for prime in primes:
if isCircular(prime):
count += 1
return count
def main():
import time
start = time.time()
print(circular_primes(1000000))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,65 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
'''
1 Jan 1900 was a Monday.
Thirty days has September,
April, June and November.
All the rest have thirty-one,
Saving February alone,
Which has twenty-eight, rain or shine.
And on leap years, twenty-nine.
A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.
How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?
'''
def find_if_leap_year(y):
if (y%4 == 0 and y%100 != 0) or (y%400 == 0):
return True
return False
def counting_sundays():
''' define variables '''
days_year = 7*31 + 4*30 + 28
count_sundays = 0
days_week = 7
dict_week = {0: 'mon', 1:'tue', 2:'wed', 3:'thu', 4:'fri', 5:'sat', 6:'sun'}
''' with info from 1900 find first day for 1901 '''
first_day = days_year%days_week # not a leap year
for y in range (1901, 2001):
leap_year = find_if_leap_year(y)
days_count = first_day
for m in range(1, 13):
if days_count%7 == 6:
count_sundays += 1
if m == 2:
if leap_year:
days_count += 29
else:
days_count += 28
elif m == 4 or m == 6 or m == 9 or m == 11:
days_count += 30
else:
days_count += 31
if leap_year: first_day = (first_day +2)%days_week
else: first_day = (first_day +1)%days_week
return count_sundays
def main():
print(counting_sundays())
print('Tests Passed!')
if __name__ == '__main__':
main()

View file

@ -0,0 +1,30 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def digit_fifth_pow(n):
lnum = []
for num in range(10**(2), 10**(n+2)):
sum_here = 0
num_str = str(num)
for i in num_str:
num_int = int(i)
num_int_pow = num_int**n
sum_here += num_int_pow
if sum_here == num:
lnum.append(num)
return lnum, sum(lnum)
def main():
import time
start = time.time()
print(digit_fifth_pow(5))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,27 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def dist_pow(a1, a2, b1, b2):
set1 = set()
for a in range(a1, a2 + 1):
for b in range(b1, b2 + 1):
set1.add(a**b)
return len(set1)
def main():
import time
start = time.time()
print(dist_pow(2, 5, 2, 5))
print(dist_pow(2, 100, 2, 100))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,18 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def even_fib_num(limit):
a, b = 0, 1
while a < limit:
yield a
a, b = b, a + b
def main():
print(sum(n for n in even_fib_num(4e6) if not (n & 1)))
print('Tests Passed!')
if __name__ == '__main__':
main()

View file

@ -0,0 +1,32 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def factorial(n):
prod = 1
for i in range(1,n):
prod *= i
return prod
def find_sum(n):
sum_ = 0
fact = factorial(n)
number = str(fact)
for i in number:
sum_ += int(i)
return sum_
def main():
import time
start = time.time()
assert(find_sum(10) == 27)
print(find_sum(100))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,32 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
import math
def is_prime(number, prime_set):
if number in prime_set: return True
for i in range(2, int(math.sqrt(number)) + 1):
if not number%i: return False
return True
def findstprime(n):
count = 0
candidate = 1
prime_set = set()
while count < n:
candidate +=1
if is_prime(candidate, prime_set):
prime_set.add(candidate)
count += 1
return candidate
def main():
assert(findstprime(6 == 13))
print(findstprime(10001))
print('Tests Passed!')
if __name__ == '__main__':
main()

View file

@ -0,0 +1,64 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def isPrime(n):
n = abs(int(n))
if n < 2:
return False
if n == 2:
return True
if not n & 1:
return False
for x in range(3, int(n**0.5)+1, 2):
if n % x == 0:
return False
return True
def generetePrimes(n):
if n == 2: return [2]
elif n < 2: return []
s = [i for i in range(3, n+1,2)]
mroot = n ** 0.5
half = (n+1)//2-1
i = 0
m = 3
while m <= mroot:
if s[i]:
j = (m*m - 3)//2
s[j] = 0
while j < half:
s[j] = 0
j += m
i = i+1
m = 2*i+3
return [2]+[x for x in s if x]
def gold_other(n):
primes_for_n = generetePrimes(n)
numbers = {prime + 2*x**2 for prime in primes_for_n for x in range(1, int(n**0.5))}
conj = {x for x in range(3, n, 2) if not isPrime(x)}
while True:
candidates = conj - numbers
if not candidates:
gold_other(2*n)
else:
return min(candidates)
def main():
import time
start = time.time()
print(gold_other(10000))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,43 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
import math
def find_div(n):
''' find the divisor of a given n'''
set_div = {1, n}
for i in range(2, int(math.sqrt(n))+ 1):
if not n % i:
set_div.add(i)
set_div.add(n//i)
l1 = list(set_div)
return len(l1)
def find_trian(l):
''' find the lth trian number'''
return sum(range(1, l+1))
def highly_divisible_trian_num(d):
thtriangle, n_div, count = 1, 0, 1
while n_div < d:
count += 1
thtriangle += count
n_div = find_div(thtriangle)
return (thtriangle, count)
def main():
import time
start = time.time()
assert(highly_divisible_trian_num(6) == (28, 7))
print(highly_divisible_trian_num(500))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,47 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def is_palindrome(s):
return s == reverse(s)
def reverse(s):
rev = 0
while s > 0:
rev = 10*rev + s%10
s = s//10
return rev
def is_palindrome_2(s):
# to use it you need to cast str() first
while s:
if s[0] != s[-1]: return False
else:
s = s[1:-1]
is_palindrome(s)
return True
def larg_palind_product(n):
nmax, largpal = 9, 0
for i in range(1, n):
nmax += 9*10**i
for i in range(nmax, nmax//2, -1):
for j in range(i -1, (i -1)//2, -1):
candidate = i*j
if is_palindrome(candidate) and candidate > largpal:
largpal = candidate
return largpal
def test_larg_palind_product():
assert(larg_palind_product(2)== 9009)
print(larg_palind_product(3))
print('Tests Passed!')
if __name__ == '__main__':
test_larg_palind_product()

View file

@ -0,0 +1,20 @@
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48

View file

@ -0,0 +1,66 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
import string
def get_grid(filename):
grid = [ [ 0 for i in range(20) ] for j in range(20) ]
with open(filename) as file:
for row, line in enumerate(file):
line.strip('\n')
for collumn, number in enumerate(line.split(' ')):
grid[row][collumn] = int(number)
return grid
def larg_prod_grid(grid):
row, col, larg_prod = 0, 0, 0
up, down, left, right, diag1, diag2, diag3, diag4 = 0, 0, 0, 0, 0, 0, 0, 0
while row < len(grid):
while col < len(grid[0]):
if col > 2:
up = grid[row][col] * grid[row][col-1] * grid[row][col-2] * grid[row][col-3]
if col < len(grid[0]) - 3:
down = grid[row][col] * grid[row][col+1] * grid[row][col+2] * grid[row][col+3]
if row > 2:
left = grid[row][col] * grid[row-1][col] * grid[row-2][col] * grid[row-3][col]
if row < len(grid) - 3:
right = grid[row][col] * grid[row+1][col] * grid[row+2][col] * grid[row+3][col]
if col > 2 and row > 2:
diag1 = grid[row][col] * grid[row-1][col-1] * grid[row-2][col-2] * grid[row-3][col-3]
if col > 2 and row < len(grid) - 3:
diag2 = grid[row][col] * grid[row+1][col-1] * grid[row+2][col-2] * grid[row+3][col-3]
if col < len(grid[0]) - 3 and row > 2:
diag3 = grid[row][col] * grid[row-1][col+1] * grid[row-2][col+2] * grid[row-3][col+3]
if col < len(grid[0]) -3 and row < len(grid) - 3:
down = grid[row][col] * grid[row+1][col+1] * grid[row+1][col+2] * grid[row+1][col+3]
l1 = [up, down, left, right, diag1, diag2, diag3, diag4]
largest_prod_here = max(l1)
if largest_prod_here > larg_prod:
larg_prod = largest_prod_here
col += 1
col = 0
row += 1
return larg_prod
def main():
import time
start = time.time()
filename = 'larg_prod_grid.dat'
grid = get_grid(filename)
assert((grid[6][8], grid[7][9], grid[8][10], grid[9][11]) == (26, 63, 78, 14))
print(larg_prod_grid(grid))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,100 @@
37107287533902102798797998220837590246510135740250
46376937677490009712648124896970078050417018260538
74324986199524741059474233309513058123726617309629
91942213363574161572522430563301811072406154908250
23067588207539346171171980310421047513778063246676
89261670696623633820136378418383684178734361726757
28112879812849979408065481931592621691275889832738
44274228917432520321923589422876796487670272189318
47451445736001306439091167216856844588711603153276
70386486105843025439939619828917593665686757934951
62176457141856560629502157223196586755079324193331
64906352462741904929101432445813822663347944758178
92575867718337217661963751590579239728245598838407
58203565325359399008402633568948830189458628227828
80181199384826282014278194139940567587151170094390
35398664372827112653829987240784473053190104293586
86515506006295864861532075273371959191420517255829
71693888707715466499115593487603532921714970056938
54370070576826684624621495650076471787294438377604
53282654108756828443191190634694037855217779295145
36123272525000296071075082563815656710885258350721
45876576172410976447339110607218265236877223636045
17423706905851860660448207621209813287860733969412
81142660418086830619328460811191061556940512689692
51934325451728388641918047049293215058642563049483
62467221648435076201727918039944693004732956340691
15732444386908125794514089057706229429197107928209
55037687525678773091862540744969844508330393682126
18336384825330154686196124348767681297534375946515
80386287592878490201521685554828717201219257766954
78182833757993103614740356856449095527097864797581
16726320100436897842553539920931837441497806860984
48403098129077791799088218795327364475675590848030
87086987551392711854517078544161852424320693150332
59959406895756536782107074926966537676326235447210
69793950679652694742597709739166693763042633987085
41052684708299085211399427365734116182760315001271
65378607361501080857009149939512557028198746004375
35829035317434717326932123578154982629742552737307
94953759765105305946966067683156574377167401875275
88902802571733229619176668713819931811048770190271
25267680276078003013678680992525463401061632866526
36270218540497705585629946580636237993140746255962
24074486908231174977792365466257246923322810917141
91430288197103288597806669760892938638285025333403
34413065578016127815921815005561868836468420090470
23053081172816430487623791969842487255036638784583
11487696932154902810424020138335124462181441773470
63783299490636259666498587618221225225512486764533
67720186971698544312419572409913959008952310058822
95548255300263520781532296796249481641953868218774
76085327132285723110424803456124867697064507995236
37774242535411291684276865538926205024910326572967
23701913275725675285653248258265463092207058596522
29798860272258331913126375147341994889534765745501
18495701454879288984856827726077713721403798879715
38298203783031473527721580348144513491373226651381
34829543829199918180278916522431027392251122869539
40957953066405232632538044100059654939159879593635
29746152185502371307642255121183693803580388584903
41698116222072977186158236678424689157993532961922
62467957194401269043877107275048102390895523597457
23189706772547915061505504953922979530901129967519
86188088225875314529584099251203829009407770775672
11306739708304724483816533873502340845647058077308
82959174767140363198008187129011875491310547126581
97623331044818386269515456334926366572897563400500
42846280183517070527831839425882145521227251250327
55121603546981200581762165212827652751691296897789
32238195734329339946437501907836945765883352399886
75506164965184775180738168837861091527357929701337
62177842752192623401942399639168044983993173312731
32924185707147349566916674687634660915035914677504
99518671430235219628894890102423325116913619626622
73267460800591547471830798392868535206946944540724
76841822524674417161514036427982273348055556214818
97142617910342598647204516893989422179826088076852
87783646182799346313767754307809363333018982642090
10848802521674670883215120185883543223812876952786
71329612474782464538636993009049310363619763878039
62184073572399794223406235393808339651327408011116
66627891981488087797941876876144230030984490851411
60661826293682836764744779239180335110989069790714
85786944089552990653640447425576083659976645795096
66024396409905389607120198219976047599490197230297
64913982680032973156037120041377903785566085089252
16730939319872750275468906903707539413042652315011
94809377245048795150954100921645863754710598436791
78639167021187492431995700641917969777599028300699
15368713711936614952811305876380278410754449733078
40789923115535562561142322423255033685442488917353
44889911501440648020369068063960672322193204149535
41503128880339536053299340368006977710650566631954
81234880673210146739058568557934581403627822703280
82616570773948327592232845941706525094512325230608
22918802058777319719839450180888072429661980811197
77158542502016545090413245809786882778948721859617
72107838435069186155435662884062257473692284509516
20849603980134001723930671666823555245252804609722
53503534226472524250874054075591789781264330331690

View file

@ -0,0 +1,25 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def large_sum(filename):
sum_total, lines, numbers = 0, 0, 0
with open(filename) as file:
for line in file:
sum_total += int(line.strip('\n'))
return str(sum_total)[0:10]
def main():
import time
start = time.time()
filename = 'large_sum.dat'
print(large_sum(filename))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,41 @@
#!/usr/bin/python3
#!/usr/bin/python3
def is_prime(n):
if n < 4 : return True
for i in range(2, int(n**0.5 + 1)):
if not n%i: return False
return True
def largest_prime_factor(n):
i = int(n**0.5 +1)
while i > 1 :
if not n%i and i&1:
if is_prime(i): return i
i -= 1
return None
def largest_prime_factor_optimized(n):
factor = 2
lastfactor = 1
while n > 1:
if not n%factor:
lastfactor = factor
n = n//factor
while n%factor == 0:
n = n//factor
factor += 1
return lastfactor
def test_largest_prime_factor():
assert(largest_prime_factor(13195)== 29)
print(largest_prime_factor(600851475143))
assert(largest_prime_factor_optimized(13195) == 29)
print(largest_prime_factor_optimized(600851475143))
print('Tests Passed!')
if __name__ == '__main__':
test_largest_prime_factor()

View file

@ -0,0 +1,28 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def largest_prod_seq(n):
result = 0
for i in range(0, len(n)-4):
first = int(n[i])
second = int(n[i+1])
third = int(n[i+2])
fourth = int(n[i+3])
fifth = int(n[i+4])
result_here = first*second*third*fourth*fifth
if result < result_here:
result = result_here
return result
def main():
n = '7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450'
print(largest_prod_seq(n))
print('Tests Passed!')
if __name__ == '__main__':
main()

View file

@ -0,0 +1,42 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def lattice_paths(squares):
gridsize = squares+1
grid = [[0 for i in range(gridsize)] for j in range(gridsize)]
row, col = 0, 0
while col < gridsize:
while row < gridsize:
if row == 0 and col == 0:
grid[row][col] = 1
else:
if row == 0 and col != 0:
grid[row][col] += grid[row][col-1]
elif row != 0 and col == 0:
grid[row][col] += grid[row-1][col]
else:
grid[row][col] += grid[row][col-1] + grid[row-1][col]
row += 1
row = 0
col += 1
return grid[gridsize-1][gridsize-1]
def main():
import time
start = time.time()
assert(lattice_paths(2) == 6)
print(lattice_paths(20))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,33 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def perm_item(elements):
if len(elements) <= 1:
yield elements
else:
for (index, elmt) in enumerate(elements):
other_elmts = elements[:index]+elements[index+1:]
for permutation in perm_item(other_elmts):
yield [elmt] + permutation
def lex_perm(l1, n):
perm_list = list(perm_item(l1))
return sorted(perm_list)[n-1]
def main():
import time
start = time.time()
l1 = [0,1,2,3,4,5,6,7,8,9]
n = 10**6
print(lex_perm(l1, n))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,43 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def find_coll_seq(n):
count = 1
while n > 1:
if n%2 == 0:
n = n//2
else:
n = 3*n +1
count += 1
return count
def find_longest_chain(limit):
longest, number = 0, 0
start = 0
while start <= limit:
size_chain = find_coll_seq(start)
if size_chain > longest:
longest = size_chain
number = start
start += 1
return (longest, number)
def main():
import time
start = time.time()
#print(find_longest_chain(13))
print(find_longest_chain(10**6))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,15 @@
75
95 64
17 47 82
18 35 87 10
20 04 82 47 65
19 01 23 75 03 34
88 02 77 73 07 63 67
99 65 04 28 06 16 70 92
41 41 26 56 83 40 80 70 33
41 48 72 33 47 32 37 16 94 29
53 71 44 65 25 43 91 52 97 51 14
70 11 33 28 77 73 17 78 39 68 17 57
91 71 52 38 17 14 91 43 58 50 27 29 48
63 66 04 68 89 53 67 30 73 16 69 87 40 31
04 62 98 27 23 09 70 98 73 93 38 53 60 04 23

View file

@ -0,0 +1,55 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def max_path_sum(t):
root = t[0][0]
height, width, index, large_num = 1, 0, 0, 0
max_sum = root
heights = len(t[:])
while height < heights:
values_here = t[height][index:index+2]
if values_here[0] > values_here[1]:
large_num = values_here[0]
else:
large_num = values_here[1]
index += 1
max_sum += large_num
pivot = large_num
width, large_num = 0, 0
height += 1
return max_sum
def edit_input(filename):
output = []
with open(filename) as file:
for line in file:
line = line.rstrip('\n')
output.append(line.split(' '))
for i, l1 in enumerate(output):
for j, c in enumerate(output[i]):
output[i][j] = int(c)
return(output)
def main():
import time
start = time.time()
filename = 'max_path_sum0.dat'
t1 = edit_input(filename)
print('Little pir: ',max_path_sum(t1))
filename = 'max_path_sum.dat'
t2 = edit_input(filename)
print('Big pir: ', max_path_sum(t2))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,4 @@
3
7 4
2 4 6
8 5 9 3

View file

@ -0,0 +1,22 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def mul3and5(n):
result = 0
for num in range(1, n):
if num%3 == 0 or num%5 == 0:
result += num
return result
def test_():
assert(mul3and5(10) == 23)
print(mul3and5(1000))
print('Tests Passed!')
if __name__ == '__main__':
test_()

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,33 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def calculate_score(name, dict_letters):
sum_letters = 0
for letter in name:
sum_letters += dict_letters[letter]
return sum_letters
def names_score(filename):
dict_letters ={'A':1,'B':2,'C':3,'D':4,'E':5,'F':6,'G':7,'H':8,'I':9,'J':10,'K':11,'L':12,'M':13,'N':14,'O':15,'P':16,'Q':17,'R':18,'S':19, 'T':20,'U':21,'V':22,'W':23,'X':24,'Y':25,'Z':26}
total_score = 0
with open(filename) as file:
for line in file:
names = [name.strip('"') for name in line.split(',')]
names.sort()
for i, name in enumerate(names):
total_score += (i+1)* calculate_score(name, dict_letters)
return total_score
def main():
filename = 'names.txt'
print(names_score(filename))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,44 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def find_sum_proper_div(n):
sum_proper_div = 0
for i in range(1, n):
if n%i == 0:
sum_proper_div += i
return sum_proper_div
def find_all_abund(n):
sum_div_list = [find_sum_proper_div(i) for i in range(n)]
abu = set()
for i in range(n):
if i < sum_div_list[i]:
abu.add(i)
return abu
def non_abund_sums(n):
abu = find_all_abund(n)
sum_nom_abu = 0
for i in range(n):
if not any( (i-a in abu) for a in abu):
sum_nom_abu += i
return sum_nom_abu
def test_():
r = set([i for i in range(25)])
r_abu = {24}
r = r - r_abu
assert(non_abund_sums(25) == sum(r))
print(non_abund_sums(28123))
print('Tests Passed!')
if __name__ == '__main__':
test_()

View file

@ -0,0 +1,63 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def number_letter_counts(n):
dict_lett = build_dict(n)
sum_letter = 0
for item in dict_lett:
sum_letter += dict_lett[item]
return sum_letter
def build_dict(n):
lett_dict = {}
numbers = (x for x in range(1, n+1))
dec = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen']
ties = ['twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety']
for number in numbers:
if 1 <= number < 20:
lett_dict[number] = len(dec[number-1])
elif 20 <= number < 100:
index_dec = number//10
index_num = number%10
if index_num == 0:
lett_dict[number] = len(ties[index_dec-2])
else:
lett_dict[number] = len(ties[index_dec-2]) + len(dec[index_num-1])
elif 100 <= number < 1000:
index_hun = number//100
index_dec = number%100
if index_dec == 0:
lett_dict[number] = len(dec[index_hun-1]) + len('hundred')
else:
if 1 <= index_dec < 20:
lett_dict[number] = len(dec[index_hun-1]) + len('hundred') + len('and') + len(dec[index_dec-1])
elif 20 <= index_dec < 100:
index_dec2 = index_dec//10
index_num = index_dec%10
if index_num == 0:
lett_dict[number] = len(dec[index_hun-1]) + len('hundred') + len('and') + len(ties[index_dec2-2])
else:
lett_dict[number] = len(dec[index_hun-1]) + len('hundred') + len('and') + len(ties[index_dec2-2]) + len(dec[index_num-1])
elif number == 1000:
lett_dict[number] = len('onethousand')
return lett_dict
def main():
import time
start = time.time()
assert(number_letter_counts(5) == 19)
print(number_letter_counts(1000))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,39 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def number_spiral(spiral):
return rows, mid
def make_spiral(n):
spiral = []
row = rows//2
col = col//2
count = 1
while row < n:
while col < n:
spiral[col][row] = count
count += 1
if count%2 == 0:
col += 1
else:
row += 1
return spiral
def main():
import time
start = time.time()
n = 5
spiral = make_spiral(n)
print(number_spiral(spiral))# 101
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,28 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def path_sum_two_ways(m1):
paths = []
row, col = 0, 0
p = len(m1)
while row < len(m1):
print(m1[0:p])
while p:
aux = sum([x for x in m1[0:p]])
paths.append(aux)
p -= 1
row += 1
return max(paths)
def main():
m1 = [[131, 673, 234, 103, 18], [201, 96, 342, 965, 150], [630, 803, 746, 422, 111], [537, 699, 497, 121, 956], [805, 732, 524, 37, 331]]
print(path_sum_two_ways(m1))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,22 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def power_digit_sum(n):
number = str(2**n)
sum_res = 0
for i in number:
sum_res += int(i)
return sum_res
def test_():
assert(power_digit_sum(15) == 26)
print(power_digit_sum(1000))
print('Tests Passed!')
if __name__ == '__main__':
test_()

View file

@ -0,0 +1,50 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def quad_form(n, a, b):
return n**2 + a*n + b
def isPrime(n):
n = abs(int(n))
if n < 2:
return False
if n == 2:
return True
if not n & 1:
return False
for x in range(3, int(n**0.5)+1, 2):
if n % x == 0:
return False
return True
def quad_primes(a, b):
count_max = 0
coef = ()
for aa in range(-a, a):
for bb in range(-b, b):
n = 0
while True:
number = quad_form(n, aa, bb)
if isPrime(number):
n += 1
else:
if n > count_max:
count_max = n
coef = (aa, bb)
break
return coef(0)*coef(1), coef
def main():
import time
start = time.time()
print(quad_primes(1000, 1000))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,29 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def self_powers(power, digits):
sum_total = 0
for pow in range(1, power+1):
sum_total += pow**pow
sum_total_str = str(sum_total)
last_digits = ''
for i, c in enumerate(sum_total_str[-digits:]):
last_digits += c
return int(last_digits)
def main():
import time
start = time.time()
assert(self_powers(10, len('10405071317')) == 10405071317)
print(self_powers(1000, 10))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,32 @@
#!/usr/bin/python3
def smallest_multiple(n):
set1 = set([x for x in range(1, n+1)])
set2 = set()
for i in range(len(set1), 0, -1):
for j in range(1, i):
if i%j == 0:
set2.add(j)
set1 = set1 - set2
res_num = n*n
while True:
for i in set1:
missing_div = False
if res_num%i:
missing_div = True
shift = res_num%i
break
if not missing_div: return res_num
res_num += 1 or shift
shift = 0
def test_():
assert(smallest_multiple(10) == 2520)
print(smallest_multiple(20))
print('Tests Passed!')
if __name__ == '__main__':
test_()

View file

@ -0,0 +1,26 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def special_pyt(n):
for i in range(3, n):
for j in range(i+1, n):
c = calc_c(i,j)
if i + j + c == n:
return i*j*c
def calc_c(a, b):
return (a**2 + b**2)**0.5
def main():
assert(special_pyt(3+4+5) == (3*4*5))
print(special_pyt(1000))
print('Tests Passed!')
if __name__ == '__main__':
main()

View file

@ -0,0 +1,38 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def calculate_chain(n):
n_str = str(n)
while n_str != 1 or n_str != 89:
n_str = str(n_str)
sum_here = 0
for d in n_str:
sum_here += int(d)**2
n_str = sum_here
if n_str == 89:
return 1
if n_str == 1:
return 0
def square_dig_chains(n):
count = 0
for i in range(1, n+1):
count += calculate_chain(i)
return count
def main():
import time
start = time.time()
print(square_dig_chains(10**7))
elapsed = (time.time() - start)
print('Tests Passed!\n It took %s seconds to run them.' % (elapsed))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,21 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def sum_square_diff(n):
sq_sum, sum_sq = 0, 0
for i in range(1, n+1):
sum_sq += i**2
sq_sum += i
sq_sum = sq_sum **2
return sq_sum - sum_sq
def main():
assert(sum_square_diff(10) == 2640)
print(sum_square_diff(100))
print('Tests Passed!')
if __name__ == '__main__':
main()

View file

@ -0,0 +1,24 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
from findstprime import is_prime
def summation_primes(n):
candidate = 2
prime_set = set()
while candidate < n:
if is_prime(candidate, prime_set):
prime_set.add(candidate)
candidate +=1
return sum(prime_set)
def main():
assert(summation_primes(10) == 17)
print(summation_primes(2000000))
print('Tests Passed!')
if __name__ == '__main__':
main()

View file

@ -0,0 +1,70 @@
#!/usr/bin/python3
# mari von steinkirch @2013
# steinkirch at gmail
def findToneDiff(tones):
tonesDiff = []
n = len(tones)
for i, tone in enumerate(tones):
for j in range(i+1, len(tones)):
sum_here = abs(tone - tones[j])
tonesDiff.append([sum_here, i, j])
return sorted(tonesDiff)
def findAllPossible(duration, tones, T):
tonesDiff = findToneDiff(tones)
sumsTone1 = [(song, i) for i, song in enumerate(duration) if song <= T]
sumsTone2 = []
for song in tonesDiff:
sum_here = song[0] + duration[song[1]] + duration[song[2]]
if sum_here <= T:
sumsTone2.append((sum_here, song[1], song[2], 2))
return sumsTone1, sumsTone2
def findAllPossibleNext(sumsTone, T, n_music):
sumsTone2 = []
for i, song1 in enumerate(sumsTone):
index1 = song1[1]
for j in range(i+1, len(sumsTone)):
song2 = sumsTone[j]
index2 = song2[1]
if index1 == index2:
sum_here = song1[0] + song2[0]
if sum_here < T:
sumsTone2.append((sum_here, song2[1], song2[2], n_music))
return sumsTone2
def maxSongs(duration, tones, T):
if min(duration) >= T:
return 0
sumsTone1, sumsTone = findAllPossible(duration, tones, T)
if not sumsTone:
return 1
while sumsTone:
n_music = sumsTone[0][3]+1
sumsTone = findAllPossibleNext(sumsTone, T, n_music)
if not sumsTone:
return n_music
def tests_250():
print(maxSongs([3, 5, 4, 11], [2, 1, 3, 1], 17)) #3
print(maxSongs([9, 11, 13, 17], [2, 1, 3, 4], 20)) #1
print(maxSongs([100, 200, 300], [1,2,3], 99)) #0
print(maxSongs([87,21,20,73,97,57,12,80,86,97,98,85,41,12,89,15,41,17,68,37,21,1,9,65,4,67,38,91,46,82,7,98,21,70,99,41,21,65,11,1,8,12,77,62,52,69,56,33,98,97], [88,27,89,2,96,32,4,93,89,50,58,70,15,48,31,2,27,20,31,3,23,86,69,12,59,61,85,67,77,34,29,3,75,42,50,37,56,45,51,68,89,17,4,47,9,14,29,59,43,3], 212))
if __name__ == '__main__':
tests_250()