-
Notifications
You must be signed in to change notification settings - Fork 0
/
ctci.py
224 lines (176 loc) · 5.3 KB
/
ctci.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
"""
A collection of solutions to common interview problems.
"""
def permute_string(string):
""" Returns a list of all possible permutations of string
"""
if len(string) == 1:
return [string]
permuted = []
used_chars = []
for idx, char in enumerate(string):
# skip if dupe
if char in used_chars:
continue
used_chars.append(char)
substring = string[0:idx]+string[idx+1:]
for permuted_substring in permute_string(substring):
permuted.append(char+permuted_substring)
return permuted
def rand7_optimized():
""" Given rand5 implement rand7 using bitvector
"""
from random import randint
bitvect = (int(randint(0,5) < 3),
int(randint(0,5) < 3),
int(randint(0,5) < 3))
return(int('{}{}{}'.format(*bitvect),2))
def rand7():
""" Given rand5 implement rand7
"""
from random import randint
count = 0
rand7_dict = {}
for i in range(6):
for j in range(6):
rand7_dict[(i, j)] = count
count += 1
rand5_tup = (randint(0,5), randint(0,5))
while rand7_dict[rand5_tup] >= 32:
rand5_tup = (randint(0,5), randint(0,5))
return rand7_dict[rand5_tup] % 8
class bst(object):
""" Implementation of bst
"""
@staticmethod
def min_node(node):
while node.left is not None:
node = node.left
return node
@staticmethod
def search(node, number):
if number == node.value:
return node
elif number < node.value and node.left is not None:
return bst.search(node.left, number)
elif number > node.value and node.right is not None:
return bst.search(node.right, number)
else:
return
def __init__(self, num):
self.left = None
self.right = None
self.parent = None
self.value = num
def add(self, number):
if self.value is None:
self.value = number
elif number <= self.value:
if self.left is None:
self.left = bst(number)
self.left.parent = self
else:
self.left.add(number)
else:
if self.right is None:
self.right = bst(number)
self.left.parent = self
else:
self.right.add(number)
def remove(self, node):
if node.parent:
if node.parent.value > node.value:
node.parent.left = None
else:
node.parent.right = None
else:
node.value = None
def update_parent(self, parent, node):
if parent.value < node.value:
parent.right = node
else:
parent.left = node
def delete(self, number):
node = bst.search(self, number)
if node is not None:
if node.left is None and node.right is None:
self.remove(node)
elif node.left is not None and node.right is not None:
min_node = bst.min_node(node.right)
node.value = min_node.value
self.remove(min_node)
elif node.left is None:
self.update_parent(node.parent, node.right)
elif node.right is None:
self.update_parent(node.parent, node.left)
# Carbon1
def memoize(func):
import functools
dd = {}
@functools.wraps(func)
def func_wrapped(*args, **kwargs):
if args not in dd:
dd[args] = func(*args, **kwargs)
return dd[args]
return func_wrapped
@memoize
def evens(x):
""" returns true if int x has even number of 1s in binary
"""
if not x:
return True
return bool(x % 2 ^ evens(x/2))
# Carbon2
@memoize
def sieve(upto):
""" The sieve algorithm to get all primes less than 'upto'
"""
from math import sqrt
primes = [2]
possibles = list(range(3, upto, 2))
while primes[-1] < sqrt(upto):
primes.append(possibles[0])
possibles = [x for x in possibles if x % primes[-1]]
return primes + possibles
def mod_exp(m, e, n):
"""
m (int): base
e (int): exponent
n (int): modulo
Perform modulo exponentiation
Returns m**e (mod n)
"""
c = 1
for i in range(e):
c = (c*m) % n
return c
def encrypt(msg):
"""
msg (str): string to be encrypted
Encrypts a string *msg* using RSA-based approach
Returns tuple with public modulo, private key, and encrypted message array
"""
import random
lmsg = list(map(ord, msg))
primes = sieve(1000)[1:]
p = primes[random.randint(0, len(primes)-1)]
primes.remove(p)
q = primes[random.randint(0, len(primes)-1)]
n = p*q
phi = (p-1)*(q-1)
e = max(q,p)
for pr in primes:
if phi % pr:
e = pr
break
for d in range(e, phi, 2):
if (e*d) % phi == 1:
break
return n, d, [mod_exp(imsg, e, n) for imsg in lmsg]
def decrypt(enc):
"""
enc (tuple): first element is public key, second element is
private key, third element the encrypted message array
Returns decrypted message (str)
"""
return ''.join([chr(mod_exp(ienc, enc[1], enc[0])) for ienc in enc[2]])