===
Index
sortedcontainers
python 中的 sortedcontainers 模块 封装了对列表、字典、集合的排序等常用操作,在算法比赛中非常有用,很多在c++中实现较为困难的题在sortedcontainers的帮助下,python可以很容易完成代码编写。 纯python编写,速度与c扩展一样快,
安装
pip install sortedcontainers
sortedset
常用基本方法
from sortedcontainers import SortedSet
s = SortedSet([1,2,3,4])
print(3 in ss) # True
print(len(s)) # 4
s = set([1,2,3,4]) # True
s.add(5) # 添加元素5 s = [1,2,3,4,5] O(log(n))
s.add(3) # s = [1,2,3,4,5]
s.discard(3) # 删除值为3的元素 s = [1,2,4,5] O(log(n))
print(s[2]) # s[2] = 4 runtime complexity: O(log(n))
del s[2] # 删除下标2处元素 O(log(n)) s = [1,2,5]
a = s.pop() # 取最后一个元素,并删除该元素 O(log(n))
a = s.pop(2) # 取下标为2的元素,并删除该元素
s.remove(3) # 删除值为3的元素,不存在时会报异常
s.clear() # 删除所有元素。O(n)
常用集合运算
-
集合差-=
求差并更新&
集合交集&=
求交集并更新^
对称差 (并集-交集)^=
异或并更新|
并集|=
并集并更新
difference
返回所有在该集合中而不在另一个集合中的元素,返回一个新的SortedSet
from sortedcontainers import SortedSet
ss = SortedSet([1, 2, 3, 4, 5])
ss.difference([4, 5, 6, 7]) # SortedSet([1, 2, 3])
difference_update
返回所有在该集合中而不在另一个集合中的元素,并更新为当前集合
ss = SortedSet([1, 2, 3, 4, 5])
_ = ss.difference_update([4, 5, 6, 7]) # [1,2,3]
print(ss) # [1,2,3]
intersection
返回两个或多个集合的交集, 返回一个新的SortedSet
ss = SortedSet([1, 2, 3, 4, 5])
ss.intersection([4,5,6,7]) # SortedSet([4, 5])
intersection_update
求两个或多个集合的交集, 并更新该集合为交集的集合
ss = SortedSet([1, 2, 3, 4, 5])
a = ss.intersection_update([4, 5, 6, 7]) #[4,5]
print(ss) # (4,5)
symmetric_difference
返回两个集合的异或 (并集-交集) 等价于 ss ^ s
ss = SortedSet([1, 2, 3, 4, 5])
s = SortedSet([4,5,6,7])
a = ss.symmetric_difference(s)
b = ss ^ s # [1,2,3,6,7]
print(a) # [1,2,3,6,7]
symmetric_difference_update
返回两个集合的异或,同时更新当前集合
ss = SortedSet([1, 2, 3, 4, 5])
_ = ss.symmetric_difference_update([4, 5, 6, 7])
print(ss) # [1,2,3,6,7]
union
集合合并 等价于 ss | s
update
集合合并 并更新 等价于 ss |= s
count
返回某个值在集合中出现次数
sortedlist
常用函数
- add(value) 添加元素 O(log(n))
- update(iterable) 添加list O(k*log(n))
- clear() 清空list O(n)
- discard(value) 删除值为value的元素,如果不存在,do nothing O(log(n))
- remove(value) 删除值为value的元素,不存在时抛出异常 O(log(n))
- pop(index=-1) 删除并返回下标为的元素,默认-1 O(log(n))
- count(value) 某个值的出现次数 O(log(n))
- index(value,start=None, stop=None) 返回在区间内值第一次出现的下标 O(log(n))
- 支持 in, len, [], del, + 等关键字
bisect_left(value)
返回一个大于等于该元素的最小的下标,类似于lower_bound
from sortedcontainers import SortedList
sl = SortedList([10, 11, 15, 16, 19])
sl.bisect_left(14) # 2
sl.bisect_left(11) # 1
bisect_right(value)
返回一个大于该元素的最小的下标,类似于upper_bound
from sortedcontainers import SortedList
sl = SortedList([10, 11, 15, 16, 19])
sl.bisect_right(14) # 2
sl.bisect_right(11) # 2
irange(minimum=None, maximum=None, inclusive=True, True, reverse=False)
返回一个值在[min,max]区间的新iterator
sl = SortedList([10, 11,12, 15, 16, 19])
it = sl.irange(11, 15)
print(list(it)) # [11,12,15]
islice(start=None, stop=None, reverse=False)
返回下标从[start,stop)的区间的iterator
sl = SortedList('abcdefghij')
it = sl.islice(2, 6)
print(list(it)) # ['c', 'd', 'e', 'f']
SortedKeyList
SortedList 的子类,根据key函数去比较元素大小
SortedList中可用的所有相同方法也可在SortedKeyList中使用
from operator import neg
neg(1) # -1
skl = SortedKeyList(key=neg)
skl = SortedKeyList([3, 1, 2], key=neg) # [3,2,1]
sorteddict
Sorted dict 实现了
- SortedDict
- SortedKeysView
- SortedItemView
- SortedValueView
初始化
d = {'alpha': 1, 'beta': 2}
s = SortedDict(d)
s = SortedDict([('alpha', 1), ('beta', 2)])
s = SortedDict({'alpha': 1, 'beta': 2})
s = SortedDict(alpha=1, beta=2)
sd = SortedDict()
sd['c'] = 3
setdefault(key, default=None)
如果key存在,返回value,如果key不存在,插入{key:default},返回default
O(log(n))
sd = SortedDict()
sd.setdefault('a', 1) # 1
sd.setdefault('a', 10) # 1
常用函数
- pop(key, default=
) 返回key对应value并删除key - popitem(index=- 1) 返回下标index处的(key, value)对,并删除
- peekitem(index=- 1) 返回下标index处的(key, value)对
- get(key, default=
) 返回key对应value,不存在返回default - keys(),items(),values() 同dict
collections
python 中的高性能容器数据结构,包含
- namedtuple(): 创建命名元组子类的工厂函数
- deque 类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop)
- ChainMap 类似字典(dict)的容器类,将多个映射集合到一个视图里面
- Counter 字典的子类,提供了可哈希对象的计数功能
- OrderedDict 字典的子类,保存了他们被添加的顺序
- defaultdict 字典的子类,提供了一个工厂函数,为字典查询提供一个默认值
- UserDict 封装了字典对象,简化了字典子类化
- UserList 封装了列表对象,简化了列表子类化
- UserString 封装了字符串对象,简化了字符串子类化
counter
一个计数器工具提供快速和方便的计数。比如
cnt = Counter()
for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
cnt[word] += 1
print(cnt) # Counter({'blue': 3, 'red': 2, 'green': 1})
elements
返回一个迭代器,其中每个元素将重复出现计数值所指定次
c = Counter(a=4, b=2, c=0, d=-2)
sorted(c.elements())
# ['a', 'a', 'a', 'a', 'b', 'b']
most_common
返回一个列表,其中包含 n 个最常见的元素及出现次数,按常见程度由高到低排序。 如果 n 被省略或为 None,most_common() 将返回计数器中的 所有 元素。 计数值相等的元素按首次出现的顺序排序:
Counter('abracadabra').most_common(3)
# [('a', 5), ('b', 2), ('r', 2)]
total()
计算总计数值。
c = Counter(a=10, b=5, c=0)
c.total() # 15
示例题目
滑动窗口中位数
中位数是有序序列最中间的那个数。如果序列的长度是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。
例如:
[2,3,4],中位数是 3 [2,3],中位数是 (2 + 3) / 2 = 2.5 给你一个数组 nums,有一个长度为 k 的窗口从最左端滑动到最右端。窗口中有 k 个数,每次窗口向右移动 1 位。你的任务是找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。
from sortedcontainers import SortedList
class Solution:
def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]:
q = SortedList([])
ans = []
for i in range(len(nums)):
q.add(nums[i])
if i < k - 1:
continue
if i >= k:
q.discard(nums[i - k])
mid = q[k // 2]
if k % 2 == 0:
mid = (mid + q[k // 2 - 1]) / 2.0
ans.append(mid)
return ans
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
class Solution {
public:
tree<pair<int, int>, null_type, less<pair<int, int>>, rb_tree_tag, tree_order_statistics_node_update> t;
vector<double> medianSlidingWindow(vector<int>& nums, int k) {
queue<pair<int, int>> q;
vector<double> ans;
for(int i = 0; i < nums.size(); ++i) {
q.push({nums[i], i});
t.insert({nums[i], i});
if(q.size() >= k) {
long x = (*t.find_by_order(k / 2)).first;
long y = (*t.find_by_order((k - 1) / 2)).first;
ans.push_back((x + y) / 2.0);
t.erase(q.front());
q.pop();
}
}
return ans;
}
};