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

Add Python to Intro_Sorted_Sets Module #4862

Merged
merged 25 commits into from
Oct 29, 2024
Merged
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
85f0dec
Update content/3_Silver/Intro_Sorted_Sets.mdx
CryoJS Oct 25, 2024
ed8ee72
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 25, 2024
63623f3
Update content/3_Silver/Intro_Sorted_Sets.mdx
CryoJS Oct 27, 2024
18e4f28
Update content/3_Silver/Intro_Sorted_Sets.mdx
CryoJS Oct 27, 2024
130db1d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 27, 2024
a6f6fb3
Merge branch 'master' into py
CryoJS Oct 27, 2024
8cff55d
Update content/3_Silver/Intro_Sorted_Sets.mdx
CryoJS Oct 27, 2024
bc4edd7
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 27, 2024
6f15cf1
Update Intro_Sorted_Sets.mdx
SansPapyrus683 Oct 27, 2024
a24ed0b
Update content/3_Silver/Intro_Sorted_Sets.mdx
CryoJS Oct 27, 2024
4a17b5b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 27, 2024
89925ad
Merge branch 'master' into py
CryoJS Oct 27, 2024
fe11a65
Update content/3_Silver/Intro_Sorted_Sets.mdx
CryoJS Oct 27, 2024
c0be548
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 27, 2024
52c16ef
Update content/3_Silver/Intro_Sorted_Sets.mdx
CryoJS Oct 27, 2024
d03d27d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 27, 2024
33a8818
Update content/3_Silver/Intro_Sorted_Sets.mdx
CryoJS Oct 27, 2024
36db49f
Merge branch 'master' into py
CryoJS Oct 28, 2024
c68a350
Update content/3_Silver/Intro_Sorted_Sets.mdx
CryoJS Oct 28, 2024
8579ef3
Update content/3_Silver/Intro_Sorted_Sets.mdx
CryoJS Oct 28, 2024
7857cb3
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 28, 2024
12b1166
Update content/3_Silver/Intro_Sorted_Sets.mdx
CryoJS Oct 28, 2024
d31adae
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 28, 2024
9a95d1a
Merge branch 'master' into py
CryoJS Oct 29, 2024
4cc8617
Update content/3_Silver/Intro_Sorted_Sets.mdx
CryoJS Oct 29, 2024
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
175 changes: 157 additions & 18 deletions content/3_Silver/Intro_Sorted_Sets.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
id: intro-sorted-sets
title: 'More Operations on Sorted Sets'
author: Darren Yao, Benjamin Qi, Andrew Wang
contributors: Aadit Ambadkar, Jeffrey Hu
contributors: Aadit Ambadkar, Jeffrey Hu, Jason Sun
prerequisites:
- intro-sets
description:
Expand Down Expand Up @@ -48,25 +48,23 @@ redirects:
In sets and maps where keys (or elements) are stored in sorted order, accessing
or removing the next key higher or lower than some input key `k` is supported.

Keep in mind that insertion and deletion will take $\mathcal{O}(\log N)$ time for
sorted sets, which is more than the average $\mathcal{O}(1)$ insertion and
deletion for unordered sets, but less than the worst case $\mathcal{O}(N)$ insertion
and deletion for unordered sets.
Keep in mind that insertion and deletion will take $\mathcal{O}(\log N)$ time
for sorted sets, which is more than the average $\mathcal{O}(1)$ insertion and
deletion for unordered sets, but less than the worst case $\mathcal{O}(N)$
insertion and deletion for unordered sets.

## Using Iterators

In Bronze, we avoided discussion of any set operations involving iterators.

<LanguageSection>

<CPPSection>

<Resources>
<Resource source="CPH" title="4.4 - Set Iterators" starred />
</Resources>

</CPPSection>

<JavaSection>

In Java, iterators are helpful for looping through sets.
Expand Down Expand Up @@ -125,13 +123,44 @@ which can only be used once before calling the `next()` method.
</Warning>

</JavaSection>
<PySection>

