Skip to content

Feature/solutions #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ $ pip install py-algorithms
- Weighted Union Find
- Weighted Union Find with Path Compression

- Longest Consecutive

---

### Dynamic Programing (DP)
Expand Down
57 changes: 57 additions & 0 deletions py_algorithms/array/longest_consecutive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from typing import List


class LongestConsecutive:
@staticmethod
def apply(nums: List[int]) -> int:
return LongestConsecutive.with_sorting(nums)

@staticmethod
def with_sorting(nums: List[int]):
if not nums:
return 0

nums = sorted(nums)
longest_consecutive = 1
current = 1

for i in range(1, len(nums)):
if nums[i] != nums[i - 1]:
if nums[i] == nums[i - 1] + 1:
current += 1
else:
longest_consecutive = max(current, longest_consecutive)
current = 1

return max(current, longest_consecutive)

@staticmethod
def brute_force(nums: List[int]):
if not nums:
return 0

longest_consecutive = 1
for num in nums:
current = num
current_seq = 1

while current + 1 in nums:
current += 1
current_seq += 1

longest_consecutive = max(longest_consecutive, current_seq)
return longest_consecutive

@staticmethod
def with_set(nums):
xs = set(nums)
known_max = 0

for p in xs:
if p - 1 not in xs:
q = p + 1
while q in xs:
q += 1
known_max = max(known_max, q - p)

return known_max
59 changes: 59 additions & 0 deletions py_algorithms/array/median_of_two_sorted_arrays.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from heapq import heappop
from heapq import heappush
from heapq import nsmallest


class MedianOfTwoSortedArrays:
@staticmethod
def apply_2(nums1, nums2):
def _push_to_heap(item):
median = _median()
if item > median:
heappush(min_pq, item)
elif item < median:
heappush(max_pq, -1 * item)
else:
heappush(min_pq, item)

if abs(len(max_pq) - len(min_pq)) > 1:
_rebalance()

def _rebalance():
if len(min_pq) > len(max_pq):
heappush(max_pq, -1 * heappop(min_pq))
else:
heappush(min_pq, -1 * heappop(max_pq))

def _median():
if len(min_pq) > len(max_pq):
return float(nsmallest(1, min_pq)[0])
elif len(max_pq) > len(min_pq):
return float(-1 * nsmallest(1, max_pq)[0])
else:
if len(min_pq) == 0 and len(max_pq) == 0:
return 0.0
a = nsmallest(1, min_pq)[0]
b = -1 * nsmallest(1, max_pq)[0]
return (a + b) / 2

max_pq = list()
min_pq = list()

while len(nums1) > 0 or len(nums2) > 0:
if len(nums1) > 0:
_push_to_heap(nums1.pop())

if len(nums2) > 0:
_push_to_heap(nums2.pop())

return _median()

@staticmethod
def apply(nums1, nums2):
arr = sorted(nums1 + nums2)
n = len(arr)
mid = n // 2
if n % 2 == 0:
return (arr[mid - 1] + arr[mid]) / 2
else:
return float(arr[mid])
25 changes: 25 additions & 0 deletions py_algorithms/caches/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
__all__ = [
'new_lfu_cache',
'new_lru_cache'
]

from .lfu_cache import LfuCache
from .lru_cache import LruCache


def new_lfu_cache(size) -> LfuCache:
"""
Factory method
:param size: Size of cache
:return: LfuCache
"""
return LfuCache(size)


def new_lru_cache(size) -> LruCache:
"""
Factory method
:param size: Size of cache
:return: LruCache
"""
return LruCache(size)
55 changes: 55 additions & 0 deletions py_algorithms/caches/lfu_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from collections import defaultdict


class LfuCache:
def __init__(self, capacity):
"""
:type capacity: int
"""
self.n = capacity
self.table = {}
self.counts = {}
self.buckets = defaultdict(list)
self.min = -1

def get(self, key):
"""
:type key: int
:rtype: int
"""
if key not in self.table:
return -1

count = self.counts[key]
self.counts[key] = count + 1
self.buckets[count].remove(key)

if count == self.min and len(self.buckets[count]) == 0:
self.min += 1

self.buckets[count + 1].append(key)

return self.table[key]

