Skip to content

Commit a79be29

Browse files
authored
Merge pull request #1 from KodingKurriculum/initial-project
Initial project
2 parents 6b38d2e + ad53d4b commit a79be29

20 files changed

Lines changed: 573 additions & 2 deletions

.gitignore

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Byte-compiled / optimized / DLL files
2+
*.pyc
3+
**/__pycache__
4+
*.py[cod]
5+
*$py.class
6+
.spyderproject/
7+
.spyproject/
8+
*.spyderproject
9+
10+
.idea/
11+
~$*
12+
13+
14+
# C extensions
15+
*.so
16+
17+
# Distribution / packaging
18+
.Python
19+
build/
20+
develop-eggs/
21+
dist/
22+
downloads/
23+
eggs/
24+
.eggs/
25+
lib/
26+
lib64/
27+
parts/
28+
sdist/
29+
var/
30+
wheels/
31+
*.egg-info/
32+
.installed.cfg
33+
*.egg
34+
MANIFEST
35+
36+
# PyInstaller
37+
# Usually these files are written by a python script from a template
38+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
39+
*.manifest
40+
*.spec
41+
42+
# Installer logs
43+
pip-log.txt
44+
pip-delete-this-directory.txt
45+
46+
# Unit test / coverage reports
47+
htmlcov/
48+
.tox/
49+
.coverage
50+
.coverage.*
51+
.cache
52+
nosetests.xml
53+
coverage.xml
54+
*.cover
55+
.hypothesis/
56+
.pytest_cache/
57+
58+
# Translations
59+
*.mo
60+
*.pot
61+
62+
# Django stuff:
63+
*.log
64+
local_settings.py
65+
db.sqlite3
66+
67+
# Flask stuff:
68+
instance/
69+
.webassets-cache
70+
71+
# Scrapy stuff:
72+
.scrapy
73+
74+
# Sphinx documentation
75+
docs/_build/
76+
77+
# PyBuilder
78+
target/
79+
80+
# Jupyter Notebook
81+
.ipynb_checkpoints
82+
83+
# pyenv
84+
.python-version
85+
86+
# celery beat schedule file
87+
celerybeat-schedule
88+
89+
# SageMath parsed files
90+
*.sage.py
91+
92+
# Environments
93+
.env
94+
.venv
95+
env/
96+
venv/
97+
ENV/
98+
env.bak/
99+
venv.bak/
100+
101+
# Spyder project settings
102+
.spyderproject
103+
.spyproject
104+
105+
# Rope project settings
106+
.ropeproject
107+
108+
# mkdocs documentation
109+
/site
110+
111+
# mypy
112+
.mypy_cache/

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1-
# level-0-python-coding-interview
2-
A level 0 series of common interview and data structure problems every professional developer should know
1+
# Practice Problems
2+
3+
## Sorting Algorithms
4+
1. Merge Sort
5+
6+

environment.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
name: Practice
2+
channels:
3+
- conda-forge
4+
dependencies:
5+
- plumbum
6+
- pytest

practice_problems/__init__.py

Whitespace-only changes.

practice_problems/graph/__init__.py

Whitespace-only changes.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
from plumbum import cli
2+
from graph import Graph, inf
3+
from collections import deque
4+
import pprint
5+
6+
'''
7+
https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/
8+
https://dev.to/mxl/dijkstras-algorithm-in-python-algorithms-for-beginners-dkc
9+
http://interactivepython.org/courselib/static/pythonds/Graphs/DijkstrasAlgorithm.html
10+
'''
11+
class DijkstrasAlgorithm(cli.Application):
12+
13+
# a - 2 -> b - 7 -> |
14+
# | | 10 |
15+
# | - 9 -> c |
16+
# | | 2 |
17+
# | - 14 -> d <- - - |
18+
19+
_graph = Graph([
20+
("a", "b", 2), ("a", "c", 9), ("b", "c", 10),
21+
("b", "d", 7), ("a", "d", 14), ("c", "d", 2)
22+
])
23+
24+
def main(self):
25+
if list is None or len(self._graph.vertices) is 0:
26+
print("List should have at least one element")
27+
return 1
28+
else:
29+
dijkstras = self.run_dijkstras(self._graph, "a", "d")
30+
pprint.pprint(dijkstras)
31+
32+
def run_dijkstras(self, graph, source, destination):
33+
34+
# 1.) Create a shortest path tree set, initially empty
35+
# Optimization - use a parent path dict to retain previous short path
36+
shortest_path_tree = []
37+
previous_vertices = {vertex: None for vertex in graph.vertices}
38+
39+
# 2.) Creates a map of each vertex (variable) to infinity
40+
# Set the source to 0
41+
distances = {vertex: inf for vertex in graph.vertices}
42+
distances[source] = 0
43+
44+
# 3.) While we have visited all vertices in set
45+
# Technique is to create a copy, and remove from set as its consumed
46+
vertices = graph.vertices.copy()
47+
while vertices:
48+
49+
# 4.) Select node with the minimum distance value
50+
# Once we pull from minimum distance, remove from our vertices
51+
next_node = min(vertices, key=lambda key: distances[key])
52+
vertices.remove(next_node)
53+
54+
# 5.) Add the minimum distance node to set
55+
# ... As long as we're not left with all unreachable vertices
56+
if distances[next_node] == inf:
57+
break
58+
shortest_path_tree.append(next_node)
59+
distance = distances[next_node]
60+
61+
# 6.) Update the distance values the next node's neighbors
62+
neighbors = graph.neighbours[next_node]
63+
for neighbor, cost in neighbors:
64+
neighbor_distance = distance + cost
65+
66+
# ... either if we've found a shorter distance to neighbor
67+
# or we haven't been here before
68+
if neighbor not in distances or \
69+
(neighbor in distances
70+
and neighbor_distance < distances[neighbor]):
71+
distances[neighbor] = neighbor_distance
72+
previous_vertices[neighbor] = next_node
73+
74+
# 7.) Work our way backwards from the destination and
75+
# Find the shortest path by looking up in the previous_vertices map
76+
shortest_path, current_vertex = deque(), destination
77+
while previous_vertices[current_vertex] is not None:
78+
shortest_path.appendleft(current_vertex)
79+
current_vertex = previous_vertices[current_vertex]
80+
81+
# When we reach the source, append to the path
82+
if shortest_path:
83+
shortest_path.appendleft(current_vertex)
84+
return shortest_path, distances
85+