In Python, we can use `iter()` to obtain the iterator object of any iterable.
Using `next()` on the iterator lets you iterate through the iterable. Below, a
dictionary is used instead of a set because dictionaries keep order.

Iterating through a dictionary representation of an ordered set:

```py
nums = {0: None, 1: None, 2: None, 4: None, 7: None}
iterator = iter(nums)

print(next(iterator)) # 0
SansPapyrus683 marked this conversation as resolved.
Show resolved Hide resolved
print(next(iterator)) # 1
print(next(iterator)) # 2
print(next(iterator)) # 4
print(next(iterator)) # 7
```

<Warning>
As of Python 3.6, dictionaries are ordered by **insertion order**. For older
versions, you can use an `OrderedDict` from `collections`. Keep in mind that
the above representation is of an ordered set, not a sorted set, because Python
does not have sorted sets in its standard library, as you will see in the next
section.
</Warning>

Python's iterators are fundamental to iteration and are used in its for loops
and tuple unpacking. This is useful when you want more control over your
iteration. It can also be simply used in cases where you just want the first or
any element.

</PySection>
</LanguageSection>

## Sorted Sets

<LanguageSection>

<CPPSection>

The sorted `std::set` also supports:
Expand Down Expand Up @@ -168,7 +197,6 @@ make sure to avoid it!
</Warning>

</CPPSection>

<JavaSection>

`TreeSet`s in Java allow for a multitude of additional operations:
Expand Down Expand Up @@ -196,7 +224,67 @@ System.out.println(set.higher(23)); // ERROR, no such element exists
```

</JavaSection>
<PySection>

Python does not have a sorted set nor a sorted map, so see the C++ or Java if
you want an implementation from the standard library. However, if you are still
curious regarding the Python implementation, you can find an AVL tree
representation of a sorted set below.

<Resources>
<Resource source="DSA Python" url="https://nibmehub.com/opac-service/pdf/read/Data%20Structures%20and%20Algorithms%20in%20Python.pdf#page=503" title="AVL Trees">
definition and implementation of AVL Trees in Python
</Resource>
</Resources>

<Warning>

You are not expected to know how to create an AVL tree in USACO Silver, nor is
it recommended to do so for a representation of a sorted set since other
languages have sorted sets built-in.

</Warning>

Since some online judges include additional libraries, an implementation of
sorted sets from the `sortedcontainers` library (which is not included in most
online judges like USACO) is shown below. All operations shown below are
$\mathcal{O}(\log N)$ time, except for its $\mathcal{O}(N \log N)$
initialization.

```py
from sortedcontainers import SortedSet

sorted_set = SortedSet([5, 1, 3, 2])
print(sorted_set) # SortedSet([1, 2, 3, 4, 7])

# Add elements
sorted_set.add(4)
sorted_set.add(6)
print(sorted_set) # SortedSet([1, 2, 3, 4, 5, 6])

# Remove elements
sorted_set.discard(3)
sorted_set.discard(5)
print(sorted_set) # SortedSet([1, 2, 4, 6])

# Check if an element is in the sorted set
print(2 in sorted_set) # True
print(100 in sorted_set) # False

# Access elements by it's index
print(sorted_set[0]) # 1 (smallest element, first index)
print(sorted_set[-1]) # 6 (largest element, last index)
print(sorted_set[2]) # 4

# Get the index of an element
print(sorted_set.index(4)) # 2

# Find the index to insert the given value
print(sorted_set.bisect_left(2)) # 1
print(sorted_set.bisect_right(2)) # 2
```

</PySection>
</LanguageSection>

One limitation of sorted sets is that we can't efficiently access the $k^{th}$
Expand All @@ -207,7 +295,6 @@ structure called an [order statistic tree](/gold/PURS#order-statistic-tree).
## Sorted Maps

<LanguageSection>

<CPPSection>

The ordered `map` also allows:
Expand All @@ -231,7 +318,6 @@ if (m.upper_bound(10) == m.end()) {
```

</CPPSection>

<JavaSection>

