mirror of
https://github.com/harivansh-afk/veet-code.git
synced 2026-04-16 06:02:47 +00:00
clanker: veet-hard-problems (run)
This commit is contained in:
parent
c4d74aca3e
commit
de869bc230
4 changed files with 239 additions and 0 deletions
40
problems/hard/shortest-path/solution.py
Normal file
40
problems/hard/shortest-path/solution.py
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
"""
|
||||||
|
Shortest Path
|
||||||
|
|
||||||
|
You're building a navigation system for a logistics company. Given a
|
||||||
|
network of cities connected by weighted roads, implement a shortest-path
|
||||||
|
finder that computes the minimum-cost route between two cities using
|
||||||
|
Dijkstra's algorithm. The system must also detect when no route exists.
|
||||||
|
|
||||||
|
Example 1:
|
||||||
|
Input: edges = [("A", "B", 4), ("A", "C", 2), ("C", "B", 1), ("B", "D", 5), ("C", "D", 8)], start = "A", end = "D"
|
||||||
|
Output: (7, ["A", "C", "B", "D"])
|
||||||
|
Explanation: A->C (2) + C->B (1) + B->D (5) = 7, cheaper than A->C->D (10) or A->B->D (9).
|
||||||
|
|
||||||
|
Example 2:
|
||||||
|
Input: edges = [("X", "Y", 3)], start = "Y", end = "X"
|
||||||
|
Output: (-1, [])
|
||||||
|
Explanation: No path from Y to X because the edge is one-directional.
|
||||||
|
|
||||||
|
Example 3:
|
||||||
|
Input: edges = [("A", "B", 1), ("B", "C", 2), ("A", "C", 10)], start = "A", end = "C"
|
||||||
|
Output: (3, ["A", "B", "C"])
|
||||||
|
Explanation: Going through B costs 3, which beats the direct edge of 10.
|
||||||
|
|
||||||
|
Constraints:
|
||||||
|
- Edges are directed: (source, destination, weight)
|
||||||
|
- All weights are positive integers (>= 1)
|
||||||
|
- No duplicate edges (same source and destination)
|
||||||
|
- Node names are non-empty strings
|
||||||
|
- Return (-1, []) if no path exists
|
||||||
|
- Return (0, [start]) if start == end
|
||||||
|
- If multiple shortest paths exist, return any one of them
|
||||||
|
- The path list includes both start and end nodes
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def shortest_path(
|
||||||
|
edges: list[tuple[str, str, int]], start: str, end: str
|
||||||
|
) -> tuple[int, list[str]]:
|
||||||
|
"""Return (cost, path) for shortest path, or (-1, []) if unreachable."""
|
||||||
|
pass # Your implementation here
|
||||||
75
problems/hard/shortest-path/tests.py
Normal file
75
problems/hard/shortest-path/tests.py
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
"""Tests for shortest-path."""
|
||||||
|
import pytest
|
||||||
|
from solution import shortest_path
|
||||||
|
|
||||||
|
|
||||||
|
class TestBasicCases:
|
||||||
|
"""Test basic functionality with typical inputs."""
|
||||||
|
|
||||||
|
def test_example_one(self):
|
||||||
|
"""Test first example from problem description."""
|
||||||
|
edges = [("A", "B", 4), ("A", "C", 2), ("C", "B", 1), ("B", "D", 5), ("C", "D", 8)]
|
||||||
|
assert shortest_path(edges, "A", "D") == (7, ["A", "C", "B", "D"])
|
||||||
|
|
||||||
|
def test_example_two(self):
|
||||||
|
"""Test second example with no reverse path."""
|
||||||
|
edges = [("X", "Y", 3)]
|
||||||
|
assert shortest_path(edges, "Y", "X") == (-1, [])
|
||||||
|
|
||||||
|
def test_example_three(self):
|
||||||
|
"""Test indirect path cheaper than direct edge."""
|
||||||
|
edges = [("A", "B", 1), ("B", "C", 2), ("A", "C", 10)]
|
||||||
|
assert shortest_path(edges, "A", "C") == (3, ["A", "B", "C"])
|
||||||
|
|
||||||
|
def test_direct_edge_is_shortest(self):
|
||||||
|
"""Test when the direct edge is the cheapest route."""
|
||||||
|
edges = [("A", "B", 1), ("A", "C", 5), ("C", "B", 5)]
|
||||||
|
assert shortest_path(edges, "A", "B") == (1, ["A", "B"])
|
||||||
|
|
||||||
|
|
||||||
|
class TestEdgeCases:
|
||||||
|
"""Test edge cases and boundary conditions."""
|
||||||
|
|
||||||
|
def test_start_equals_end(self):
|
||||||
|
"""Test when start and end are the same node."""
|
||||||
|
edges = [("A", "B", 1)]
|
||||||
|
assert shortest_path(edges, "A", "A") == (0, ["A"])
|
||||||
|
|
||||||
|
def test_no_edges(self):
|
||||||
|
"""Test with empty edge list and different start/end."""
|
||||||
|
assert shortest_path([], "A", "B") == (-1, [])
|
||||||
|
|
||||||
|
def test_single_edge_path(self):
|
||||||
|
"""Test path that is a single edge."""
|
||||||
|
edges = [("A", "B", 7)]
|
||||||
|
assert shortest_path(edges, "A", "B") == (7, ["A", "B"])
|
||||||
|
|
||||||
|
def test_long_chain(self):
|
||||||
|
"""Test shortest path through a long chain of nodes."""
|
||||||
|
edges = [("A", "B", 1), ("B", "C", 1), ("C", "D", 1), ("D", "E", 1)]
|
||||||
|
assert shortest_path(edges, "A", "E") == (4, ["A", "B", "C", "D", "E"])
|
||||||
|
|
||||||
|
def test_disconnected_graph(self):
|
||||||
|
"""Test with disconnected components."""
|
||||||
|
edges = [("A", "B", 1), ("C", "D", 1)]
|
||||||
|
assert shortest_path(edges, "A", "D") == (-1, [])
|
||||||
|
|
||||||
|
def test_multiple_paths_picks_cheapest(self):
|
||||||
|
"""Test graph with many paths to verify optimal is chosen."""
|
||||||
|
edges = [
|
||||||
|
("S", "A", 10), ("S", "B", 3), ("B", "A", 1),
|
||||||
|
("A", "T", 2), ("B", "T", 20),
|
||||||
|
]
|
||||||
|
cost, path = shortest_path(edges, "S", "T")
|
||||||
|
assert cost == 6
|
||||||
|
assert path[0] == "S" and path[-1] == "T"
|
||||||
|
|
||||||
|
def test_large_weights(self):
|
||||||
|
"""Test with large edge weights."""
|
||||||
|
edges = [("A", "B", 1000000), ("B", "C", 1000000)]
|
||||||
|
assert shortest_path(edges, "A", "C") == (2000000, ["A", "B", "C"])
|
||||||
|
|
||||||
|
def test_end_node_not_in_graph(self):
|
||||||
|
"""Test when end node has no edges at all."""
|
||||||
|
edges = [("A", "B", 1), ("B", "C", 2)]
|
||||||
|
assert shortest_path(edges, "A", "Z") == (-1, [])
|
||||||
45
problems/hard/task-scheduler/solution.py
Normal file
45
problems/hard/task-scheduler/solution.py
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
"""
|
||||||
|
Task Scheduler
|
||||||
|
|
||||||
|
You're building a CI/CD pipeline orchestrator. Given a set of build tasks
|
||||||
|
with durations and dependency requirements, determine the minimum total
|
||||||
|
time to complete all tasks when independent tasks can run in parallel.
|
||||||
|
Also detect if the dependency graph contains a cycle (making the build
|
||||||
|
impossible).
|
||||||
|
|
||||||
|
Each task is represented as (name, duration, dependencies) where
|
||||||
|
dependencies is a list of task names that must complete before this
|
||||||
|
task can start.
|
||||||
|
|
||||||
|
Example 1:
|
||||||
|
Input: tasks = [("compile", 3, []), ("test", 5, ["compile"]), ("lint", 2, []), ("deploy", 1, ["test", "lint"])]
|
||||||
|
Output: (9, ["compile", "test", "deploy"])
|
||||||
|
Explanation: compile(3) -> test(5) -> deploy(1) = 9. lint(2) runs in parallel and finishes before deploy starts. The critical path is compile -> test -> deploy.
|
||||||
|
|
||||||
|
Example 2:
|
||||||
|
Input: tasks = [("A", 2, ["B"]), ("B", 3, ["A"])]
|
||||||
|
Output: (-1, [])
|
||||||
|
Explanation: Circular dependency between A and B makes execution impossible.
|
||||||
|
|
||||||
|
Example 3:
|
||||||
|
Input: tasks = [("X", 4, []), ("Y", 4, []), ("Z", 1, ["X", "Y"])]
|
||||||
|
Output: (5, ["X", "Z"])
|
||||||
|
Explanation: X and Y run in parallel (both take 4). Z waits for both, then takes 1. Critical path is X(4) -> Z(1) = 5 (or equivalently Y -> Z). Return either.
|
||||||
|
|
||||||
|
Constraints:
|
||||||
|
- Task names are unique non-empty strings
|
||||||
|
- Durations are positive integers (>= 1)
|
||||||
|
- Dependencies reference other task names in the list
|
||||||
|
- Return (-1, []) if a cycle exists
|
||||||
|
- The critical path is the longest path through the dependency graph
|
||||||
|
- If multiple critical paths have the same length, return any one
|
||||||
|
- The critical path list is ordered from first task to last
|
||||||
|
- All tasks must be completed; the answer is the makespan
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def schedule_tasks(
|
||||||
|
tasks: list[tuple[str, int, list[str]]],
|
||||||
|
) -> tuple[int, list[str]]:
|
||||||
|
"""Return (min_total_time, critical_path) or (-1, []) if cycle exists."""
|
||||||
|
pass # Your implementation here
|
||||||
79
problems/hard/task-scheduler/tests.py
Normal file
79
problems/hard/task-scheduler/tests.py
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
"""Tests for task-scheduler."""
|
||||||
|
import pytest
|
||||||
|
from solution import schedule_tasks
|
||||||
|
|
||||||
|
|
||||||
|
class TestBasicCases:
|
||||||
|
"""Test basic functionality with typical inputs."""
|
||||||
|
|
||||||
|
def test_example_one(self):
|
||||||
|
"""Test first example from problem description."""
|
||||||
|
tasks = [("compile", 3, []), ("test", 5, ["compile"]), ("lint", 2, []), ("deploy", 1, ["test", "lint"])]
|
||||||
|
assert schedule_tasks(tasks) == (9, ["compile", "test", "deploy"])
|
||||||
|
|
||||||
|
def test_example_two_cycle(self):
|
||||||
|
"""Test second example with circular dependency."""
|
||||||
|
tasks = [("A", 2, ["B"]), ("B", 3, ["A"])]
|
||||||
|
assert schedule_tasks(tasks) == (-1, [])
|
||||||
|
|
||||||
|
def test_example_three_parallel(self):
|
||||||
|
"""Test parallel tasks with shared dependency."""
|
||||||
|
tasks = [("X", 4, []), ("Y", 4, []), ("Z", 1, ["X", "Y"])]
|
||||||
|
cost, path = schedule_tasks(tasks)
|
||||||
|
assert cost == 5
|
||||||
|
assert path[0] in ("X", "Y") and path[-1] == "Z"
|
||||||
|
|
||||||
|
def test_linear_chain(self):
|
||||||
|
"""Test simple linear dependency chain."""
|
||||||
|
tasks = [("A", 2, []), ("B", 3, ["A"]), ("C", 4, ["B"])]
|
||||||
|
assert schedule_tasks(tasks) == (9, ["A", "B", "C"])
|
||||||
|
|
||||||
|
|
||||||
|
class TestEdgeCases:
|
||||||
|
"""Test edge cases and boundary conditions."""
|
||||||
|
|
||||||
|
def test_single_task(self):
|
||||||
|
"""Test with a single task and no dependencies."""
|
||||||
|
tasks = [("solo", 5, [])]
|
||||||
|
assert schedule_tasks(tasks) == (5, ["solo"])
|
||||||
|
|
||||||
|
def test_all_independent(self):
|
||||||
|
"""Test all tasks run in parallel with no dependencies."""
|
||||||
|
tasks = [("A", 3, []), ("B", 7, []), ("C", 5, [])]
|
||||||
|
cost, path = schedule_tasks(tasks)
|
||||||
|
assert cost == 7
|
||||||
|
assert path == ["B"]
|
||||||
|
|
||||||
|
def test_diamond_dependency(self):
|
||||||
|
"""Test diamond-shaped dependency graph."""
|
||||||
|
tasks = [("A", 1, []), ("B", 5, ["A"]), ("C", 2, ["A"]), ("D", 1, ["B", "C"])]
|
||||||
|
assert schedule_tasks(tasks) == (7, ["A", "B", "D"])
|
||||||
|
|
||||||
|
def test_three_node_cycle(self):
|
||||||
|
"""Test cycle involving three nodes."""
|
||||||
|
tasks = [("A", 1, ["C"]), ("B", 1, ["A"]), ("C", 1, ["B"])]
|
||||||
|
assert schedule_tasks(tasks) == (-1, [])
|
||||||
|
|
||||||
|
def test_wide_fan_in(self):
|
||||||
|
"""Test many tasks feeding into one final task."""
|
||||||
|
tasks = [("A", 1, []), ("B", 2, []), ("C", 3, []), ("D", 4, []), ("final", 1, ["A", "B", "C", "D"])]
|
||||||
|
assert schedule_tasks(tasks) == (5, ["D", "final"])
|
||||||
|
|
||||||
|
def test_deep_chain_with_parallel_branch(self):
|
||||||
|
"""Test long chain alongside a shorter parallel branch."""
|
||||||
|
tasks = [
|
||||||
|
("A", 1, []), ("B", 1, ["A"]), ("C", 1, ["B"]), ("D", 1, ["C"]),
|
||||||
|
("shortcut", 2, []),
|
||||||
|
("end", 1, ["D", "shortcut"]),
|
||||||
|
]
|
||||||
|
assert schedule_tasks(tasks) == (5, ["A", "B", "C", "D", "end"])
|
||||||
|
|
||||||
|
def test_partial_cycle_with_valid_tasks(self):
|
||||||
|
"""Test graph where some tasks form a cycle but others don't."""
|
||||||
|
tasks = [("A", 1, []), ("B", 2, ["C"]), ("C", 3, ["B"])]
|
||||||
|
assert schedule_tasks(tasks) == (-1, [])
|
||||||
|
|
||||||
|
def test_large_durations(self):
|
||||||
|
"""Test with large task durations."""
|
||||||
|
tasks = [("A", 1000000, []), ("B", 1000000, ["A"])]
|
||||||
|
assert schedule_tasks(tasks) == (2000000, ["A", "B"])
|
||||||
Loading…
Add table
Add a link
Reference in a new issue