Skip to content
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

Added Set in .py #169

Open
wants to merge 4 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
69 changes: 69 additions & 0 deletions Set/Randomized_Set.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#! /usr/bin/env python3

"""
Design a data structure that supports all following operations
in average O(1) time.
insert(val): Inserts an item val to the set if not already present.
remove(val): Removes an item val from the set if present.
random_element: Returns a random element from current set of elements.
Each element must have the same probability of being returned.
"""

import random


class RandomizedSet():
"""
idea: shoot
"""

def __init__(self):
self.elements = []
self.index_map = {} # element -> index

def insert(self, new_one):
if new_one in self.index_map:
return
self.index_map[new_one] = len(self.elements)
self.elements.append(new_one)

def remove(self, old_one):
if not old_one in self.index_map:
return
index = self.index_map[old_one]
last = self.elements.pop()
self.index_map.pop(old_one)
if index == len(self.elements):
return
self.elements[index] = last
self.index_map[last] = index

def random_element(self):
return random.choice(self.elements)


def __test():
rset = RandomizedSet()
ground_truth = set()
n = 64

for i in range(n):
rset.insert(i)
ground_truth.add(i)

# Remove a half
for i in random.sample(range(n), n // 2):
rset.remove(i)
ground_truth.remove(i)

print(len(ground_truth), len(rset.elements), len(rset.index_map))
for i in ground_truth:
assert(i == rset.elements[rset.index_map[i]])

for i in range(n):
print(rset.random_element(), end=' ')
print()


if __name__ == "__main__":
__test()
108 changes: 108 additions & 0 deletions Set/Set_Covering.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
from itertools import chain, combinations

"""
Universe *U* of n elements
Collection of subsets of U:
S = S1,S2...,Sm
Where every substet Si has an associated cost.
Find a minimum cost subcollection of S that covers all elements of U
Example:
U = {1,2,3,4,5}
S = {S1,S2,S3}
S1 = {4,1,3}, Cost(S1) = 5
S2 = {2,5}, Cost(S2) = 10
S3 = {1,4,3,2}, Cost(S3) = 3
Output:
Set cover = {S2, S3}
Min Cost = 13
"""


def powerset(iterable):
"""Calculate the powerset of any iterable.
For a range of integers up to the length of the given list,
make all possible combinations and chain them together as one object.
From https://docs.python.org/3/library/itertools.html#itertools-recipes
"""
"list(powerset([1,2,3])) --> [(), (1,), (2,), (3,), (1,2), (1,3), (2,3), (1,2,3)]"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1))


def optimal_set_cover(universe, subsets, costs):
""" Optimal algorithm - DONT USE ON BIG INPUTS - O(2^n) complexity!
Finds the minimum cost subcollection os S that covers all elements of U
Args:
universe (list): Universe of elements
subsets (dict): Subsets of U {S1:elements,S2:elements}
costs (dict): Costs of each subset in S - {S1:cost, S2:cost...}
"""
pset = powerset(subsets.keys())
best_set = None
best_cost = float("inf")
for subset in pset:
covered = set()
cost = 0
for s in subset:
covered.update(subsets[s])
cost += costs[s]
if len(covered) == len(universe) and cost < best_cost:
best_set = subset
best_cost = cost
return best_set


def greedy_set_cover(universe, subsets, costs):
"""Approximate greedy algorithm for set-covering. Can be used on large
inputs - though not an optimal solution.
Args:
universe (list): Universe of elements
subsets (dict): Subsets of U {S1:elements,S2:elements}
costs (dict): Costs of each subset in S - {S1:cost, S2:cost...}
"""
elements = set(e for s in subsets.keys() for e in subsets[s])
# elements don't cover universe -> invalid input for set cover
if elements != universe:
return None

# track elements of universe covered
covered = set()
cover_sets = []

while covered != universe:
min_cost_elem_ratio = float("inf")
min_set = None
# find set with minimum cost:elements_added ratio
for s, elements in subsets.items():
new_elements = len(elements - covered)
# set may have same elements as already covered -> new_elements = 0
# check to avoid division by 0 error
if new_elements != 0:
cost_elem_ratio = costs[s] / new_elements
if cost_elem_ratio < min_cost_elem_ratio:
min_cost_elem_ratio = cost_elem_ratio
min_set = s
cover_sets.append(min_set)
# union
covered |= subsets[min_set]
return cover_sets


if __name__ == '__main__':
universe = {1, 2, 3, 4, 5}
subsets = {'S1': {4, 1, 3}, 'S2': {2, 5}, 'S3': {1, 4, 3, 2}}
costs = {'S1': 5, 'S2': 10, 'S3': 3}

optimal_cover = optimal_set_cover(universe, subsets, costs)
optimal_cost = sum(costs[s] for s in optimal_cover)

greedy_cover = greedy_set_cover(universe, subsets, costs)
greedy_cost = sum(costs[s] for s in greedy_cover)

print('Optimal Set Cover:')
print(optimal_cover)
print('Cost = %s' % optimal_cost)

print('Greedy Set Cover:')
print(greedy_cover)
print('Cost = %s' % greedy_cost)
1 change: 1 addition & 0 deletions Set/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .find_keyboard_row import *
24 changes: 24 additions & 0 deletions Set/find_keyboard_row.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""
Given a List of words, return the words that can be typed using letters of
alphabet on only one row's of American keyboard.
For example:
Input: ["Hello", "Alaska", "Dad", "Peace"]
Output: ["Alaska", "Dad"]
Reference: https://leetcode.com/problems/keyboard-row/description/
"""
def find_keyboard_row(words):
"""
:type words: List[str]
:rtype: List[str]
"""
keyboard = [
set('qwertyuiop'),
set('asdfghjkl'),
set('zxcvbnm'),
]
result = []
for word in words:
for key in keyboard:
if set(word.lower()).issubset(key):
result.append(word)
return result