Skip to content

Commit

Permalink
Refactored solutions 336 - 350
Browse files Browse the repository at this point in the history
  • Loading branch information
WHAHA-HA committed Feb 2, 2021
1 parent 1236508 commit b8e40c0
Show file tree
Hide file tree
Showing 15 changed files with 53 additions and 96 deletions.
31 changes: 13 additions & 18 deletions Solutions/336.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
"""

from math import log2
from typing import List


def choose(n, k, nCk):
# function to get nCk using dynamic programming
def choose(n: int, k: int, nCk: List[List[int]]) -> int:
# get nCk using dynamic programming
if k > n:
return 0
if n <= 1:
Expand All @@ -24,14 +25,13 @@ def choose(n, k, nCk):
return 1
if nCk[n][k] != -1:
return nCk[n][k]
# updating nCk

answer = choose(n - 1, k - 1, nCk) + choose(n - 1, k, nCk)
nCk[n][k] = answer
return answer


def get_left(n):
# calculate l for give value of n
def get_nodes_left(n: int) -> int:
if n == 1:
return 0
h = int(log2(n))
Expand All @@ -40,22 +40,19 @@ def get_left(n):
# number of elements that are actually present in the last level
# [hth level (2 ^ h - 1)]
last = n - ((1 << h) - 1)
# if more than half of the last level is filled
if last >= (num_h // 2):
# if more than half of the last level is filled
return (1 << h) - 1
else:
return (1 << h) - 1 - ((num_h // 2) - last)
return (1 << h) - 1 - ((num_h // 2) - last)


def number_of_heaps(n, dp, nCk):
# find maximum number of heaps for n
def number_of_heaps(n: int, dp: List[int], nCk: List[List[int]]) -> int:
if n <= 1:
return 1
if dp[n] != -1:
return dp[n]
# getting the number of nodes left
left = get_left(n)
# generating the result

left = get_nodes_left(n)
ans = (
choose(n - 1, left, nCk)
* number_of_heaps(left, dp, nCk)
Expand All @@ -65,11 +62,9 @@ def number_of_heaps(n, dp, nCk):
return ans


def get_number_of_heaps(n):
# initializing dynamic programming data
dp = [-1 for i in range(n + 1)]
nCk = [[-1 for i in range(n + 1)] for i in range(n + 1)]
# generating result
def get_number_of_heaps(n: int) -> int:
dp = [-1 for _ in range(n + 1)]
nCk = [[-1 for _ in range(n + 1)] for _ in range(n + 1)]
return number_of_heaps(n, dp, nCk)


Expand Down
10 changes: 2 additions & 8 deletions Solutions/337.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,21 @@

from random import randint

from DataStructures.LinkedList import Node, LinkedList
from DataStructures.LinkedList import LinkedList


def shuffle(ll: LinkedList) -> LinkedList:
# base case, no shuffling possible
length = len(ll)
if length in (0, 1):
return ll
# shuffling values

for _ in range(length):
# generating 2 random positions
pos1, pos2 = randint(0, length - 1), randint(0, length - 1)
node1, node2 = ll.head, ll.head
# positioning the pointers at the proper poitions
for _ in range(pos1):
node1 = node1.next
for _ in range(pos2):
node2 = node2.next
# swaping values
node1.val, node2.val = node2.val, node1.val
return ll

Expand All @@ -37,9 +33,7 @@ def shuffle(ll: LinkedList) -> LinkedList:
ll.add(i)

print(ll)

shuffle(ll)

print(ll)


Expand Down
5 changes: 2 additions & 3 deletions Solutions/338.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ def get_set_bits(num: int) -> int:
return sum([int(digit) for digit in bin_num])


def get_next_int(num: int) -> int:
# function to get the next number with same number of set bits
def get_next_number_with_same_count_of_set_bits(num: int) -> int:
num_of_set_bits = get_set_bits(num)
curr = num + 1
while True:
Expand All @@ -23,7 +22,7 @@ def get_next_int(num: int) -> int:


if __name__ == "__main__":
print(get_next_int(6))
print(get_next_number_with_same_count_of_set_bits(6))


"""
Expand Down
4 changes: 1 addition & 3 deletions Solutions/339.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@


def target_sum_of_two(arr: List[int], k: int, index_1: int, index_2: int) -> bool:
# helper function to check if 2 numbers add up to a given number
while index_1 < index_2:
elem_1, elem_2 = arr[index_1], arr[index_2]
curr_sum = elem_1 + elem_2
Expand All @@ -24,12 +23,11 @@ def target_sum_of_two(arr: List[int], k: int, index_1: int, index_2: int) -> boo