The ordered map additionally supports `firstKey` / `firstEntry` and `lastKey` /
Expand All @@ -255,24 +341,74 @@ System.out.println(map.lowerKey(3)); // ERROR
```

</JavaSection>
<PySection>

Sorted maps in Python can be created by adding a dictionary to a sorted set,
where each element in the sorted set is a key in the dictionary and values can
be assigned with the dictionary. This is the most straightforward
implementation, and the ground up implementation of a sorted set can be found in
the above section.

Additionally, you can implement a `SortedDict` with the `sortedcontainers`
library. All operations shown below are $\mathcal{O}(\log N)$ time, except for
an $\mathcal{O}(N \log N)$ initialization and $\mathcal{O}(N)$ time to get all
items, keys, or values.

```py
from sortedcontainers import SortedDict

sorted_map = SortedDict({1: "one", 4: "four", 3: "three"})
print(sorted_map) # SortedDict({1: 'one', 3: 'three', 4: 'four'})

# Add elements
sorted_map[2] = "two"
sorted_map[5] = "five"

# Output SortedDict({1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'})
print(sorted_map)

# Remove elements
del sorted_map[3]
print(sorted_map) # SortedDict({1: 'one', 2: 'two', 4: 'four', 5: 'five'})

# Check if a key is in the sorted dict
print(1 in sorted_map) # True
print(100 in sorted_map) # False

# Get the key's value
print(sorted_map[2]) # two
print(sorted_map[4]) # four

# Get all items (key value pairs), keys, or values below
print(*sorted_map.items()) # (1, 'one') (2, 'two') (4, 'four') (5, 'five')
print(*sorted_map.keys()) # 1 2 4 5
print(*sorted_map.values()) # one two four five

# Find the index of an existing key
print(sorted_map.index(2)) # 1

# Find the index to insert a given key
print(sorted_map.bisect_left(3)) # 2
print(sorted_map.bisect_right(6)) # 4
```

</PySection>
</LanguageSection>

## Multisets

A **multiset** is a sorted set that allows multiple copies of the same element.

<LanguageSection>

<CPPSection>

In addition to all of the regular set operations,

- the `count()` method returns the number of times an element is present in the
multiset. However, this method takes time **linear** in the number of matches
so you shouldn't use it in a contest.
- To remove a value __once__, use `ms.erase(ms.find(val))`.
- To remove __all__ occurrences of a value, use `ms.erase(val)`.
- To remove a value **once**, use `ms.erase(ms.find(val))`.
- To remove **all** occurrences of a value, use `ms.erase(val)`.

<Warning>
Using `ms.erase(val)` erases __all__ instances of `val` from the multiset. To remove one instance of `val`, use `ms.erase(ms.find(val))`!
Expand All @@ -296,7 +432,6 @@ cout << ms.count(9) << '\n'; // 0
```

</CPPSection>

<JavaSection>

While there is no multiset in Java, we can implement one using the `TreeMap`
Expand Down Expand Up @@ -326,7 +461,6 @@ static void remove(int x) {
```

</JavaSection>

</LanguageSection>

## Priority Queues
Expand Down Expand Up @@ -392,11 +526,16 @@ pq.add(6); // [7, 6, 5]

In Python (unlike in C++), we delete and retrieve the **lowest** element.

Note that Python's priority queue is not encapsulated; `heapq` operates on a provided list directly by turning it into a heap, then doing operations on the heap.
Note that Python's priority queue is not encapsulated; `heapq` operates on a
provided list directly by turning it into a heap, then doing operations on the
heap.

<Warning>

Because of a heap's structure, printing out `pq` will **not** print out the elements in sorted order in Python; instead, it will print out the list. The comments below are a **representation** of what the heap contains, **not** what the contents of `pq` actually are.
Because of a heap's structure, printing out `pq` will **not** print out the
elements in sorted order in Python; instead, it will print out the list. The
comments below are a **representation** of what the heap contains, **not** what
the contents of `pq` actually are.

</Warning>

Expand Down
Loading