def put(self, key, value):
"""
:type key: int
:type value: int
:rtype: void
"""
if self.n <= 0:
return

if key in self.table:
self.table[key] = value
self.get(key)
return

if len(self.table) >= self.n:
to_evict = self.buckets[self.min].pop(0)
del self.table[to_evict]

self.table[key] = value
self.counts[key] = 1
self.min = 1
self.buckets[1].append(key)
111 changes: 111 additions & 0 deletions py_algorithms/caches/lru_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
from collections import OrderedDict
from typing import Any
from typing import Union


class LruCache:
class Node:
def __init__(self, key, value):
self.key = key
self.value = value
self.next = None
self.prev = None

def __init__(self, capacity):
"""
:type capacity: int
"""
self.n = capacity
self.table = {}
self.head = None
self.tail = None

def get(self, key):
"""
:type key: int
:rtype: int
"""
if key in self.table:
node = self.table[key]
self._remove(node)
self._make_head(node)
return node.value

return -1

def put(self, key, value):
"""
:type key: int
:type value: int
:rtype: void
"""
if key in self.table:
node = self.table.get(key)
node.value = value
self._remove(node)
self._make_head(node)
else:
new_node = self.Node(key, value)
if len(self.table) >= self.n:
del self.table[self.tail.key]
self._remove(self.tail)
self._make_head(new_node)
self.table[key] = new_node

def _remove(self, node):
if node.prev is not None:
node.prev.next = node.next
else:
self.head = node.next

if node.next is not None:
node.next.prev = node.prev
else:
self.tail = node.prev

def _make_head(self, node):
node.next = self.head
node.prev = None

if self.head is not None:
self.head.prev = node

self.head = node

if self.tail is None:
self.tail = self.head


class SimpleLruCache:
def __init__(self, capacity):
"""
:type capacity: int
"""
self.capacity = capacity
self.d = OrderedDict()

def get(self, key) -> Union[Any, int]:
"""
:type key: int
:rtype: int
"""
if key in self.d:
value = self.d[key]
del self.d[key]
self.d[key] = value
return value
else:
return -1

def put(self, key, value) -> None:
"""
:type key: int
:type value: int
:rtype: None
"""
if key in self.d:
del self.d[key]
elif len(self.d) == self.capacity:
self.d.popitem(False)

self.d[key] = value
Empty file.
49 changes: 49 additions & 0 deletions py_algorithms/strings/word_break.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from typing import List


class WordBreak:
@staticmethod
def apply(word: str, voc: List[str]) -> bool:
queue = [0]
visited = []

while len(queue) > 0:
start = queue.pop(0)
if start not in visited:
end = start + 1
while end <= len(word):
if word[start:end] in voc:
queue.append(end)
if end == len(word):
return True
end += 1

visited.append(start)
return False

@staticmethod
def dp_apply(word: str, voc: List[str]) -> bool:
dp = [False for _ in range(len(word))]
length = len(word)

for i in range(length):
for w in voc:
w_len = len(w)
if w == word[i - w_len + 1:i + 1]:
if dp[i - w_len] or i - w_len == -1:
dp[i] = True
return dp[-1]

@staticmethod
def dp2_apply(word: str, voc: List[str]) -> bool:
dp = [False for _ in range(len(word) + 1)]
dp[0] = True

for i in range(1, len(word) + 1):
j = 0
while j < i:
if dp[j] and word[j:i] in voc:
dp[i] = True
j += 1

return dp[-1]
28 changes: 28 additions & 0 deletions tests/py_algorithms/arrays/longest_consecutive_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import pytest

from py_algorithms.array.longest_consecutive import LongestConsecutive


def _test_case_helper(f, mapping):
for x in mapping:
payload, expected = x
assert expected == f(payload)


@pytest.fixture
def cases():
return [
([100, 4, 200, 1, 3, 2], 4),
([], 0),
([2, 1, 1, 3], 3)]


class TestLongestConsecutive:
def test_apply(self):
_test_case_helper(LongestConsecutive.with_sorting, cases())

def test_brute_force(self):
_test_case_helper(LongestConsecutive.brute_force, cases())

def test_with_set(self):
_test_case_helper(LongestConsecutive.with_set, cases())
Loading