Skip to content
Open

Day4 #199

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions applications/crack_caesar/crack_caesar.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@

# Use frequency analysis to find the key to ciphertext.txt, and then
# decode it.

# Your code here

import os

f = open(f"{os.getcwd()}/applications/crack_caesar/ciphertext.txt")

text = f.read()
print(text)


letter_frequencies = {'E': 11.53, 'T': 9.75, 'A': 8.46, 'O': 8.08, 'H': 7.71,
'N': 6.73, 'R': 6.29, 'I': 5.84, 'S': 5.56, 'D': 4.74,
'L': 3.92, 'W': 3.08, 'U': 2.59, 'G': 2.48, 'F': 2.42,
'B': 2.19, 'M': 2.18, 'Y': 2.02, 'C': 1.58, 'P': 1.08,
'K': 0.84, 'V': 0.59, 'Q': 0.17, 'J': 0.07, 'X': 0.07,
'Z': 0.03}
13 changes: 11 additions & 2 deletions applications/expensive_seq/expensive_seq.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
# Your code here

dictionary = {}

def expensive_seq(x, y, z):
# Your code here
if (x, y, z) in dictionary:
return dictionary[(x, y, z)]

result = 0
if x <= 0:
result = y + z
if x > 0:
result = expensive_seq(x-1,y+1,z) + expensive_seq(x-2,y+2,z*2) + expensive_seq(x-3,y+3,z*3)

dictionary[(x, y, z)] = result
return result


if __name__ == "__main__":
Expand Down
4 changes: 2 additions & 2 deletions applications/histo/histo.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Your code here

# Your code here
20 changes: 11 additions & 9 deletions applications/lookup_table/lookup_table.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
# Your code here
import math
import random

dictionary = {}

def slowfun_too_slow(x, y):
v = math.pow(x, y)
v = math.factorial(v)
v //= (x + y)
v %= 982451653

return v

def slowfun(x, y):
"""
Rewrite slowfun_too_slow() in here so that the program produces the same
output, but completes quickly instead of taking ages to run.
"""
# Your code here

if (x, y) in dictionary:
return dictionary[(x, y)]
v = math.pow(x, y)
v = math.factorial(v)
v //= (x + y)
v %= 982451653

dictionary[(x, y)] = v
return v

# Do not modify below this line!

Expand Down
1 change: 0 additions & 1 deletion applications/markov/markov.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,3 @@

# TODO: construct 5 random sentences
# Your code here

16 changes: 15 additions & 1 deletion applications/no_dups/no_dups.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
def no_dups(s):
# Your code here
array = []
result_string = ""
split_string = s.split()

if s == "":
return result_string

for word in split_string:
if word not in array:
array.append(word)
result_string += word + " "

if result_string.endswith(" "):
return result_string[:-1]

return result_string


if __name__ == "__main__":
Expand Down
18 changes: 17 additions & 1 deletion applications/word_count/word_count.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
def word_count(s):
# Your code here
dictionary = {}
special_characters = ['"', ":", ";", ",", ".", "-", "+", "=", "/", "|", "[", "]", "{", "}", "(", ")", "*", "^", "&", "\\"]

lower_case = s.lower()

for i in special_characters:
lower_case = lower_case.replace(i, "")

split_string = lower_case.split()
if split_string.count == 0:
return dictionary

for word in split_string:
if word in dictionary:
dictionary[word] += 1
else:
dictionary[word] = 1
return dictionary


if __name__ == "__main__":
Expand Down
126 changes: 98 additions & 28 deletions hashtable/hashtable.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,58 +11,64 @@ def __init__(self, key, value):
# Hash table can't have fewer than this many slots
MIN_CAPACITY = 8

MAX_LOAD_FACTOR = 0.7
MIN_LOAD_FACTOR = 0.2

class HashTable:
"""
A hash table that with `capacity` buckets
that accepts string keys

Implement this.
"""

def __init__(self, capacity):
# Your code here

def __init__(self, capacity=MIN_CAPACITY):
self.capacity = capacity
self.array = [None] * capacity
self.items = 0

def get_num_slots(self):
"""
Return the length of the list you're using to hold the hash
table data. (Not the number of items stored in the hash table,
but the number of slots in the main list.)

One of the tests relies on this.

Implement this.
"""
# Your code here
return self.capacity


def get_load_factor(self):
"""
Return the load factor for this hash table.

Implement this.
"""
# Your code here
return self.items / self.get_num_slots()


def fnv1(self, key):
"""
FNV-1 Hash, 64-bit

Implement this, and/or DJB2.
"""

# Your code here
hash = 14638081039346656478 # Offset

for s in key:
hash = hash * 1099511628211 # FVN prime
hash = hash ^ ord(s)
return hash % len(self.array)


def djb2(self, key):
"""
DJB2 hash, 32-bit

Implement this, and/or FNV-1.
"""
# Your code here
hash = 5381

for x in key:
hash = ((hash << 5) + hash) + ord(x)
return hash & 0xffffffff % self.capacity


def hash_index(self, key):
Expand All @@ -76,45 +82,109 @@ def hash_index(self, key):
def put(self, key, value):
"""
Store the value with the given key.

Hash collisions should be handled with Linked List Chaining.

Implement this.
"""
# Your code here
index = self.hash_index(key)

entry = self.array[index]

if entry is None:
self.array[index] = HashTableEntry(key, value)
self.items += 1
self.resizeIfNeeded()
return

while entry.next != None and entry.key !=key:
entry = entry.next

if entry.key == key:
entry.value = value
else:
entry.next = HashTableEntry(key, value)
self.items += 1
self.resizeIfNeeded()


def delete(self, key):
"""
Remove the value stored with the given key.

Print a warning if the key is not found.

Implement this.
"""
# Your code here
index = self.hash_index(key)

entry = self.array[index]
prev_entry = None

if entry is not None:
while entry.next != None and entry.key != key:
prev_entry = entry
entry = entry.next

if entry.key == key:
if prev_entry is None:
self.array[index] = entry.next
else:
prev_entry.next = entry.next
self.items -= 1
self.resizeIfNeeded()
return

print(f"Warning: Attempted to delete value from HashTable but no value exists for key '{key}'")


def get(self, key):
"""
Retrieve the value stored with the given key.


Returns None if the key is not found.
index = self.hash_index(key)

Implement this.
"""
# Your code here
entry = self.array[index]

if entry is None:
return None

while entry.next != None and entry.key != key:
entry = entry.next

return entry.value if entry.key == key else None


def resizeIfNeeded(self):
if self.get_load_factor () > MAX_LOAD_FACTOR:
self.resize(self.capacity * 2)
elif self.get_load_factor() < MIN_LOAD_FACTOR and int(self.capacity / 2) >= MIN_CAPACITY:
self.resize(int(self.capacity / 2))

def resize(self, new_capacity):
"""
Changes the capacity of the hash table and
rehashes all key/value pairs.

Implement this.
"""
# Your code here

old_array = self.array
self.array = [None] * new_capacity
self.capacity = new_capacity

for old_entry in old_array:
while old_entry is not None:
key = old_entry.key
value = old_entry.value
index = self.hash_index(key)
entry = self.array[index]

# inserts old key/value into resized hash table

if entry is None:
self.array[index] = HashTableEntry(key, value)
else:
while entry.next != None:
entry = entry.next
entry.next = HashTableEntry(key, value)

old_entry = old_entry.next



if __name__ == "__main__":
Expand Down Expand Up @@ -150,4 +220,4 @@ def resize(self, new_capacity):
for i in range(1, 13):
print(ht.get(f"line_{i}"))

print("")
print("")