Python
Contents
Python¶
Defaultdict¶
(defaultdict(list))
from collections import defaultdict
lookup = defaultdict(list)
lookup[0].append((1, 2))
lookup
defaultdict(list, {0: [(1, 2)]})
lookup[0].append((3, 4))
lookup
defaultdict(list, {0: [(1, 2), (3, 4)]})
Insert element into list at position i
a = [1,2,3,4]
a.insert(2, 400)
a
[1, 2, 400, 3, 4]
Bisect¶
https://docs.python.org/3/library/bisect.html
from bisect import bisect_left, bisect_right, bisect
nums = [1,50,100,150]
# Locate the insertion point for x in nums to maintain sorted order.
# The parameters lo and hi may be used to specify a subset of the list which should be considered;
# bisect left inserts x to the left of any pre-existing entries of x
bisect_left(nums, x=50)
1
# Similar to bisect_left(), but returns an insertion point which comes after (to the right of) any existing entries of x in a.
# The returned insertion point i partitions the array a into two halves so that all(val <= x for val in a[lo : i]) for the left side and all(val > x for val in a[i : hi]) for the right side.
# bisect_right = bisect
# bisect right and bisect insert x to the right of any pre-existing entries of x
bisect_right(nums, x=50)
2
bisect(nums, x=50)
2
# if x is greater than all elements of a, return 4 since 4 is the correct insertion point
bisect(nums, x=151)
4
# if x is less than than all elements of a, returns 0, since 0 is the correct insertion point for -1
bisect(nums, x=-1)
0
Bisect application (uses binary search and hashmap)
https://leetcode.com/problems/time-based-key-value-store/submissions/
from collections import defaultdict
from bisect import bisect_right
class TimeMap:
# approach #1
# use a hashmap
# key: [(timestamp, value), (timestamp, value)]
# approach #2
def __init__(self):
self.timestamps = defaultdict(list)
self.values = defaultdict(list)
def set(self, key: str, value: str, timestamp: int) -> None:
# timestamp increases with each successive call,
# so we can just append and they will be sorted
# by timestamp in increasing order
# create two defaultdicts for timestamps and values
# we could use one lookup with a list of tuples
# where lookup[key] = [(timestamp, value), (timestamp1, value1)]
# but bisect only provides the key parameter in python 3.10+
self.timestamps[key].append(timestamp)
self.values[key].append(value)
def get(self, key: str, timestamp: int) -> str:
if self.timestamps.get(key) is None:
return ""
# If the last (and greatest) timestamp for this key is smaller
# than the timestamp requested, return the last timestamp
if self.timestamps[key][-1] < timestamp:
return self.values[key][-1]
# find theoretical insertion point for timestamp in self.timestamps[key] to maintain sorted order
# bisect_right() and bisect() find idx to insert x to the right of any pre-existing entries of x
i = bisect_right(a=self.timestamps[key], x=timestamp)
# all timestamps are greater than the one requested
# return not found
if i == 0:
return ""
# since all elements with index <= i are <= timestamp,
# we return the value at i-1
# which has a timestamp <= the requested timestamp
return self.values[key][i-1]
# Your TimeMap object will be instantiated and called as such:
# obj = TimeMap()
# obj.set(key,value,timestamp)
# param_2 = obj.get(key,timestamp)
Alternative approach¶
TODO
Min/Max Heap¶
https://docs.python.org/3/library/heapq.html
(b) Our pop method returns the smallest item, not the largest (called a “min heap” in textbooks; a “max heap” is more common in texts because of its suitability for in-place sorting).
nums = [10, 1, 5, 2, 7]
import heapq
heapq.heapify(nums) # min-heap by default
n = len(nums)
for i in range(n):
print(heapq.heappop(nums))
1
2
5
7
10
A heapsort can be implemented by pushing all values onto a heap and then popping off the smallest values one at a time:
def heapsort(iterable):
h = []
for value in iterable:
heapq.heappush(h, value)
return [heapq.heappop(h) for _ in range(len(h))]
nums = [10, 1, 4, 8, 2, 3]
print(heapsort(nums))
[1, 2, 3, 4, 8, 10]
From Big-O CheatSheet The heapsort worst time complexity is O(nlogn) and the worst space complexity is O(1) It is effectively better than mergesort because mergesort has a space complexity of O(n) It is better than quicksort because quicksort has a ‘worst’ time complexity of O(n^2) and a space complexity of O(logn)
a = [1,2,3,4,5]
a[::-1]
[5, 4, 3, 2, 1]
Class variables vs. Instance variables in Python¶
Source: https://www.geeksforgeeks.org/g-fact-34-class-or-static-variables-in-python/
class CSStudent:
stream = 'cse' # Class Variable
def __init__(self,name,roll):
self.name = name # Instance Variable
self.roll = roll # Instance Variable
Static variables in functions in Python¶
def testing123():
testing123.val = 3
result = False
try:
testing123.val
except AttributeError as e:
print(f"Raised {e}")
result = True
assert result
testing123()
print(testing123.val)
testing123.val += 1
print(testing123.val)
Raised 'function' object has no attribute 'val'
3
4
Sets https://www.geeksforgeeks.org/unordered_set-in-cpp-stl/
# Convert a list of 1s and 0s to binary using
# Cast each digit to a string using the map() function
# Cast the string to an int with base equal to 2
digits = [1,0,1,0,0]
num1 = int("".join(map(str, digits)), base=2)