practice_problems/graph/graph.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from collections import deque, namedtuple
2+
# Credit to: https://dev.to/mxl/dijkstras-algorithm-in-python-algorithms-for-beginners-dkc
3+
inf = float('inf')
4+
Edge = namedtuple('Edge', 'start, end, cost')
5+
6+
7+
def make_edge(start, end, cost=1):
8+
return Edge(start, end, cost)
9+
10+
11+
class Graph:
12+
def __init__(self, edges):
13+
# let's check that the data is right
14+
wrong_edges = [i for i in edges if len(i) not in [2, 3]]
15+
if wrong_edges:
16+
raise ValueError('Wrong edges data: {}'.format(wrong_edges))
17+
18+
self.edges = [make_edge(*edge) for edge in edges]
19+
20+
@property
21+
def vertices(self):
22+
return set(
23+
sum(
24+
([edge.start, edge.end] for edge in self.edges), []
25+
)
26+
)
27+
28+
def get_node_pairs(self, n1, n2, both_ends=True):
29+
if both_ends:
30+
node_pairs = [[n1, n2], [n2, n1]]
31+
else:
32+
node_pairs = [[n1, n2]]
33+
return node_pairs
34+
35+
def remove_edge(self, n1, n2, both_ends=True):
36+
node_pairs = self.get_node_pairs(n1, n2, both_ends)
37+
edges = self.edges[:]
38+
for edge in edges:
39+
if [edge.start, edge.end] in node_pairs:
40+
self.edges.remove(edge)
41+
42+
def add_edge(self, n1, n2, cost=1, both_ends=True):
43+
node_pairs = self.get_node_pairs(n1, n2, both_ends)
44+
for edge in self.edges:
45+
if [edge.start, edge.end] in node_pairs:
46+
return ValueError('Edge {} {} already exists'.format(n1, n2))
47+
48+
self.edges.append(Edge(start=n1, end=n2, cost=cost))
49+
if both_ends:
50+
self.edges.append(Edge(start=n2, end=n1, cost=cost))
51+
52+
@property
53+
def neighbours(self):
54+
neighbours = {vertex: set() for vertex in self.vertices}
55+
for edge in self.edges:
56+
neighbours[edge.start].add((edge.end, edge.cost))
57+
58+
return neighbours
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/usr/bin/env python
2+
from plumbum import cli
3+
from longest_connected_values import LongestConnectedValues
4+
from dijkstras_algorithm import DijkstrasAlgorithm
5+
6+
class GraphAlgorithms(cli.Application):
7+
8+
def main(self, *args):
9+
if args:
10+
print("Unknown command {0!r}".format(args[0]))
11+
return 1 # error exit code
12+
if not self.nested_command: # will be ``None`` if no sub-command follows
13+
print("No command given")
14+
return 1 # error exit code
15+
16+
17+
if __name__ == '__main__':
18+
GraphAlgorithms.subcommand("longest", LongestConnectedValues)
19+
GraphAlgorithms.subcommand("dijkstras", DijkstrasAlgorithm)
20+
GraphAlgorithms.run()
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from plumbum import cli
2+
import pprint
3+
4+
class LongestConnectedValues(cli.Application):
5+
# Making the assumption that values are not repeated!
6+
# 6 , 5 , 7
7+
# 1 , 4 , 8
8+
# 2 , 3 , 9
9+
_graph = {
10+
6: [1, 5],
11+
1: [6, 4, 2],
12+
2: [1, 3],
13+
5: [6, 4, 7],
14+
4: [5, 8, 3, 1],
15+
3: [2, 4, 9],
16+
7: [5, 8],
17+
8: [7, 4, 9],
18+
9: [3, 8]
19+
}
20+
21+
def main(self):
22+
if list is None or len(self._graph) is 0:
23+
print("List should have at least one element")
24+
return 1
25+
else:
26+
longest = self.search_graph(self._graph)
27+
pprint.pprint(longest)
28+
29+
def search_graph(self, graph):
30+
found_longest = {}
31+
32+
for parent,children in graph.items():
33+
found_longest[parent] = self.find_longest(graph, parent, children, [parent], found_longest)
34+
return found_longest
35+
36+
def find_longest(self, graph, parent, children, longest, found_longest):
37+
for child in children:
38+
if parent+1 == child:
39+
if child in found_longest:
40+
longest.extend(found_longest[child])
41+
else:
42+
longest.append(child)
43+
self.find_longest(graph, child, graph[child], longest, found_longest)
44+
45+
return longest

practice_problems/interview/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)