2662. Minimum Cost of a Path With Special Roads
Problem Description
You are given a starting position and a target position on a 2D plane, and you need to find the minimum cost to travel from start to target.
The problem provides:
start = [startX, startY]
: your initial position coordinatestarget = [targetX, targetY]
: your destination coordinatesspecialRoads
: an array of special one-way roads
The normal cost of moving from any position (x1, y1)
to another position (x2, y2)
is the Manhattan distance: |x2 - x1| + |y2 - y1|
.
However, there are special roads that can potentially reduce travel cost. Each special road is defined as [x1, y1, x2, y2, cost]
, which means:
- The road goes from position
(x1, y1)
to position(x2, y2)
- The road is one-directional (can only be traveled from
(x1, y1)
to(x2, y2)
) - Using this road costs exactly
cost
units (which may be less than the Manhattan distance) - You can use any special road multiple times
Your task is to find the minimum total cost to reach the target from the start position. You can:
- Move directly using Manhattan distance between any two points
- Use special roads when beneficial
- Combine regular movement and special roads in any way
For example, you might walk normally to the start of a special road, use the special road, then walk normally from its end to your target - if that results in a lower total cost than walking directly.
Intuition
The key insight is that this is a shortest path problem in a graph where we need to consider both normal movement and special roads.
Think about it this way: at any position (x, y)
we're currently at, we have multiple choices:
- Walk directly to the target (cost: Manhattan distance)
- Walk to the start of any special road, use that road, and continue from there
Since special roads might offer shortcuts, we can't just greedily walk straight to the target. We need to explore different paths and find the one with minimum cost.
The critical observation is that special roads have fixed endpoints. This means the only "interesting" positions we need to consider are:
- Our starting position
- The endpoints of special roads (both start and end points)
- Our target position
From any position, we can either:
- Go directly to the target
- Go to the start of a special road (paying Manhattan distance), then use that road
This naturally leads to a graph search problem where we want to find the minimum cost path. Since we're dealing with weighted edges (different costs for different paths), Dijkstra's algorithm is perfect for this.
The algorithm explores positions in order of their distance from the start. For each position (x, y)
we visit with cost d
:
- We check if going directly to the target from here is better:
d + dist(x, y, target)
- We consider taking each special road by first walking to its start:
d + dist(x, y, road_start) + road_cost
By processing positions in order of increasing cost (using a priority queue), we ensure we always find the optimal path to each position first. Eventually, we'll have considered all possible combinations of walking and using special roads, giving us the minimum cost to reach the target.
Learn more about Graph, Shortest Path and Heap (Priority Queue) patterns.
Solution Approach
We implement Dijkstra's algorithm to find the shortest path from start to target, considering both normal movement and special roads.
Data Structures Used:
- Priority Queue (
heappop
/heappush
): Stores positions to visit, ordered by their minimum cost from the start - Visited Set (
vis
): Tracks positions we've already processed to avoid redundant calculations
Implementation Steps:
-
Initialize the priority queue with the starting position:
q = [(0, start[0], start[1])]
- The tuple format is
(cost, x, y)
where cost is 0 initially
- The tuple format is
-
Define a helper function
dist(x1, y1, x2, y2)
to calculate Manhattan distance between two points -
Process positions using Dijkstra's algorithm:
while q: d, x, y = heappop(q) # Get position with minimum cost if (x, y) in vis: # Skip if already processed continue vis.add((x, y)) # Mark as visited
-
For each position
(x, y)
with costd
:- Update the answer by considering direct movement to target:
ans = min(ans, d + dist(x, y, *target))
- Consider all special roads: For each special road from
(x1, y1)
to(x2, y2)
with costcost
:
This adds the endpointheappush(q, (d + dist(x, y, x1, y1) + cost, x2, y2))
(x2, y2)
to our queue with total cost:d
: cost to reach current positiondist(x, y, x1, y1)
: cost to walk to the special road's startcost
: cost to use the special road
- Update the answer by considering direct movement to target:
Why this works:
- Dijkstra's algorithm guarantees we process positions in order of increasing distance from the start
- When we first visit a position, we've found the minimum cost to reach it
- By considering all special roads from each position, we explore all possible path combinations
- The algorithm naturally handles using multiple special roads in sequence
- The final answer is the minimum of all possible ways to reach the target
Time Complexity: O(n² log n)
where n
is the number of special roads, since we might visit each road endpoint and for each, we consider all special roads.
Space Complexity: O(n)
for the priority queue and visited set.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to illustrate the solution approach.
Given:
start = [1, 1]
target = [4, 5]
specialRoads = [[1, 2, 3, 3, 2], [3, 4, 4, 5, 1]]
- Road 1: from (1,2) to (3,3) with cost 2
- Road 2: from (3,4) to (4,5) with cost 1
Step-by-step execution:
Initial Setup:
- Priority queue:
[(0, 1, 1)]
- start at (1,1) with cost 0 - Visited set: empty
- Answer: infinity
Iteration 1: Pop (0, 1, 1)
- Mark (1,1) as visited
- Direct to target: cost = 0 + |4-1| + |5-1| = 0 + 3 + 4 = 7
- Update answer to 7
- Consider special roads:
- Road 1: Walk to (1,2) costs |1-1| + |2-1| = 1, then use road (cost 2) to reach (3,3)
- Add to queue:
(0 + 1 + 2, 3, 3)
=(3, 3, 3)
- Add to queue:
- Road 2: Walk to (3,4) costs |3-1| + |4-1| = 5, then use road (cost 1) to reach (4,5)
- Add to queue:
(0 + 5 + 1, 4, 5)
=(6, 4, 5)
- Add to queue:
- Road 1: Walk to (1,2) costs |1-1| + |2-1| = 1, then use road (cost 2) to reach (3,3)
- Queue now:
[(3, 3, 3), (6, 4, 5)]
Iteration 2: Pop (3, 3, 3)
- Mark (3,3) as visited
- Direct to target: cost = 3 + |4-3| + |5-3| = 3 + 1 + 2 = 6
- Update answer to 6 (better than 7)
- Consider special roads:
- Road 1: Walk to (1,2) costs |1-3| + |2-3| = 3, total would be 3 + 3 + 2 = 8 to reach (3,3) - but (3,3) is already visited, so this gets skipped
- Road 2: Walk to (3,4) costs |3-3| + |4-3| = 1, then use road (cost 1) to reach (4,5)
- Add to queue:
(3 + 1 + 1, 4, 5)
=(5, 4, 5)
- Add to queue:
- Queue now:
[(5, 4, 5), (6, 4, 5)]
Iteration 3: Pop (5, 4, 5)
- Mark (4,5) as visited
- Direct to target: cost = 5 + |4-4| + |5-5| = 5 + 0 = 5
- Update answer to 5 (better than 6)
- Consider special roads (both start positions would require walking backwards, making them non-optimal)
Iteration 4: Pop (6, 4, 5)
- (4,5) already visited, skip
Result: Minimum cost is 5
Path taken: Start (1,1) → Walk to (1,2) with cost 1 → Use Road 1 to (3,3) with cost 2 → Walk to (3,4) with cost 1 → Use Road 2 to (4,5) with cost 1 → Total: 1 + 2 + 1 + 1 = 5
This beats the direct Manhattan distance of 7 by cleverly using both special roads!
Solution Implementation
1from heapq import heappush, heappop
2from typing import List
3from math import inf
4
5class Solution:
6 def minimumCost(
7 self, start: List[int], target: List[int], specialRoads: List[List[int]]
8 ) -> int:
9 """
10 Find the minimum cost to travel from start to target using special roads.
11 Uses Dijkstra's algorithm to explore paths with special roads.
12
13 Args:
14 start: Starting coordinates [x, y]
15 target: Target coordinates [x, y]
16 specialRoads: List of special roads [x1, y1, x2, y2, cost]
17
18 Returns:
19 Minimum cost to reach target from start
20 """
21
22 def calculate_manhattan_distance(x1: int, y1: int, x2: int, y2: int) -> int:
23 """Calculate Manhattan distance between two points."""
24 return abs(x1 - x2) + abs(y1 - y2)
25
26 # Priority queue: (cost, x_coordinate, y_coordinate)
27 priority_queue = [(0, start[0], start[1])]
28
29 # Set to track visited positions to avoid reprocessing
30 visited_positions = set()
31
32 # Initialize minimum cost to infinity
33 min_cost = inf
34
35 # Dijkstra's algorithm
36 while priority_queue:
37 # Pop position with minimum cost so far
38 current_cost, current_x, current_y = heappop(priority_queue)
39
40 # Skip if this position was already visited
41 if (current_x, current_y) in visited_positions:
42 continue
43
44 # Mark current position as visited
45 visited_positions.add((current_x, current_y))
46
47 # Update minimum cost if we can reach target directly from current position
48 direct_to_target_cost = current_cost + calculate_manhattan_distance(
49 current_x, current_y, target[0], target[1]
50 )
51 min_cost = min(min_cost, direct_to_target_cost)
52
53 # Explore all special roads from current position
54 for road_start_x, road_start_y, road_end_x, road_end_y, road_cost in specialRoads:
55 # Calculate total cost to reach road end via this special road
56 cost_to_road_start = calculate_manhattan_distance(
57 current_x, current_y, road_start_x, road_start_y
58 )
59 total_cost_to_road_end = current_cost + cost_to_road_start + road_cost
60
61 # Add road end position to priority queue for exploration
62 heappush(priority_queue, (total_cost_to_road_end, road_end_x, road_end_y))
63
64 return min_cost
65
1class Solution {
2 public int minimumCost(int[] start, int[] target, int[][] specialRoads) {
3 // Initialize the minimum cost to a large value
4 int minCost = 1 << 30;
5
6 // Large constant used for encoding coordinates into a single long value
7 int COORDINATE_MULTIPLIER = 1000000;
8
9 // Priority queue to store states: [cost, x, y], ordered by cost
10 PriorityQueue<int[]> priorityQueue = new PriorityQueue<>((a, b) -> a[0] - b[0]);
11
12 // Set to track visited positions (encoded as long values)
13 Set<Long> visited = new HashSet<>();
14
15 // Start from the initial position with cost 0
16 priorityQueue.offer(new int[] {0, start[0], start[1]});
17
18 // Dijkstra's algorithm to find the minimum cost path
19 while (!priorityQueue.isEmpty()) {
20 int[] current = priorityQueue.poll();
21 int currentCost = current[0];
22 int currentX = current[1];
23 int currentY = current[2];
24
25 // Encode current position as a single long value for visited check
26 long encodedPosition = 1L * currentX * COORDINATE_MULTIPLIER + currentY;
27
28 // Skip if this position has already been visited
29 if (visited.contains(encodedPosition)) {
30 continue;
31 }
32
33 // Mark current position as visited
34 visited.add(encodedPosition);
35
36 // Update minimum cost if we can reach target from current position
37 int costToTarget = currentCost + dist(currentX, currentY, target[0], target[1]);
38 minCost = Math.min(minCost, costToTarget);
39
40 // Explore all special roads from current position
41 for (int[] road : specialRoads) {
42 int roadStartX = road[0];
43 int roadStartY = road[1];
44 int roadEndX = road[2];
45 int roadEndY = road[3];
46 int roadCost = road[4];
47
48 // Calculate total cost to reach the end of this special road
49 int costToRoadStart = dist(currentX, currentY, roadStartX, roadStartY);
50 int totalCost = currentCost + costToRoadStart + roadCost;
51
52 // Add new state to priority queue
53 priorityQueue.offer(new int[] {totalCost, roadEndX, roadEndY});
54 }
55 }
56
57 return minCost;
58 }
59
60 /**
61 * Calculate Manhattan distance between two points
62 * @param x1 x-coordinate of first point
63 * @param y1 y-coordinate of first point
64 * @param x2 x-coordinate of second point
65 * @param y2 y-coordinate of second point
66 * @return Manhattan distance between the two points
67 */
68 private int dist(int x1, int y1, int x2, int y2) {
69 return Math.abs(x1 - x2) + Math.abs(y1 - y2);
70 }
71}
72
1class Solution {
2public:
3 int minimumCost(vector<int>& start, vector<int>& target, vector<vector<int>>& specialRoads) {
4 // Lambda function to calculate Manhattan distance between two points
5 auto calculateManhattanDistance = [](int x1, int y1, int x2, int y2) {
6 return abs(x1 - x2) + abs(y1 - y2);
7 };
8
9 // Initialize the minimum cost to a large value
10 int minCost = 1 << 30; // Equivalent to 2^30
11
12 // Constant for encoding coordinates into a single value
13 const int ENCODING_FACTOR = 1e6;
14
15 // Priority queue for Dijkstra's algorithm
16 // Stores tuples of (distance, x-coordinate, y-coordinate)
17 // Using greater<> for min-heap behavior
18 priority_queue<tuple<int, int, int>,
19 vector<tuple<int, int, int>>,
20 greater<tuple<int, int, int>>> pq;
21
22 // Start from the initial position with cost 0
23 pq.push({0, start[0], start[1]});
24
25 // Set to track visited positions to avoid revisiting
26 unordered_set<long long> visitedPositions;
27
28 // Dijkstra's algorithm main loop
29 while (!pq.empty()) {
30 // Extract the position with minimum distance
31 auto [currentDistance, currentX, currentY] = pq.top();
32 pq.pop();
33
34 // Encode current position into a single value for visited check
35 long long encodedPosition = 1LL * currentX * ENCODING_FACTOR + currentY;
36
37 // Skip if this position has already been visited
38 if (visitedPositions.count(encodedPosition)) {
39 continue;
40 }
41
42 // Mark current position as visited
43 visitedPositions.insert(encodedPosition);
44
45 // Update minimum cost by considering direct path from current position to target
46 minCost = min(minCost,
47 currentDistance + calculateManhattanDistance(currentX, currentY,
48 target[0], target[1]));
49
50 // Explore all special roads from current position
51 for (auto& road : specialRoads) {
52 int roadStartX = road[0];
53 int roadStartY = road[1];
54 int roadEndX = road[2];
55 int roadEndY = road[3];
56 int roadCost = road[4];
57
58 // Calculate total cost: current distance + distance to road start + road cost
59 int totalCost = currentDistance +
60 calculateManhattanDistance(currentX, currentY, roadStartX, roadStartY) +
61 roadCost;
62
63 // Add the road's end position to the priority queue
64 pq.push({totalCost, roadEndX, roadEndY});
65 }
66 }
67
68 return minCost;
69 }
70};
71
1// Calculate Manhattan distance between two points
2function calculateManhattanDistance(x1: number, y1: number, x2: number, y2: number): number {
3 return Math.abs(x1 - x2) + Math.abs(y1 - y2);
4}
5
6// Compare function for priority queue (min-heap based on cost)
7function compareByCost(a: [number, number, number], b: [number, number, number]): number {
8 return a[0] - b[0];
9}
10
11// Main function to find minimum cost path from start to target using special roads
12function minimumCost(start: number[], target: number[], specialRoads: number[][]): number {
13 // Priority queue to store [cost, x, y] tuples, ordered by cost
14 const priorityQueue = new Heap<[number, number, number]>(compareByCost);
15
16 // Start from the initial position with cost 0
17 priorityQueue.push([0, start[0], start[1]]);
18
19 // Constant for encoding coordinates into a single number
20 const COORDINATE_MULTIPLIER = 1000000;
21
22 // Set to track visited positions to avoid revisiting
23 const visitedPositions: Set<number> = new Set();
24
25 // Initialize answer with a large value
26 let minimumTotalCost = 1 << 30;
27
28 // Dijkstra's algorithm to find shortest path
29 while (priorityQueue.size()) {
30 // Get the position with minimum cost so far
31 const [currentCost, currentX, currentY] = priorityQueue.pop();
32
33 // Encode current position as a single number for efficient storage
34 const encodedPosition = currentX * COORDINATE_MULTIPLIER + currentY;
35
36 // Skip if this position has already been visited
37 if (visitedPositions.has(encodedPosition)) {
38 continue;
39 }
40
41 // Mark current position as visited
42 visitedPositions.add(encodedPosition);
43
44 // Update minimum cost if direct path from current position to target is better
45 minimumTotalCost = Math.min(
46 minimumTotalCost,
47 currentCost + calculateManhattanDistance(currentX, currentY, target[0], target[1])
48 );
49
50 // Explore all special roads from current position
51 for (const [roadStartX, roadStartY, roadEndX, roadEndY, roadCost] of specialRoads) {
52 // Calculate total cost: current cost + distance to road start + road cost
53 const totalCostToRoadEnd = currentCost +
54 calculateManhattanDistance(currentX, currentY, roadStartX, roadStartY) +
55 roadCost;
56
57 // Add road end position to priority queue for exploration
58 priorityQueue.push([totalCostToRoadEnd, roadEndX, roadEndY]);
59 }
60 }
61
62 return minimumTotalCost;
63}
64
65// Type definition for comparison function
66type Compare<T> = (lhs: T, rhs: T) => number;
67
68// Min-heap implementation for priority queue
69class Heap<T = number> {
70 // Internal array storage with null at index 0 for easier indexing
71 data: Array<T | null>;
72 // Comparison function for heap ordering
73 lt: (i: number, j: number) => boolean;
74
75 // Constructor overloads
76 constructor();
77 constructor(data: T[]);
78 constructor(compare: Compare<T>);
79 constructor(data: T[], compare: Compare<T>);
80 constructor(
81 data: T[] | Compare<T> = [],
82 compare: Compare<T> = (lhs: T, rhs: T) => (lhs < rhs ? -1 : lhs > rhs ? 1 : 0),
83 ) {
84 // Handle case where first parameter is comparison function
85 if (typeof data === 'function') {
86 compare = data;
87 data = [];
88 }
89
90 // Initialize data array with null at index 0 for 1-based indexing
91 this.data = [null, ...data];
92
93 // Define less-than comparison using provided compare function
94 this.lt = (i, j) => compare(this.data[i]!, this.data[j]!) < 0;
95
96 // Heapify all elements to maintain heap property
97 for (let i = this.size(); i > 0; i--) {
98 this.heapify(i);
99 }
100 }
101
102 // Return number of elements in heap
103 size(): number {
104 return this.data.length - 1;
105 }
106
107 // Add new element and maintain heap property
108 push(v: T): void {
109 this.data.push(v);
110 let currentIndex = this.size();
111
112 // Bubble up: swap with parent while current is smaller
113 while (currentIndex >> 1 !== 0 && this.lt(currentIndex, currentIndex >> 1)) {
114 this.swap(currentIndex, currentIndex >> 1);
115 currentIndex >>= 1;
116 }
117 }
118
119 // Remove and return minimum element
120 pop(): T {
121 // Move last element to root
122 this.swap(1, this.size());
123 const minElement = this.data.pop();
124
125 // Restore heap property from root
126 this.heapify(1);
127 return minElement!;
128 }
129
130 // Return minimum element without removing
131 top(): T {
132 return this.data[1]!;
133 }
134
135 // Restore heap property starting from index i
136 heapify(i: number): void {
137 while (true) {
138 let minIndex = i;
139 const leftChild = i * 2;
140 const rightChild = i * 2 + 1;
141 const heapSize = this.data.length;
142
143 // Find minimum among current node and its children
144 if (leftChild < heapSize && this.lt(leftChild, minIndex)) {
145 minIndex = leftChild;
146 }
147 if (rightChild < heapSize && this.lt(rightChild, minIndex)) {
148 minIndex = rightChild;
149 }
150
151 // If current is not minimum, swap and continue
152 if (minIndex !== i) {
153 this.swap(i, minIndex);
154 i = minIndex;
155 } else {
156 break;
157 }
158 }
159 }
160
161 // Remove all elements from heap
162 clear(): void {
163 this.data = [null];
164 }
165
166 // Swap elements at indices i and j
167 private swap(i: number, j: number): void {
168 const tempData = this.data;
169 [tempData[i], tempData[j]] = [tempData[j], tempData[i]];
170 }
171}
172
Time and Space Complexity
Time Complexity: O(n^2 × log n)
, where n
is the number of special roads.
The algorithm uses Dijkstra's algorithm with a priority queue (min-heap). Here's the breakdown:
- Each special road endpoint can be visited at most once due to the visited set
vis
- There are at most
n
special road endpoints plus the starting point, giving usO(n)
possible positions - For each position we visit, we examine all
n
special roads to potentially add their endpoints to the queue - Each heap operation (push/pop) takes
O(log m)
time, wherem
is the size of the heap - In the worst case, the heap can contain
O(n^2)
elements (each of then
positions could potentially be reached via each of then
special roads) - Total operations:
O(n)
positions ×O(n)
special roads per position ×O(log n^2)
per heap operation =O(n^2 × 2log n)
=O(n^2 × log n)
Space Complexity: O(n^2)
The space usage comes from:
- The priority queue
q
can contain at mostO(n^2)
elements in the worst case (each endpoint of each special road could be added multiple times before being visited) - The visited set
vis
stores at mostO(n)
positions (one for each special road endpoint plus the start) - The overall space complexity is dominated by the priority queue:
O(n^2)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Not Considering Direct Path to Target
Pitfall: A common mistake is only updating the minimum cost when reaching the exact target position through the priority queue, rather than considering the direct path from every visited position to the target.
Why it happens: Developers might think they need to reach the target position exactly through the graph traversal, forgetting that you can walk directly from any position to the target using Manhattan distance.
Incorrect approach:
while priority_queue: current_cost, current_x, current_y = heappop(priority_queue) # Wrong: Only check if we've reached the target if current_x == target[0] and current_y == target[1]: return current_cost # Process special roads...
Correct approach: Always calculate the cost to reach the target directly from each visited position:
while priority_queue:
current_cost, current_x, current_y = heappop(priority_queue)
# Correct: Consider direct path to target from current position
min_cost = min(min_cost, current_cost + calculate_manhattan_distance(
current_x, current_y, target[0], target[1]
))
2. Using Special Roads Only When Cost is Less Than Manhattan Distance
Pitfall: Filtering out special roads where the road cost is greater than or equal to the Manhattan distance between the road's endpoints.
Why it happens: It seems logical that a special road with cost ≥ Manhattan distance wouldn't be useful, but this ignores that the road might position you better for subsequent moves.
Incorrect approach:
for road_start_x, road_start_y, road_end_x, road_end_y, road_cost in specialRoads: # Wrong: Filtering "inefficient" roads manhattan = calculate_manhattan_distance(road_start_x, road_start_y, road_end_x, road_end_y) if road_cost >= manhattan: continue # Skip this road - WRONG! # Process road...
Why this is wrong: Even if a special road costs more than the direct Manhattan distance between its endpoints, it might still be part of the optimal path because:
- It could position you closer to other beneficial special roads
- The detour might align better with the overall path to the target
- Multiple "inefficient" roads combined might create an efficient route
Correct approach: Consider all special roads without filtering:
for road_start_x, road_start_y, road_end_x, road_end_y, road_cost in specialRoads: # Consider all roads regardless of their individual efficiency cost_to_road_start = calculate_manhattan_distance( current_x, current_y, road_start_x, road_start_y ) total_cost = current_cost + cost_to_road_start + road_cost heappush(priority_queue, (total_cost, road_end_x, road_end_y))
3. Visiting Special Road Endpoints Only
Pitfall: Only adding special road start and end points to the graph, missing the fact that you can walk to any special road's starting point from any position.
Why it happens: When thinking of this as a graph problem, developers might pre-build a graph with only special road endpoints as nodes, missing potential optimal paths.
Incorrect approach:
# Wrong: Pre-building a limited graph nodes = {(start[0], start[1]), (target[0], target[1])} for x1, y1, x2, y2, cost in specialRoads: nodes.add((x1, y1)) nodes.add((x2, y2)) # Then only considering paths between these fixed nodes
Correct approach: The solution correctly considers walking from any position to any special road's starting point, allowing for more flexible pathfinding.
What's the output of running the following function using input [30, 20, 10, 100, 33, 12]
?
1def fun(arr: List[int]) -> List[int]:
2 import heapq
3 heapq.heapify(arr)
4 res = []
5 for i in range(3):
6 res.append(heapq.heappop(arr))
7 return res
8
1public static int[] fun(int[] arr) {
2 int[] res = new int[3];
3 PriorityQueue<Integer> heap = new PriorityQueue<>();
4 for (int i = 0; i < arr.length; i++) {
5 heap.add(arr[i]);
6 }
7 for (int i = 0; i < 3; i++) {
8 res[i] = heap.poll();
9 }
10 return res;
11}
12
1class HeapItem {
2 constructor(item, priority = item) {
3 this.item = item;
4 this.priority = priority;
5 }
6}
7
8class MinHeap {
9 constructor() {
10 this.heap = [];
11 }
12
13 push(node) {
14 // insert the new node at the end of the heap array
15 this.heap.push(node);
16 // find the correct position for the new node
17 this.bubble_up();
18 }
19
20 bubble_up() {
21 let index = this.heap.length - 1;
22
23 while (index > 0) {
24 const element = this.heap[index];
25 const parentIndex = Math.floor((index - 1) / 2);
26 const parent = this.heap[parentIndex];
27
28 if (parent.priority <= element.priority) break;
29 // if the parent is bigger than the child then swap the parent and child
30 this.heap[index] = parent;
31 this.heap[parentIndex] = element;
32 index = parentIndex;
33 }
34 }
35
36 pop() {
37 const min = this.heap[0];
38 this.heap[0] = this.heap[this.size() - 1];
39 this.heap.pop();
40 this.bubble_down();
41 return min;
42 }
43
44 bubble_down() {
45 let index = 0;
46 let min = index;
47 const n = this.heap.length;
48
49 while (index < n) {
50 const left = 2 * index + 1;
51 const right = left + 1;
52
53 if (left < n && this.heap[left].priority < this.heap[min].priority) {
54 min = left;
55 }
56 if (right < n && this.heap[right].priority < this.heap[min].priority) {
57 min = right;
58 }
59 if (min === index) break;
60 [this.heap[min], this.heap[index]] = [this.heap[index], this.heap[min]];
61 index = min;
62 }
63 }
64
65 peek() {
66 return this.heap[0];
67 }
68
69 size() {
70 return this.heap.length;
71 }
72}
73
74function fun(arr) {
75 const heap = new MinHeap();
76 for (const x of arr) {
77 heap.push(new HeapItem(x));
78 }
79 const res = [];
80 for (let i = 0; i < 3; i++) {
81 res.push(heap.pop().item);
82 }
83 return res;
84}
85
Recommended Readings
https assets algo monster cover_photos graph svg Graph Fundamentals Tree with 0 cycle At this point you should be pretty familiar with trees A tree is a special kind of graph a connected acyclic cycle less graph A graph may contain cycle s and nodes could be disconnected A tree
Shortest Path Between A and B Prereq BFS on Graph problems graph_bfs Given an unweighted connected graph return the length of the shortest path between two nodes A and B in terms of the number of edges Assume there always exists a path between nodes A and B Input graph
https assets algo monster cover_photos heap svg Priority Queue and Heap What is the relationship between priority queue and heap Priority Queue is an Abstract Data Type and Heap is the concrete data structure we use to implement a priority queue Priority Queue A priority queue is a data structure
Want a Structured Path to Master System Design Too? Don’t Miss This!