diff --git a/problems/3635-earliest-finish-time-for-land-and-water-rides-ii/analysis.md b/problems/3635-earliest-finish-time-for-land-and-water-rides-ii/analysis.md new file mode 100644 index 0000000..6ae2a9e --- /dev/null +++ b/problems/3635-earliest-finish-time-for-land-and-water-rides-ii/analysis.md @@ -0,0 +1,76 @@ +# 3635. Earliest Finish Time for Land and Water Rides II + +[LeetCode Link](https://leetcode.com/problems/earliest-finish-time-for-land-and-water-rides-ii/) + +Difficulty: Medium +Topics: Array, Two Pointers, Binary Search, Greedy, Sorting + +Acceptance Rate: 52.9% + +## Hints + +### Hint 1 + +The brute force is to try every pair of (land ride, water ride) in both orders — that is `O(n * m)` combinations. With `n` and `m` up to `5 * 10^4` each, that's `2.5 * 10^9` pairs, far too slow. Ask yourself: do you really need to look at every *pair*, or can you decouple the two categories? + +### Hint 2 + +Consider just one ordering, say **land first, then water**. If you commit to a specific water ride `j`, what is the *best* land ride to pair it with? Notice the finish time only depends on the land ride through a single number: when that land ride finishes. So you don't need to know which land ride you used — you only need the smallest possible value of that number. + +### Hint 3 + +For the "land then water" ordering, the finish time when pairing some land ride with water ride `j` is `max(landFinish, waterStartTime[j]) + waterDuration[j]`. This is *monotonic* in `landFinish`, so the best choice is always the land ride with the **minimum** `landStartTime[i] + landDuration[i]`. Precompute that single minimum once, then sweep every water ride. Do the symmetric thing for "water then land". The two minimums collapse the problem from `O(n*m)` to `O(n+m)`. + +## Approach + +A valid plan picks exactly one land ride and one water ride and runs them back-to-back in one of two orders. We handle each order independently. + +**Order 1 — land ride first, then water ride.** +If the land ride finishes at time `f`, then the water ride `j` can start no earlier than `max(f, waterStartTime[j])` and finishes at `max(f, waterStartTime[j]) + waterDuration[j]`. For a fixed `j`, this expression is non-decreasing in `f`, so among all land rides we always prefer the one with the smallest finish time. Define: + +``` +minLandFinish = min over i of (landStartTime[i] + landDuration[i]) +``` + +Then the best "land first" result is: + +``` +min over j of ( max(minLandFinish, waterStartTime[j]) + waterDuration[j] ) +``` + +**Order 2 — water ride first, then land ride.** +By identical reasoning, define: + +``` +minWaterFinish = min over j of (waterStartTime[j] + waterDuration[j]) +``` + +and the best "water first" result is: + +``` +min over i of ( max(minWaterFinish, landStartTime[i]) + landDuration[i] ) +``` + +The answer is the minimum of the two orderings. + +**Why the decoupling is valid.** The only way the first ride influences the second is through the first ride's finish time, and the second-ride finish time is monotonically non-decreasing in that value. So fixing "use the earliest-finishing ride of the first category" is never worse than any other choice. This greedy collapse is what lets us avoid examining all pairs. + +**Walkthrough of Example 1:** `landStartTime = [2,8]`, `landDuration = [4,1]`, `waterStartTime = [6]`, `waterDuration = [3]`. +- Land finishes: `2+4=6`, `8+1=9` → `minLandFinish = 6`. +- Water finishes: `6+3=9` → `minWaterFinish = 9`. +- Land first: for water ride 0, `max(6, 6) + 3 = 9`. +- Water first: for land ride 0, `max(9, 2) + 4 = 13`; for land ride 1, `max(9, 8) + 1 = 10`. Best `= 10`. +- Answer `= min(9, 10) = 9`. ✓ + +## Complexity Analysis + +Time Complexity: O(n + m) — two linear passes to compute the minimums, two linear passes to sweep the other category. +Space Complexity: O(1) — only a handful of scalar accumulators are kept. + +## Edge Cases + +- **Single ride in each category (`n = m = 1`):** both orderings still get evaluated; the formula handles it without special casing. +- **Second ride opens long before the first finishes:** the `max(...)` clamps the start to the first ride's finish time, so waiting is never modeled as starting early. Example 2 exercises this (water opens at 1 but can't start until land/water predecessor frees up). +- **First ride finishes before the second ride even opens:** then `max(minFinish, startTime) == startTime`, i.e. the tourist waits idle for the second ride to open — the `max` captures this correctly. +- **Large values / overflow:** with values up to `10^5`, a finish time stays well within `int` range, but the reasoning generalizes; using Go's `int` (64-bit on typical platforms) is safe. +- **It is never optimal to pick a slower-finishing first ride** — the monotonic argument guarantees the single minimum suffices, so don't be tempted to keep more candidates than that. diff --git a/problems/3635-earliest-finish-time-for-land-and-water-rides-ii/problem.md b/problems/3635-earliest-finish-time-for-land-and-water-rides-ii/problem.md new file mode 100644 index 0000000..c706d2c --- /dev/null +++ b/problems/3635-earliest-finish-time-for-land-and-water-rides-ii/problem.md @@ -0,0 +1,97 @@ +--- +number: "3635" +frontend_id: "3635" +title: "Earliest Finish Time for Land and Water Rides II" +slug: "earliest-finish-time-for-land-and-water-rides-ii" +difficulty: "Medium" +topics: + - "Array" + - "Two Pointers" + - "Binary Search" + - "Greedy" + - "Sorting" +acceptance_rate: 5293.4 +is_premium: false +created_at: "2026-06-03T05:24:13.050562+00:00" +fetched_at: "2026-06-03T05:24:13.050562+00:00" +link: "https://leetcode.com/problems/earliest-finish-time-for-land-and-water-rides-ii/" +date: "2026-06-03" +--- + +# 3635. Earliest Finish Time for Land and Water Rides II + +You are given two categories of theme park attractions: **land rides** and **water rides**. + + * **Land rides** + * `landStartTime[i]` - the earliest time the `ith` land ride can be boarded. + * `landDuration[i]` - how long the `ith` land ride lasts. + * **Water rides** + * `waterStartTime[j]` - the earliest time the `jth` water ride can be boarded. + * `waterDuration[j]` - how long the `jth` water ride lasts. + + + +A tourist must experience **exactly one** ride from **each** category, in **either order**. + + * A ride may be started at its opening time or **any later moment**. + * If a ride is started at time `t`, it finishes at time `t + duration`. + * Immediately after finishing one ride the tourist may board the other (if it is already open) or wait until it opens. + + + +Return the **earliest possible time** at which the tourist can finish both rides. + + + +**Example 1:** + +**Input:** landStartTime = [2,8], landDuration = [4,1], waterStartTime = [6], waterDuration = [3] + +**Output:** 9 + +**Explanation:** ​​​​​​​ + + * Plan A (land ride 0 -> water ride 0): + * Start land ride 0 at time `landStartTime[0] = 2`. Finish at `2 + landDuration[0] = 6`. + * Water ride 0 opens at time `waterStartTime[0] = 6`. Start immediately at `6`, finish at `6 + waterDuration[0] = 9`. + * Plan B (water ride 0 -> land ride 1): + * Start water ride 0 at time `waterStartTime[0] = 6`. Finish at `6 + waterDuration[0] = 9`. + * Land ride 1 opens at `landStartTime[1] = 8`. Start at time `9`, finish at `9 + landDuration[1] = 10`. + * Plan C (land ride 1 -> water ride 0): + * Start land ride 1 at time `landStartTime[1] = 8`. Finish at `8 + landDuration[1] = 9`. + * Water ride 0 opened at `waterStartTime[0] = 6`. Start at time `9`, finish at `9 + waterDuration[0] = 12`. + * Plan D (water ride 0 -> land ride 0): + * Start water ride 0 at time `waterStartTime[0] = 6`. Finish at `6 + waterDuration[0] = 9`. + * Land ride 0 opened at `landStartTime[0] = 2`. Start at time `9`, finish at `9 + landDuration[0] = 13`. + + + +Plan A gives the earliest finish time of 9. + +**Example 2:** + +**Input:** landStartTime = [5], landDuration = [3], waterStartTime = [1], waterDuration = [10] + +**Output:** 14 + +**Explanation:** ​​​​​​​ + + * Plan A (water ride 0 -> land ride 0): + * Start water ride 0 at time `waterStartTime[0] = 1`. Finish at `1 + waterDuration[0] = 11`. + * Land ride 0 opened at `landStartTime[0] = 5`. Start immediately at `11` and finish at `11 + landDuration[0] = 14`. + * Plan B (land ride 0 -> water ride 0): + * Start land ride 0 at time `landStartTime[0] = 5`. Finish at `5 + landDuration[0] = 8`. + * Water ride 0 opened at `waterStartTime[0] = 1`. Start immediately at `8` and finish at `8 + waterDuration[0] = 18`. + + + +Plan A provides the earliest finish time of 14.**​​​​​​​** + + + +**Constraints:** + + * `1 <= n, m <= 5 * 104` + * `landStartTime.length == landDuration.length == n` + * `waterStartTime.length == waterDuration.length == m` + * `1 <= landStartTime[i], landDuration[i], waterStartTime[j], waterDuration[j] <= 105` diff --git a/problems/3635-earliest-finish-time-for-land-and-water-rides-ii/solution_daily_20260603.go b/problems/3635-earliest-finish-time-for-land-and-water-rides-ii/solution_daily_20260603.go new file mode 100644 index 0000000..2130ad8 --- /dev/null +++ b/problems/3635-earliest-finish-time-for-land-and-water-rides-ii/solution_daily_20260603.go @@ -0,0 +1,52 @@ +package main + +// Earliest Finish Time for Land and Water Rides II +// +// A plan runs one land ride and one water ride back-to-back in one of two +// orders. The second ride's finish time depends on the first ride only through +// the first ride's finish time, and is monotonically non-decreasing in it. +// So for each ordering we only need the earliest-finishing ride of the first +// category, then sweep the second category once. This collapses the naive +// O(n*m) pairing into an O(n+m) greedy. +func earliestFinishTime(landStartTime []int, landDuration []int, waterStartTime []int, waterDuration []int) int { + minLandFinish := landStartTime[0] + landDuration[0] + for i := 1; i < len(landStartTime); i++ { + if f := landStartTime[i] + landDuration[i]; f < minLandFinish { + minLandFinish = f + } + } + + minWaterFinish := waterStartTime[0] + waterDuration[0] + for j := 1; j < len(waterStartTime); j++ { + if f := waterStartTime[j] + waterDuration[j]; f < minWaterFinish { + minWaterFinish = f + } + } + + best := -1 + + // Order 1: land ride first, then water ride j. + for j := range waterStartTime { + finish := max(minLandFinish, waterStartTime[j]) + waterDuration[j] + if best == -1 || finish < best { + best = finish + } + } + + // Order 2: water ride first, then land ride i. + for i := range landStartTime { + finish := max(minWaterFinish, landStartTime[i]) + landDuration[i] + if finish < best { + best = finish + } + } + + return best +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} diff --git a/problems/3635-earliest-finish-time-for-land-and-water-rides-ii/solution_daily_20260603_test.go b/problems/3635-earliest-finish-time-for-land-and-water-rides-ii/solution_daily_20260603_test.go new file mode 100644 index 0000000..33006d7 --- /dev/null +++ b/problems/3635-earliest-finish-time-for-land-and-water-rides-ii/solution_daily_20260603_test.go @@ -0,0 +1,73 @@ +package main + +import "testing" + +func TestSolution(t *testing.T) { + tests := []struct { + name string + landStartTime []int + landDuration []int + waterStartTime []int + waterDuration []int + expected int + }{ + { + name: "example 1: two land rides, one water ride", + landStartTime: []int{2, 8}, + landDuration: []int{4, 1}, + waterStartTime: []int{6}, + waterDuration: []int{3}, + expected: 9, + }, + { + name: "example 2: water first beats land first", + landStartTime: []int{5}, + landDuration: []int{3}, + waterStartTime: []int{1}, + waterDuration: []int{10}, + expected: 14, + }, + { + name: "edge case: single ride each, no waiting", + landStartTime: []int{1}, + landDuration: []int{1}, + waterStartTime: []int{1}, + waterDuration: []int{1}, + expected: 3, + }, + { + name: "edge case: second ride opens far in the future forces a wait", + landStartTime: []int{1}, + landDuration: []int{2}, + waterStartTime: []int{100}, + waterDuration: []int{5}, + expected: 105, + }, + { + name: "edge case: best land ride for ordering is not the lowest index", + landStartTime: []int{10, 1}, + landDuration: []int{10, 1}, + waterStartTime: []int{1}, + waterDuration: []int{1}, + expected: 3, + }, + { + name: "edge case: multiple rides on both sides", + landStartTime: []int{3, 7}, + landDuration: []int{2, 1}, + waterStartTime: []int{4, 9}, + waterDuration: []int{2, 1}, + expected: 7, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := earliestFinishTime(tt.landStartTime, tt.landDuration, tt.waterStartTime, tt.waterDuration) + if result != tt.expected { + t.Errorf("earliestFinishTime(%v, %v, %v, %v) = %d, want %d", + tt.landStartTime, tt.landDuration, tt.waterStartTime, tt.waterDuration, result, tt.expected) + } + }) + } +}