def target_sum_of_three(arr: List[int], k: int) -> bool:
# function to check if 3 numbers add up to a given number
length = len(arr)
# sorting the array to utilize the optimizations offered by a sorted array to find
# target sum of 2 numbers
arr.sort()
# selecting an element and running target sum of 2 to check if k can be obtained

for index_1, elem in enumerate(arr):
index_2, index_3 = index_1 + 1, length - 1
if elem >= k:
Expand Down
11 changes: 6 additions & 5 deletions Solutions/340.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,21 @@
from typing import List, Tuple


def get_distance(pt1: Tuple[int, int], pt2: Tuple[int, int]) -> float:
# helper function to get the distance between 2 points
Point = Tuple[int, int]


def get_distance(pt1: Point, pt2: Point) -> float:
x1, y1 = pt1
x2, y2 = pt2
dist = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2))
return dist


def get_nearest_points(pts_arr: List[Tuple[int, int]]) -> List[Tuple[int, int]]:
# function to get the nearest 2 points
def get_nearest_points(pts_arr: List[Point]) -> List[Point]:
length = len(pts_arr)
dist = maxsize
pt1, pt2 = None, None
# checking for all combinations

for index_1 in range(length):
for index_2 in range(index_1 + 1, length):
pt1_temp, pt2_temp = pts_arr[index_1], pts_arr[index_2]
Expand Down
25 changes: 9 additions & 16 deletions Solutions/341.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
def get_neighbours(
pos: Tuple[int, int], dim: Tuple[int, int], seen: Set[int]
) -> List[Tuple[int, int]]:
# helper function to generate the neighbours of a given position inside the matrix
# and which has not been visited
n, m = dim
i, j = pos
positions = [
Expand All @@ -42,27 +40,26 @@ def get_neighbours(
valid_positions = []
for position in positions:
y, x = position
if 0 <= y < n and 0 <= x < m:
if position not in seen:
valid_positions.append(position)
if (0 <= y < n and 0 <= x < m) and (position not in seen):
valid_positions.append(position)
return valid_positions


def generate_word(
def can_generate_word(
matrix: List[List[str]],
pos: Tuple[int, int],
word: str,
seen: Set[int],
dim: Tuple[int, int],
) -> Union[bool, Optional[Set[int]]]:
# helper function to check if the current word exists in the matrix
# check if the current word can be generated from the matrix
if word == "":
return True, seen
neighbours = get_neighbours(pos, dim, seen)
for neighbour in neighbours:
i, j = neighbour
if matrix[i][j] == word[0]:
generated, seen_pos = generate_word(
generated, seen_pos = can_generate_word(
matrix, neighbour, word[1:], seen | set([neighbour]), dim
)
if generated:
Expand All @@ -71,7 +68,7 @@ def generate_word(


def get_power_set(words: List[str]) -> List[List[str]]:
# function to generate the power set of the given list (eleminates the empty set)
# generate the power set of the given list except the empty set
num_of_words = len(words)
accumulator = []
pow_set_size = pow(2, num_of_words)
Expand All @@ -88,19 +85,18 @@ def get_power_set(words: List[str]) -> List[List[str]]:


def get_max_packed_helper(matrix: List[List[str]], words: Set[str]) -> int:
# helper function to get the maximum number of packed words
n, m = len(matrix), len(matrix[0])
count = 0
seen = set()
# checking for all combinations of words and matrix characters

for i in range(n):
for j in range(m):
char = matrix[i][j]
for word in words:
if word[0] == char:
# a match has been found, trying to generate the entire word from
# the first character in the matrix
generated, seen_temp = generate_word(
generated, seen_temp = can_generate_word(
matrix, (i, j), word[1:], seen, (n, m)
)
if generated:
Expand All @@ -110,7 +106,6 @@ def get_max_packed_helper(matrix: List[List[str]], words: Set[str]) -> int:


def get_max_packed(matrix: List[List[str]], words: Set[str]) -> int:
# function to get the maximum number of packed words
words_list = get_power_set(list(words))
max_words = 0
for word_list in words_list:
Expand All @@ -125,9 +120,7 @@ def get_max_packed(matrix: List[List[str]], words: Set[str]) -> int:
["e", "a", "n"],
["t", "t", "i"],
["a", "r", "a"]
], {
"eat", "rain", "in", "rat"
},
], {"eat", "rain", "in", "rat"},
)
)

Expand Down
7 changes: 3 additions & 4 deletions Solutions/342.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,18 @@ def sum(lst):
from typing import Any, Callable, Iterable


def reduce(iterable: Iterable, func: Callable, initial_value: Any) -> Any:
# impementation of reduce or fold
def reduce(iterable: Iterable, func: Callable, initial_value: int) -> int:
value = initial_value
for item in iterable:
value = func(value, item)
return value


def add(a, b):
def add(a: int, b: int) -> int:
return a + b


def sum(lst):
def sum(lst: Iterable) -> int:
return reduce(lst, add, 0)


Expand Down
6 changes: 1 addition & 5 deletions Solutions/343.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@


def get_sum_over_range_helper(node: Node, low: int, high: int) -> int:
# helper function to calculate the sum over the given range (while traversing
# through the tree)
if node is None:
return 0
if low <= node.val <= high:
Expand All @@ -32,12 +30,10 @@ def get_sum_over_range_helper(node: Node, low: int, high: int) -> int:
)
elif low > node.val:
return get_sum_over_range_helper(node.right, low, high)
else:
return get_sum_over_range_helper(node.left, low, high)
return get_sum_over_range_helper(node.left, low, high)


def get_sum_over_range(tree: BinarySearchTree, sum_range: Tuple[int, int]) -> int:
# function to calculate the sum over the given range
if tree.root is None:
return 0
low, high = sum_range
Expand Down
3 changes: 1 addition & 2 deletions Solutions/344.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
4 5
/ | \
6 7 8
In this case, removing the edge (3, 4) satisfies our requirement.
Write a function that returns the maximum number of edges you can remove while still
Expand All @@ -39,7 +40,6 @@ def __init__(self) -> None:


def get_even_edge_split_helper(node: Node) -> Tuple[int, int]:
# helper function to get the number of possible even splits
nodes_count = 0
even_splits = 0
for child in node.children:
Expand All @@ -52,7 +52,6 @@ def get_even_edge_split_helper(node: Node) -> Tuple[int, int]:


def get_even_edge_split(tree: Tree) -> int:
# function to get the number of possible even splits
if tree.root:
_, result = get_even_edge_split_helper(tree.root)
return result
Expand Down
3 changes: 0 additions & 3 deletions Solutions/345.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@


def generate_graph(synonyms: List[Tuple[str, str]]) -> GraphUndirectedUnweighted:
# helper function to construct the graph from the synonym list
graph = GraphUndirectedUnweighted()
for word_1, word_2 in synonyms:
graph.add_edge(word_1, word_2)
Expand All @@ -30,14 +29,12 @@ def generate_graph(synonyms: List[Tuple[str, str]]) -> GraphUndirectedUnweighted
def check_equivalence(
sentence_1: str, sentence_2: str, synonyms: List[Tuple[str, str]]
) -> bool:
# function to check if 2 sentences have same meaning
graph = generate_graph(synonyms)
word_list_1 = sentence_1.strip().split()
word_list_2 = [word for word in word_list_1]

if len(word_list_1) != len(word_list_2):
return False
# comparing the meaning of each non-matching word
for word_1, word_2 in zip(word_list_1, word_list_2):
if word_1 != word_2:
if word_1 not in graph.connections or word_2 not in graph.connections:
Expand Down
7 changes: 3 additions & 4 deletions Solutions/346.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,15 @@
from DataStructures.PriorityQueue import MinPriorityQueue


def modified_dijkstras_algo(
def modified_dijkstra(
graph: GraphDirectedWeighted, start: str, k: int
) -> Tuple[Dict[str, int], Dict[str, Optional[str]]]:
# dijkstra's algorithm for single source shortest path
dist = {node: maxsize for node in graph.connections}
parent = {node: None for node in graph.connections}
dist[start] = 0
priority_queue = MinPriorityQueue()
[priority_queue.push(node, weight) for node, weight in dist.items()]
# running dijkstra's algorithm

while not priority_queue.is_empty():
node = priority_queue.extract_min()
ancestors = 0
Expand All @@ -68,7 +67,7 @@ def generate_path(
for src, dest, wt in flights:
graph.add_edge(src, dest, wt)
# running dijkstra's algorithm
dist, parent = modified_dijkstras_algo(graph, start, k)
dist, parent = modified_dijkstra(graph, start, k)
# getting the cost and path
if not parent[dest]:
return []
Expand Down
Loading

0 comments on commit b8e40c0

Please sign in to comment.