Most Visited Sector in a Circular Track
EasyPrompt
Given an integer n and an integer array rounds. We have a circular track which consists of n sectors labeled from 1 to n. A marathon will be held on this track, the marathon consists of m rounds. The ith round starts at sector rounds[i - 1] and ends at sector rounds[i]. For example, round 1 starts at sector rounds[0] and ends at sector rounds[1]
Return an array of the most visited sectors sorted in ascending order.
Notice that you circulate the track in ascending order of sector numbers in the counter-clockwise direction (See the first example).
Example 1:
Input: n = 4, rounds = [1,3,1,2]
Output: [1,2]
Explanation: The marathon starts at sector 1. The order of the visited sectors is as follows:
1 --> 2 --> 3 (end of round 1) --> 4 --> 1 (end of round 2) --> 2 (end of round 3 and the marathon)
We can see that both sectors 1 and 2 are visited twice and they are the most visited sectors. Sectors 3 and 4 are visited only once.Example 2:
Input: n = 2, rounds = [2,1,2,1,2,1,2,1,2]
Output: [2]Example 3:
Input: n = 7, rounds = [1,3,5,7]
Output: [1,2,3,4,5,6,7]
Constraints:
2 <= n <= 1001 <= m <= 100rounds.length == m + 11 <= rounds[i] <= nrounds[i] != rounds[i + 1]for0 <= i < m
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly simulates the entire marathon as described in the problem. We maintain an array to store the visit count for each of the n sectors. We then traverse through all the rounds, and for each round, we simulate the path from the start sector to the end sector, incrementing the visit count for each sector along the path.
Algorithm
- Initialize an integer array
countsof sizen + 1to all zeros. - Increment the count for the starting sector of the marathon:
counts[rounds[0]]++. - Iterate through the
roundsarray fromi = 0torounds.length - 2. - Inside the loop, let
start = rounds[i]andend = rounds[i+1]. - Use a
whileloop to simulate the path fromstarttoend. Let acurrentpointer start atstart. - In each iteration of the
whileloop, movecurrentto the next sector (circularly:(current == n) ? 1 : current + 1) and increment the count for this new sector in thecountsarray. Stop whencurrentequalsend. - After the outer loop finishes, find the maximum value,
maxVisits, in thecountsarray. - Create a new list
result. - Iterate from
j = 1ton. Ifcounts[j]equalsmaxVisits, addjtoresult. - Return
result.
Walkthrough
The core of this method is to keep a frequency map (an array counts of size n+1 works well for 1-based indexing) of the sectors.
We start by noting the initial position of the marathon, rounds[0], and incrementing its count. Then, we loop through each of the m rounds defined by rounds[i] and rounds[i+1].
For each round, we simulate the movement from the current sector to the next, one step at a time, in a circular fashion. For every sector we land on, we increment its corresponding counter in our counts array.
After simulating all the rounds, the counts array will hold the total number of visits for each sector. The final step is to find the maximum visit count and collect all sectors that have this count. Since the sectors need to be returned in ascending order, we can iterate from sector 1 to n to build the final result list.
import java.util.ArrayList;import java.util.List; public class Solution { public List<Integer> mostVisited(int n, int[] rounds) { int[] counts = new int[n + 1]; // The marathon starts at sector rounds[0]. // We count this initial position. counts[rounds[0]]++; // Simulate each round for (int i = 0; i < rounds.length - 1; i++) { int start = rounds[i]; int end = rounds[i+1]; // Move from start to end, one sector at a time int current = start; while (current != end) { current = (current == n) ? 1 : current + 1; counts[current]++; } } // Find the maximum number of visits int maxVisits = 0; for (int count : counts) { if (count > maxVisits) { maxVisits = count; } } // Collect all sectors with the maximum number of visits List<Integer> result = new ArrayList<>(); for (int i = 1; i <= n; i++) { if (counts[i] == maxVisits) { result.add(i); } } return result; }}Complexity
Time
O(m * n), where `m` is the number of rounds (`rounds.length - 1`) and `n` is the number of sectors. In the worst case, each of the `m` rounds can traverse all `n` sectors.
Space
O(n) to store the visit counts for each sector in the `counts` array.
Trade-offs
Pros
It's a straightforward implementation that directly models the process described in the problem.
Easy to understand and debug.
Cons
The time complexity is proportional to the total path length of the marathon, which can be large. It is inefficient if
mornare large, although it passes within the given constraints.
A more insightful approach recognizes that the intermediate stops in the marathon don't alter which sectors are visited most frequently. For any intermediate sector s = rounds[i] (where 0 < i < rounds.length - 1), the marathon arrives at s and then departs from s. These cancel each other out. Furthermore, any full laps of the track add one visit to every sector, so they don't change the relative ordering of visit counts. The only thing that creates a difference in visit counts is the path covered from the marathon's overall start point, rounds[0], to its overall end point, rounds[rounds.length - 1]. Therefore, the most visited sectors are simply those on this single, direct path.
Algorithm
- Get the overall start sector,
start = rounds[0], and the overall end sector,end = rounds[rounds.length - 1]. - Create an empty list,
result, to store the most visited sectors. - Check if
start <= end:- If true, the path is direct. Iterate from
i = starttoendand add eachitoresult.
- If true, the path is direct. Iterate from
- Else (
start > end):- The path wraps around. To maintain sorted order in the result, first iterate from
i = 1toendand add eachitoresult. - Then, iterate from
i = starttonand add eachitoresult.
- The path wraps around. To maintain sorted order in the result, first iterate from
- Return the
resultlist.
Walkthrough
This optimized approach avoids simulating the entire marathon. The logic is based on a key observation: the relative frequency of visits is determined solely by the path from the first sector start = rounds[0] to the last sector end = rounds[rounds.length - 1].
Any full laps that occur during the intermediate rounds increase the visit count of every single sector by the same amount, thus not affecting which sectors are 'most' visited. The path segments between intermediate stops also have a net-zero effect on visit differentials.
So, the problem reduces to finding all sectors on the path from start to end.
There are two scenarios:
- If
start <= end, the path is a simple sequence:start, start + 1, ..., end. - If
start > end, the path wraps around the circular track:start, start + 1, ..., n, 1, 2, ..., end. We can construct the list of these sectors directly. To ensure the output is sorted as required, if the path wraps around, we first add sectors from1toendand then fromstartton.
import java.util.ArrayList;import java.util.List; public class Solution { public List<Integer> mostVisited(int n, int[] rounds) { List<Integer> result = new ArrayList<>(); int start = rounds[0]; int end = rounds[rounds.length - 1]; if (start <= end) { // Path does not wrap around for (int i = start; i <= end; i++) { result.add(i); } } else { // start > end // Path wraps around. Add segments to keep it sorted. // Segment 1: from 1 to end for (int i = 1; i <= end; i++) { result.add(i); } // Segment 2: from start to n for (int i = start; i <= n; i++) { result.add(i); } } return result; }}Complexity
Time
O(n). The time is dominated by the construction of the result list, which in the worst case involves iterating through all `n` sectors.
Space
O(n) for storing the result list. The size of the result can be up to `n`.
Trade-offs
Pros
Extremely efficient, as its runtime does not depend on the number of rounds
m.Simple to implement once the core insight is understood.
Cons
The logic is less intuitive and relies on an observation that might not be immediately obvious.
Solutions
Solution
class Solution {public List<Integer> mostVisited(int n, int[] rounds) { int m = rounds.length - 1; List<Integer> ans = new ArrayList<>(); if (rounds[0] <= rounds[m]) { for (int i = rounds[0]; i <= rounds[m]; ++i) { ans.add(i); } } else { for (int i = 1; i <= rounds[m]; ++i) { ans.add(i); } for (int i = rounds[0]; i <= n; ++i) { ans.add(i); } } return ans; }}class Solution {public: vector<int> mostVisited(int n, vector<int> &rounds) { int m = rounds.size() - 1; vector<int> ans; if (rounds[0] <= rounds[m]) { for (int i = rounds[0]; i <= rounds[m]; ++i) ans.push_back(i); } else { for (int i = 1; i <= rounds[m]; ++i) ans.push_back(i); for (int i = rounds[0]; i <= n; ++i) ans.push_back(i); } return ans; }};class Solution: def mostVisited(self, n: int, rounds: List[int]) -> List[int]: if rounds[0] <= rounds[- 1]: return list(range(rounds[0], rounds[- 1] + 1)) return list(range(1, rounds[- 1] + 1)) + list(range(rounds[0], n + 1))Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.