Skip to content

Commit a3042cd

Browse files
committed
Merge branch 'develop'
2 parents d014dc5 + 4768b66 commit a3042cd

26 files changed

+353
-172
lines changed

README.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ var list = Arrays.stream(arr).boxed().sorted().collect(Collectors.toCollection(A
156156

157157
- Advancing through an array, EPI#5.4: [c++](cpp-algorithm/src/array) | Advance through the array to the last index.
158158
- Arbitrary precision operation - increment an arbitrary-precision integer, EPI#5.2: [c++](cpp-algorithm/src/array)(`PlusOne`) | Add one to the number represented by the vector.
159-
- Arbitrary precision operation - add two arbitrary-precision integers: [c++](cpp-algorithm/src/array)((`StringAddition`)) | Add two numbers represented by strings.
159+
- Arbitrary precision operation - add two arbitrary-precision integers: [c++](cpp-algorithm/src/array)(`StringAddition`) | Add two numbers represented by strings.
160160
- Arbitrary precision operation - multiply two arbitrary-precision integers, EPI#5.3: [c++](cpp-algorithm/src/array)(`Multiply`) | Multiply two numbers represented by vectors.
161161
- Delete duplicates from a sorted array, EPI#5.5: [c++](cpp-algorithm/src/array)(`DeleteDuplicates`) | Delete duplicate elements in the array.
162162
- Delete duplicates from a sorted array: [c++](cpp-algorithm/src/array)(`DeleteDuplicateElements`) | Delete duplicate elements in the array.
@@ -260,7 +260,7 @@ algorithm DFS-VISIT(G, u):
260260
u.finished = time
261261
```
262262
263-
- Dijkstra's algorithm: [c++](cpp-algorithm/src/graph), [java](java-algorithm/src/main/java/com/example/algorithm/graph) | A single source shortest path algorithm that handle non-negative edge weights. It find the shortest path between two vertices in a graph.
263+
- Dijkstra's algorithm, CCSP#4.5.1: [c++](cpp-algorithm/src/graph),[python](python-algorithm/algorithm/graph/test)(test), [java](java-algorithm/src/main/java/com/example/algorithm/graph) | A single source the shortest path algorithm that handle non-negative edge weights. It find the shortest path between two vertices in a graph.
264264

265265
```txt
266266
algorithm Dijkstra(G, source):
@@ -347,6 +347,7 @@ algorithm Prim(G, root):
347347
**Examples**
348348

349349
- Maze problem: [java](java-algorithm/src/main/java/com/example/algorithm/graph) | A maze problem is that find a path from the start to the goal. The maze is represented by a graph. The start and the goal are represented by vertices. The path is represented by a sequence of vertices.
350+
- Minimum spanning tree (Kruskal, Prim, Boruvka), CCSP#4.4.2: [python](python-algorithm/algorithm/graph/test)(test) | Find the minimum spanning tree of a graph.
350351

351352
[:arrow_up_small: back to toc](#table-of-contents)
352353

@@ -994,9 +995,9 @@ list.sort(Comparator.comparingInt(String::length));
994995

995996
| **Case** | **Time complexity** | **Remarks** |
996997
| :---------- | :-----------------: | :-------------------------------------------------------------------------------------- |
997-
| **Best** | $O(n)$ | when the input list is already sorted in the desired order |
998+
| **Best** | $O(n)$ | when the input list is already sorted in the desired order (ascending or descending) |
998999
| **Worst** | $O(n^2)$ | when the input list is already sorted in the reverse order of the desired sorting order |
999-
| **Average** | $O(n^2)$ | |
1000+
| **Average** | $O(n^2)$ | when the input list is in jumbled order |
10001001

10011002
- Bucket sort: [java](java-algorithm/src/main/java/com/example/algorithm/sort) | Bucket sort is a sorting algorithm that works by distributing the elements of an array into a number of buckets. Each bucket contains a range of values and the elements are sorted within these buckets using any of the suitable sorting algorithms (such as insertion sort, merge sort, selection sort).<br>(`n` is the number of elements and `k` is the number of buckets)
10021003

@@ -1008,11 +1009,11 @@ list.sort(Comparator.comparingInt(String::length));
10081009

10091010
- Counting sort: [java](java-algorithm/src/main/java/com/example/algorithm/sort) | Counting sort is a non-comparative sorting algorithm that sorts the elements of an array by counting the occurrences of each element in the array. The count is stored in an auxiliary array and the sorting is done by mapping the count as an index of the auxiliary array. It is used as a subroutine in radix sort.<br>(`n` is the number of elements and `k` is the range of input values)
10101011

1011-
| **Case** | **Time complexity** | **Remarks** |
1012-
| ----------- | :-----------------: | ---------------------------------------------------- |
1013-
| **Best** | $O(n + k)$ | when the input elements have a small range of values |
1014-
| **Worst** | $O(n + k)$ | when the input elements have a large range of values |
1015-
| **Average** | $O(n + k)$ | |
1012+
| **Case** | **Time complexity** | **Remarks** |
1013+
| ----------- | :-----------------: | ------------------------------------------------------- |
1014+
| **Best** | $O(n + k)$ | when the input elements have a small range of values |
1015+
| **Worst** | $O(n + k)$ | when the input elements have a large range of values |
1016+
| **Average** | $O(n + k)$ | when the elements are distributed randomly in the array |
10161017

10171018
- Heap sort: [java](java-algorithm/src/main/java/com/example/algorithm/sort) | Heap sort is a comparison-based sorting algorithm that uses a binary heap data structure to sort an array. It is used for the implementation of priority queue.<br>(`n` is the number of elements)
10181019

@@ -1062,7 +1063,7 @@ list.sort(Comparator.comparingInt(String::length));
10621063
- Merge two sorted arrays, EPI#13.2, LeetCode#merge-sorted-array: [c++](cpp-algorithm/src/sort)(`MergeTwoSortedArray`) | Merge two sorted array. Merge the second array into the first array.
10631064
- Partitioning and sorting an array with many repeated entries, EPI#13.9: [java](java-algorithm/src/main/java/com/example/algorithm/sort)(`GroupByAge`) | Given an array of objects with an age field, reorder the array so that objects of equal age appear together. They should be sorted in ascending order of age, and the order of objects with the same age is not important.
10641065
- Remove first-name duplicates, EPI#13.4: [c++](cpp-algorithm/src/sort)(`EliminateFirstNameDuplicate`) | Given an array of names, remove the duplicates of the first name.
1065-
- Salary threadhold, EPI#13.12: [java](java-algorithm/src/main/java/com/example/algorithm/sort)(`SalaryThreshold`) | Given an array of salaries and a budget, compute the salary cap so that the total salaries equal the budget.
1066+
- Salary threshold, EPI#13.12: [java](java-algorithm/src/main/java/com/example/algorithm/sort)(`SalaryThreshold`) | Given an array of salaries and a budget, compute the salary cap so that the total salaries equal the budget.
10661067
- Team photo day, EPI#13.10: [java](java-algorithm/src/main/java/com/example/algorithm/sort)(`SortPlayerByHeight`) | Given two arrays of numbers, for team photos, players are arranged in front and back rows and then photographed. The players in the back row must necessarily be taller than those in the front row. Additionally, all players in a row should belong to the same team.
10671068
- Union of intervals, EPI#13.8: [c++](cpp-algorithm/src/sort)(`UnionOfIntervals`) | Given a set of intervals, compute their union.
10681069
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import networkx
2+
3+
seattle = 'Seattle'
4+
san_francisco = 'San Francisco'
5+
los_angeles = 'Los Angeles'
6+
riverside = 'Riverside'
7+
phoenix = 'Phoenix'
8+
dallas = 'Dallas'
9+
houston = 'Houston'
10+
atlanta = 'Atlanta'
11+
miami = 'Miami'
12+
chicago = 'Chicago'
13+
detroit = 'Detroit'
14+
boston = 'Boston'
15+
new_york = 'New York'
16+
philadelphia = 'Philadelphia'
17+
washington = 'Washington'
18+
19+
20+
def create_city_graph() -> networkx.Graph:
21+
edges = [
22+
(seattle, chicago),
23+
(seattle, san_francisco),
24+
(san_francisco, riverside),
25+
(san_francisco, los_angeles),
26+
(los_angeles, riverside),
27+
(los_angeles, phoenix),
28+
(riverside, phoenix),
29+
(riverside, chicago),
30+
(phoenix, dallas),
31+
(phoenix, houston),
32+
(dallas, chicago),
33+
(dallas, atlanta),
34+
(dallas, houston),
35+
(houston, atlanta),
36+
(houston, miami),
37+
(atlanta, chicago),
38+
(atlanta, washington),
39+
(atlanta, miami),
40+
(miami, washington),
41+
(chicago, detroit),
42+
(detroit, boston),
43+
(detroit, washington),
44+
(detroit, new_york),
45+
(boston, new_york),
46+
(new_york, philadelphia),
47+
(philadelphia, washington)
48+
]
49+
graph = networkx.Graph()
50+
graph.add_edges_from(edges)
51+
return graph
52+
53+
54+
def create_weighted_city_graph() -> networkx.Graph:
55+
weighted_edges = [
56+
(seattle, chicago, 1737),
57+
(seattle, san_francisco, 678),
58+
(san_francisco, riverside, 386),
59+
(san_francisco, los_angeles, 348),
60+
(los_angeles, riverside, 50),
61+
(los_angeles, phoenix, 357),
62+
(riverside, phoenix, 307),
63+
(riverside, chicago, 1704),
64+
(phoenix, dallas, 887),
65+
(phoenix, houston, 1015),
66+
(dallas, chicago, 805),
67+
(dallas, atlanta, 721),
68+
(dallas, houston, 225),
69+
(houston, atlanta, 702),
70+
(houston, miami, 968),
71+
(atlanta, chicago, 588),
72+
(atlanta, washington, 543),
73+
(atlanta, miami, 604),
74+
(miami, washington, 923),
75+
(chicago, detroit, 238),
76+
(detroit, boston, 613),
77+
(detroit, washington, 396),
78+
(detroit, new_york, 482),
79+
(boston, new_york, 190),
80+
(new_york, philadelphia, 81),
81+
(philadelphia, washington, 123)
82+
]
83+
graph = networkx.Graph()
84+
graph.add_weighted_edges_from(weighted_edges)
85+
return graph
Lines changed: 46 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,64 @@
1-
import pytest, networkx
2-
3-
4-
def create_city_graph() -> networkx.Graph:
5-
graph = networkx.Graph()
6-
graph.add_edge("Seattle", "Chicago")
7-
graph.add_edge("Seattle", "San Francisco")
8-
graph.add_edge("San Francisco", "Riverside")
9-
graph.add_edge("San Francisco", "Los Angeles")
10-
graph.add_edge("Los Angeles", "Riverside")
11-
graph.add_edge("Los Angeles", "Phoenix")
12-
graph.add_edge("Riverside", "Phoenix")
13-
graph.add_edge("Riverside", "Chicago")
14-
graph.add_edge("Phoenix", "Dallas")
15-
graph.add_edge("Phoenix", "Houston")
16-
graph.add_edge("Dallas", "Chicago")
17-
graph.add_edge("Dallas", "Atlanta")
18-
graph.add_edge("Dallas", "Houston")
19-
graph.add_edge("Houston", "Atlanta")
20-
graph.add_edge("Houston", "Miami")
21-
graph.add_edge("Atlanta", "Chicago")
22-
graph.add_edge("Atlanta", "Washington")
23-
graph.add_edge("Atlanta", "Miami")
24-
graph.add_edge("Miami", "Washington")
25-
graph.add_edge("Chicago", "Detroit")
26-
graph.add_edge("Detroit", "Boston")
27-
graph.add_edge("Detroit", "Washington")
28-
graph.add_edge("Detroit", "New York")
29-
graph.add_edge("Boston", "New York")
30-
graph.add_edge("New York", "Philadelphia")
31-
graph.add_edge("Philadelphia", "Washington")
32-
return graph
1+
import networkx
2+
import pytest
333

4+
from algorithm.graph.test.graph_data_utils import create_city_graph
345

356
city_graph = create_city_graph()
367

378

389
@pytest.mark.benchmark(group='graph_neighbors')
3910
@pytest.mark.parametrize(
40-
argnames='graph, source, expected',
11+
argnames='graph, source, expected_neighbors',
4112
argvalues=[
42-
(city_graph, "Seattle", ["Chicago", "San Francisco"]),
43-
(city_graph, "San Francisco", ["Seattle", "Riverside", "Los Angeles"]),
44-
(city_graph, "Los Angeles", ["San Francisco", "Riverside", "Phoenix"]),
45-
(city_graph, "Riverside", ["San Francisco", "Los Angeles", "Phoenix", "Chicago"]),
46-
(city_graph, "Phoenix", ["Los Angeles", "Riverside", "Dallas", "Houston"]),
47-
(city_graph, "Chicago", ["Seattle", "Riverside", "Dallas", "Atlanta", "Detroit"]),
48-
(city_graph, "Boston", ["Detroit", "New York"]),
49-
(city_graph, "New York", ["Detroit", "Boston", "Philadelphia"]),
50-
(city_graph, "Atlanta", ["Dallas", "Houston", "Chicago", "Washington", "Miami"]),
51-
(city_graph, "Miami", ["Houston", "Atlanta", "Washington"]),
52-
(city_graph, "Dallas", ["Phoenix", "Chicago", "Atlanta", "Houston"]),
53-
(city_graph, "Houston", ["Phoenix", "Dallas", "Atlanta", "Miami"]),
54-
(city_graph, "Detroit", ["Chicago", "Boston", "Washington", "New York"]),
55-
(city_graph, "Philadelphia", ["New York", "Washington"]),
56-
(city_graph, "Washington", ["Atlanta", "Miami", "Detroit", "Philadelphia"])
13+
(city_graph, 'Seattle', ['Chicago', 'San Francisco']),
14+
(city_graph, 'San Francisco', ['Seattle', 'Riverside', 'Los Angeles']),
15+
(city_graph, 'Los Angeles', ['San Francisco', 'Riverside', 'Phoenix']),
16+
(city_graph, 'Riverside', ['San Francisco', 'Los Angeles', 'Phoenix', 'Chicago']),
17+
(city_graph, 'Phoenix', ['Los Angeles', 'Riverside', 'Dallas', 'Houston']),
18+
(city_graph, 'Chicago', ['Seattle', 'Riverside', 'Dallas', 'Atlanta', 'Detroit']),
19+
(city_graph, 'Boston', ['Detroit', 'New York']),
20+
(city_graph, 'New York', ['Detroit', 'Boston', 'Philadelphia']),
21+
(city_graph, 'Atlanta', ['Dallas', 'Houston', 'Chicago', 'Washington', 'Miami']),
22+
(city_graph, 'Miami', ['Houston', 'Atlanta', 'Washington']),
23+
(city_graph, 'Dallas', ['Phoenix', 'Chicago', 'Atlanta', 'Houston']),
24+
(city_graph, 'Houston', ['Phoenix', 'Dallas', 'Atlanta', 'Miami']),
25+
(city_graph, 'Detroit', ['Chicago', 'Boston', 'Washington', 'New York']),
26+
(city_graph, 'Philadelphia', ['New York', 'Washington']),
27+
(city_graph, 'Washington', ['Atlanta', 'Miami', 'Detroit', 'Philadelphia'])
5728
])
58-
def test_graph_neighbors(benchmark, graph, source, expected):
59-
result = benchmark(graph.neighbors, source)
60-
assert sorted(expected) == sorted(result)
29+
def test_graph_neighbors(benchmark, graph, source, expected_neighbors):
30+
"""
31+
Find the neighboring city nodes of the source city node in the United States city graph.
32+
:param benchmark: benchmark fixture
33+
:param graph: city graph of the United States
34+
:param source: source city node
35+
:param expected_neighbors: list of neighboring city nodes
36+
"""
37+
neighbor_iterator = benchmark(graph.neighbors, source)
38+
assert sorted(expected_neighbors) == sorted(neighbor_iterator)
6139

6240

6341
@pytest.mark.benchmark(group='graph_breadth_first_search')
6442
@pytest.mark.parametrize(
65-
argnames='graph, source, distance, expected',
43+
argnames='graph, source, distance, expected_nodes',
6644
argvalues=[
67-
(city_graph, "Boston", 1, ["Detroit", "New York"]),
68-
(city_graph, "Boston", 2, ["Chicago", "Washington", "Philadelphia"]),
69-
(city_graph, "Boston", 3, ["Seattle", "Riverside", "Dallas", "Atlanta", "Miami"]),
45+
(city_graph, 'Boston', 1, ['Detroit', 'New York']),
46+
(city_graph, 'Boston', 2, ['Chicago', 'Washington', 'Philadelphia']),
47+
(city_graph, 'Boston', 3, ['Seattle', 'Riverside', 'Dallas', 'Atlanta', 'Miami']),
7048
],
71-
ids=["distance1", "distance2", "distance3"])
72-
def test_graph_breadth_first_search(benchmark, graph, source, distance, expected):
49+
ids=['distance1', 'distance2', 'distance3'])
50+
def test_graph_breadth_first_search(benchmark, graph, source, distance, expected_nodes):
51+
"""
52+
Find the city nodes at a given distance from the source city node in the United States city graph.
53+
:param benchmark: benchmark fixture
54+
:param graph: city graph of the United States
55+
:param source: source city node
56+
:param distance: distance from the source city node
57+
:param expected_nodes: list of city nodes at the given distance from the source city node
58+
"""
7359
bfs_generator = benchmark(networkx.bfs_layers, graph, source)
74-
path = []
60+
nodes = []
7561
for i, layer in enumerate(bfs_generator):
7662
if i == distance:
77-
path = list(layer)
78-
assert path == expected
63+
nodes = list(layer)
64+
assert nodes == expected_nodes
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import networkx
2+
import pytest
3+
4+
from algorithm.graph.test.graph_data_utils import create_weighted_city_graph
5+
6+
city_graph = create_weighted_city_graph()
7+
8+
9+
@pytest.mark.benchmark(group='graph_dijkstra')
10+
@pytest.mark.parametrize(
11+
argnames='graph, source, target, expected_path',
12+
argvalues=[
13+
(city_graph, 'Los Angeles', 'Boston', ['Los Angeles', 'Riverside', 'Chicago', 'Detroit', 'Boston']),
14+
],
15+
ids=['los_angeles_to_boston'])
16+
def test_graph_dijkstra_path(benchmark, graph, source, target, expected_path):
17+
"""
18+
Find the shortest path between two nodes in a graph using Dijkstra's algorithm.
19+
:param benchmark: benchmark fixture
20+
:param graph: city graph of the United States
21+
:param source: source city node
22+
:param target: target city node
23+
:param expected_path: expected shortest path
24+
"""
25+
shortest_path = benchmark(networkx.dijkstra_path, graph, source, target)
26+
assert shortest_path == expected_path
27+
28+
29+
@pytest.mark.benchmark(group='graph_dijkstra')
30+
@pytest.mark.parametrize(
31+
argnames='graph, source, target, expected_distance',
32+
argvalues=[
33+
(city_graph, 'Los Angeles', 'Boston', 2605),
34+
],
35+
ids=['los_angeles_to_boston'])
36+
def test_graph_dijkstra_distance(benchmark, graph, source, target, expected_distance):
37+
"""
38+
Find the shortest distance between two nodes in a graph using Dijkstra's algorithm.
39+
:param benchmark: benchmark fixture
40+
:param graph: city graph of the United States
41+
:param source: source city node
42+
:param target: target city node
43+
:param expected_distance: expected shortest distance (weight)
44+
"""
45+
total_weight = benchmark(networkx.dijkstra_path_length, graph, source, target)
46+
assert total_weight == expected_distance
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import matplotlib.pyplot as plt
2+
import networkx
3+
import pytest
4+
5+
from algorithm.graph.test.graph_data_utils import create_weighted_city_graph
6+
7+
city_graph = create_weighted_city_graph()
8+
9+
10+
@pytest.mark.skip(reason='This test is for visualization only')
11+
def test_graph_mst_temp():
12+
mst = networkx.minimum_spanning_tree(city_graph, algorithm='kruskal')
13+
pos = networkx.spring_layout(mst)
14+
networkx.draw_networkx_nodes(mst, pos)
15+
networkx.draw_networkx_edges(mst, pos, width=1)
16+
networkx.draw_networkx_labels(mst, pos, font_size=10)
17+
plt.show()
18+
19+
20+
city_edges = {('Seattle', 'San Francisco'), ('San Francisco', 'Los Angeles'), ('Los Angeles', 'Riverside'),
21+
('Riverside', 'Phoenix'), ('Phoenix', 'Dallas'), ('Dallas', 'Houston'), ('Houston', 'Atlanta'),
22+
('Atlanta', 'Miami'), ('Atlanta', 'Washington'), ('Washington', 'Philadelphia'),
23+
('Philadelphia', 'New York'), ('New York', 'Boston'), ('Washington', 'Detroit'), ('Detroit', 'Chicago')}
24+
25+
26+
@pytest.mark.benchmark(group='graph_minimum_spanning_tree')
27+
@pytest.mark.parametrize(
28+
argnames='graph, algorithm, expected_total_weight, expected_edges',
29+
argvalues=[
30+
(city_graph, 'kruskal', 5372, city_edges),
31+
(city_graph, 'prim', 5372, city_edges),
32+
(city_graph, 'boruvka', 5372, city_edges),
33+
],
34+
ids=['kruskal', 'prim', 'boruvka'])
35+
def test_graph_mst(benchmark, graph, algorithm, expected_total_weight, expected_edges):
36+
mst = benchmark(networkx.minimum_spanning_tree, graph, algorithm=algorithm)
37+
38+
mst_total_weight = sum(d['weight'] for u, v, d in mst.edges(data=True))
39+
assert expected_total_weight == mst_total_weight
40+
41+
mst_edges = set((u, v) for u, v, d in mst.edges(data=True))
42+
normalized_set1 = {tuple(sorted(edge)) for edge in expected_edges}
43+
normalized_set2 = {tuple(sorted(edge)) for edge in mst_edges}
44+
assert normalized_set1 == normalized_set2

python-algorithm/algorithm/greedy/cashier_change.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
def cashier_change(denominations: list[int], price: int) -> int:
2+
"""
3+
Find the minimum number of coins needed to make change for a given amount of money.
4+
:param denominations: list of coin denominations
5+
:param price: amount of money
6+
:return: minimum number of coins
7+
"""
28
change = price
39
coins = 0
410

0 commit comments

Comments
 (0)