568. Maximum Vacation Days 🔒
Problem Description
You are planning a travel schedule across n
cities over k
weeks to maximize vacation days. You start in city 0 on Monday of the first week.
Travel Rules:
- Cities are numbered from 0 to n-1
- You can only fly between cities on Monday mornings (once per week)
- The
flights
matrix shows available flights:flights[i][j] = 1
means there's a flight from city i to city j,flights[i][j] = 0
means no flight exists - You can choose to stay in your current city instead of flying
Vacation Rules:
- The
days
matrix shows vacation days available:days[i][j]
represents the maximum vacation days you can take in city i during week j - You can stay in a city even after using all vacation days (working on extra days)
- If you fly to a new city and take vacation that week, the vacation days count for the destination city
Goal: Find the maximum total vacation days possible over all k weeks.
Example Understanding: If you're in city A in week 1 with 2 vacation days available, and city B has 5 vacation days available in week 2, you could:
- Stay in city A for week 1 (get 2 vacation days)
- Fly to city B on Monday of week 2 (if a flight exists)
- Take vacation in city B for week 2 (get 5 vacation days)
- Total: 7 vacation days
The solution uses dynamic programming where f[k][j]
represents the maximum vacation days achievable by week k ending in city j. For each week and city, it considers either staying in the same city or flying from any connected city, then adds the vacation days available at the destination.
Intuition
The key insight is that at any point in time, what matters is: which week we're in and which city we're currently at. Our future vacation days don't depend on how we got to this city, only on our current position and remaining weeks.
This naturally leads to a dynamic programming approach. We can think of the problem as making optimal decisions week by week. For each week, we need to decide: should we stay in our current city or fly to another city?
The state can be defined as f[k][j]
= maximum vacation days we can get by the end of week k
if we're in city j
.
For each week k
and each possible destination city j
, we have two choices:
- Stay in city
j
from the previous week (if we were already there):f[k-1][j]
- Fly from some other city
i
to cityj
(if a flight exists):f[k-1][i]
whereflights[i][j] = 1
We take the maximum of all these possibilities and add the vacation days available in city j
during week k
: days[j][k-1]
.
The initialization is crucial: we start at city 0 with 0 vacation days before week 1 begins, so f[0][0] = 0
. All other states start as negative infinity since they're impossible to reach initially.
After processing all k
weeks, the answer is the maximum value among all cities in the final week, since we can end our journey in any city.
This bottom-up approach ensures we consider all possible flight paths and choose the one that maximizes total vacation days.
Learn more about Dynamic Programming patterns.
Solution Approach
We implement a 2D dynamic programming solution where f[k][j]
represents the maximum vacation days achievable by the end of week k
when ending in city j
.
Initialization:
- Create a 2D array
f
with dimensions(K+1) × n
, whereK
is the number of weeks andn
is the number of cities - Initialize all values to negative infinity (
-inf
) to represent impossible states - Set
f[0][0] = 0
since we start in city 0 with 0 vacation days before any week begins
State Transition:
For each week k
from 1 to K
and each possible destination city j
:
-
Option 1 - Stay in the same city:
- If we were in city
j
last week, we can stay:f[k][j] = f[k-1][j]
- If we were in city
-
Option 2 - Fly from another city:
- Check all cities
i
that have flights to cityj
- If
flights[i][j] == 1
, we can fly from cityi
to cityj
- Update:
f[k][j] = max(f[k][j], f[k-1][i])
- Check all cities
-
Add vacation days:
- After determining the best way to reach city
j
in weekk
, add the vacation days available f[k][j] += days[j][k-1]
(note:k-1
becausedays
array is 0-indexed for weeks)
- After determining the best way to reach city
Final Answer:
After processing all weeks, the maximum vacation days is the maximum value in the last week across all cities: max(f[K][j])
for all j
from 0 to n-1
.
Time Complexity: O(K × n²)
- For each of K
weeks, we check all n
cities, and for each city, we check all n
possible source cities.
Space Complexity: O(K × n)
- We maintain a 2D DP array of size (K+1) × n
.
The algorithm ensures we explore all possible travel paths while making optimal decisions at each step to maximize total vacation days.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example with 3 cities and 2 weeks:
Input:
flights = [[0,1,1], [1,0,1], [1,1,0]]
(city 0 connects to 1,2; city 1 connects to 0,2; city 2 connects to 0,1)days = [[1,3], [6,0], [3,3]]
(vacation days per city per week)- We start in city 0
DP Table Initialization:
Create f[k][j]
where k=0 to 2 (weeks), j=0 to 2 (cities):
f[0][0] = 0 (start position) f[0][1] = -inf (can't start here) f[0][2] = -inf (can't start here)
Week 1 Processing: For each city j, find the best way to reach it and add vacation days:
-
City 0: Can stay from f[0][0]=0, or fly from city 1 (f[0][1]=-inf) or city 2 (f[0][2]=-inf)
- Best: stay from city 0 → f[1][0] = 0 + days[0][0] = 0 + 1 = 1
-
City 1: Can fly from city 0 (f[0][0]=0) since flights[0][1]=1, or stay from f[0][1]=-inf
- Best: fly from city 0 → f[1][1] = 0 + days[1][0] = 0 + 6 = 6
-
City 2: Can fly from city 0 (f[0][0]=0) since flights[0][2]=1, or city 1 (f[0][1]=-inf)
- Best: fly from city 0 → f[1][2] = 0 + days[2][0] = 0 + 3 = 3
After Week 1: f[1] = [1, 6, 3]
Week 2 Processing: For each city j, consider all possible origins:
-
City 0: Can fly from city 1 (f[1][1]=6) or city 2 (f[1][2]=3), or stay (f[1][0]=1)
- Best: fly from city 1 → f[2][0] = 6 + days[0][1] = 6 + 3 = 9
-
City 1: Can fly from city 0 (f[1][0]=1) or city 2 (f[1][2]=3), or stay (f[1][1]=6)
- Best: stay in city 1 → f[2][1] = 6 + days[1][1] = 6 + 0 = 6
-
City 2: Can fly from city 0 (f[1][0]=1) or city 1 (f[1][1]=6), or stay (f[1][2]=3)
- Best: fly from city 1 → f[2][2] = 6 + days[2][1] = 6 + 3 = 9
After Week 2: f[2] = [9, 6, 9]
Final Answer: max(f[2]) = 9 vacation days
Optimal Path: Start in city 0 → Fly to city 1 (take 6 vacation days in week 1) → Fly to city 0 or 2 (take 3 vacation days in week 2) = 9 total days
Solution Implementation
1class Solution:
2 def maxVacationDays(self, flights: List[List[int]], days: List[List[int]]) -> int:
3 # Number of cities
4 num_cities = len(flights)
5 # Number of weeks
6 num_weeks = len(days[0])
7
8 # dp[week][city] = maximum vacation days possible when ending at city after week
9 # Initialize with negative infinity (impossible states)
10 dp = [[float('-inf')] * num_cities for _ in range(num_weeks + 1)]
11
12 # Base case: start at city 0 in week 0 with 0 vacation days
13 dp[0][0] = 0
14
15 # Iterate through each week
16 for week in range(1, num_weeks + 1):
17 # Consider each destination city for this week
18 for dest_city in range(num_cities):
19 # Option 1: Stay in the same city as previous week
20 dp[week][dest_city] = dp[week - 1][dest_city]
21
22 # Option 2: Fly from another city
23 for src_city in range(num_cities):
24 # Check if there's a flight from src_city to dest_city
25 if flights[src_city][dest_city]:
26 dp[week][dest_city] = max(dp[week][dest_city], dp[week - 1][src_city])
27
28 # Add vacation days available in dest_city during this week
29 # Note: week-1 because days array is 0-indexed for weeks
30 dp[week][dest_city] += days[dest_city][week - 1]
31
32 # Return the maximum vacation days possible ending at any city after all weeks
33 return max(dp[-1][city] for city in range(num_cities))
34
1class Solution {
2 public int maxVacationDays(int[][] flights, int[][] days) {
3 int numCities = flights.length;
4 int numWeeks = days[0].length;
5 final int NEGATIVE_INFINITY = -(1 << 30);
6
7 // dp[week][city] = maximum vacation days when at 'city' after 'week' weeks
8 int[][] dp = new int[numWeeks + 1][numCities];
9
10 // Initialize all states to negative infinity (impossible states)
11 for (int[] row : dp) {
12 Arrays.fill(row, NEGATIVE_INFINITY);
13 }
14
15 // Base case: start at city 0 with 0 vacation days at week 0
16 dp[0][0] = 0;
17
18 // Process each week
19 for (int week = 1; week <= numWeeks; ++week) {
20 // For each possible destination city
21 for (int destCity = 0; destCity < numCities; ++destCity) {
22 // Option 1: Stay in the same city from previous week
23 dp[week][destCity] = dp[week - 1][destCity];
24
25 // Option 2: Fly from another city to this destination city
26 for (int srcCity = 0; srcCity < numCities; ++srcCity) {
27 if (flights[srcCity][destCity] == 1) {
28 dp[week][destCity] = Math.max(dp[week][destCity],
29 dp[week - 1][srcCity]);
30 }
31 }
32
33 // Add vacation days for staying in destCity during this week
34 // Note: week-1 because days array is 0-indexed for weeks
35 dp[week][destCity] += days[destCity][week - 1];
36 }
37 }
38
39 // Find maximum vacation days across all possible ending cities
40 int maxVacationDays = 0;
41 for (int city = 0; city < numCities; ++city) {
42 maxVacationDays = Math.max(maxVacationDays, dp[numWeeks][city]);
43 }
44
45 return maxVacationDays;
46 }
47}
48
1class Solution {
2public:
3 int maxVacationDays(vector<vector<int>>& flights, vector<vector<int>>& days) {
4 int numCities = flights.size();
5 int numWeeks = days[0].size();
6
7 // dp[week][city] = maximum vacation days achievable by week 'week' ending in 'city'
8 // Initialize with very small negative values to indicate unreachable states
9 int dp[numWeeks + 1][numCities];
10 memset(dp, -0x3f, sizeof(dp));
11
12 // Base case: start at city 0 at week 0 with 0 vacation days
13 dp[0][0] = 0;
14
15 // Fill the DP table week by week
16 for (int week = 1; week <= numWeeks; ++week) {
17 for (int currentCity = 0; currentCity < numCities; ++currentCity) {
18 // Option 1: Stay in the same city from previous week
19 dp[week][currentCity] = dp[week - 1][currentCity];
20
21 // Option 2: Fly from another city to current city
22 for (int previousCity = 0; previousCity < numCities; ++previousCity) {
23 if (flights[previousCity][currentCity] == 1) {
24 dp[week][currentCity] = max(dp[week][currentCity],
25 dp[week - 1][previousCity]);
26 }
27 }
28
29 // Add vacation days for staying in currentCity during week (week-1)
30 // Note: week-1 because weeks are 0-indexed in the days array
31 dp[week][currentCity] += days[currentCity][week - 1];
32 }
33 }
34
35 // Find the maximum vacation days across all possible ending cities
36 int maxDays = 0;
37 for (int city = 0; city < numCities; ++city) {
38 maxDays = max(maxDays, dp[numWeeks][city]);
39 }
40
41 return maxDays;
42 }
43};
44
1/**
2 * Calculates the maximum number of vacation days that can be taken
3 * @param flights - 2D array where flights[i][j] = 1 if there's a flight from city i to city j, 0 otherwise
4 * @param days - 2D array where days[i][j] represents vacation days in city i during week j
5 * @returns Maximum number of vacation days possible
6 */
7function maxVacationDays(flights: number[][], days: number[][]): number {
8 const numCities: number = flights.length;
9 const numWeeks: number = days[0].length;
10 const NEGATIVE_INFINITY: number = Number.NEGATIVE_INFINITY;
11
12 // dp[week][city] represents the maximum vacation days achievable
13 // when staying in 'city' at the end of 'week'
14 const dp: number[][] = Array.from(
15 { length: numWeeks + 1 },
16 () => Array(numCities).fill(NEGATIVE_INFINITY)
17 );
18
19 // Initial state: start from city 0 at week 0 with 0 vacation days
20 dp[0][0] = 0;
21
22 // Process each week
23 for (let week = 1; week <= numWeeks; week++) {
24 // For each destination city in current week
25 for (let destinationCity = 0; destinationCity < numCities; destinationCity++) {
26 // Option 1: Stay in the same city as previous week
27 dp[week][destinationCity] = dp[week - 1][destinationCity];
28
29 // Option 2: Fly from another city to destination city
30 for (let sourceCity = 0; sourceCity < numCities; sourceCity++) {
31 if (flights[sourceCity][destinationCity] === 1) {
32 dp[week][destinationCity] = Math.max(
33 dp[week][destinationCity],
34 dp[week - 1][sourceCity]
35 );
36 }
37 }
38
39 // Add vacation days for staying in destination city during this week
40 // Note: week-1 because days array is 0-indexed for weeks
41 dp[week][destinationCity] += days[destinationCity][week - 1];
42 }
43 }
44
45 // Return the maximum vacation days across all cities at the final week
46 return Math.max(...dp[numWeeks]);
47}
48
Time and Space Complexity
Time Complexity: O(K * n^2)
The algorithm uses dynamic programming with three nested loops:
- The outermost loop iterates through
K
weeks (whereK
is the number of weeks) - The middle loop iterates through
n
cities (wheren
is the number of cities) - The innermost loop also iterates through
n
cities to check all possible flights from cityi
to cityj
For each week k
and each destination city j
, we check all n
possible source cities i
, resulting in K * n * n = O(K * n^2)
operations.
Space Complexity: O(K * n)
The algorithm uses a 2D DP table f
with dimensions (K + 1) × n
:
K + 1
rows representing weeks from 0 to Kn
columns representing the cities
This gives us a space complexity of O((K + 1) * n) = O(K * n)
.
Note that the input arrays flights
(size n × n
) and days
(size n × K
) are not counted in the space complexity analysis as they are given inputs rather than auxiliary space used by the algorithm.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Forgetting Self-Loops in the Flight Matrix
A critical oversight is not accounting for the ability to stay in the same city without flying. The problem states "You can choose to stay in your current city instead of flying," but the flights
matrix might not explicitly include self-loops (i.e., flights[i][i]
might be 0).
The Issue: The current code only considers staying in the same city through this line:
dp[week][dest_city] = dp[week - 1][dest_city]
However, this only works if dp[week - 1][dest_city]
is already a valid state (not -inf
). If we can't reach dest_city
by the previous week, we won't consider staying there even if we could reach it in an earlier week and stay multiple weeks.
The Fix: Treat staying in the same city as a special case of "flying" by ensuring self-loops are considered:
for src_city in range(num_cities):
# Allow staying in the same city OR flying if a flight exists
if src_city == dest_city or flights[src_city][dest_city]:
dp[week][dest_city] = max(dp[week][dest_city], dp[week - 1][src_city])
2. Incorrect Handling of Unreachable States
The code adds vacation days even to unreachable cities (those with dp[week][dest_city] = -inf
), which can lead to incorrect results.
The Issue:
dp[week][dest_city] += days[dest_city][week - 1]
If dp[week][dest_city]
is still -inf
(unreachable), adding vacation days to it doesn't make sense and could cause issues with the final maximum calculation.
The Fix: Only add vacation days if the city is reachable:
if dp[week][dest_city] != float('-inf'):
dp[week][dest_city] += days[dest_city][week - 1]
3. Space Optimization Opportunity Missed
While not a correctness issue, the solution uses O(K × n) space when it could use O(n) space since we only need the previous week's data.
The Optimization: Use two 1D arrays instead of a 2D array:
prev = [float('-inf')] * num_cities
prev[0] = 0
for week in range(num_weeks):
curr = [float('-inf')] * num_cities
for dest_city in range(num_cities):
for src_city in range(num_cities):
if src_city == dest_city or flights[src_city][dest_city]:
curr[dest_city] = max(curr[dest_city], prev[src_city])
if curr[dest_city] != float('-inf'):
curr[dest_city] += days[dest_city][week]
prev = curr
return max(prev)
Complete Corrected Solution:
class Solution:
def maxVacationDays(self, flights: List[List[int]], days: List[List[int]]) -> int:
num_cities = len(flights)
num_weeks = len(days[0])
dp = [[float('-inf')] * num_cities for _ in range(num_weeks + 1)]
dp[0][0] = 0
for week in range(1, num_weeks + 1):
for dest_city in range(num_cities):
for src_city in range(num_cities):
# Can stay in same city or fly if flight exists
if src_city == dest_city or flights[src_city][dest_city]:
dp[week][dest_city] = max(dp[week][dest_city], dp[week - 1][src_city])
# Only add vacation days if city is reachable
if dp[week][dest_city] != float('-inf'):
dp[week][dest_city] += days[dest_city][week - 1]
return max(dp[-1])
Which of the following uses divide and conquer strategy?
Recommended Readings
What is Dynamic Programming Prerequisite DFS problems dfs_intro Backtracking problems backtracking Memoization problems memoization_intro Pruning problems backtracking_pruning Dynamic programming is an algorithmic optimization technique that breaks down a complicated problem into smaller overlapping sub problems in a recursive manner and uses solutions to the sub problems to construct a solution
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!