- Link:1152. Analyze User Website Visit Pattern - Medium
- Track: NeetCode150
Question
Restate the problem
- Given three arrays
username,timestamp,website(each index = one visit event) - find the 3-sequence of websites visited by the most users.
- A 3-sequence is any ordered triple
(a, b, c)from a user’s visit history (not necessarily consecutive). - Return the lexicographically smallest if there’s a tie.
Edge Case
- A user with fewer than 3 visits →
combinationsreturns nothing, skipped naturally - Same user visits same pattern multiple times → count only once per user (use
set) - Tie on count → return lexicographically smallest pattern
| Method | Approach | Time Complexity | Space Complexity |
|---|---|---|---|
| Method 1 ⭐ | Sort + itertools.combinations | ||
| Method 2 | Sort + Manual triple loop |
Method 1
Key
- Use
set(combinations(sites, 3))per user- the
setprevents counting the same pattern twice for one user. Sort by timestamp first so combinations are in the correct order.
Approach
- Sort all events by timestamp, then group websites by user
- For each user, generate all unique 3-sequences using
combinationswrapped in aset - Count how many users have each pattern
- Return the pattern with the highest count — lexicographically smallest on tie
Complexity
- Time Complexity:
- visits to sort
- users each with up to visits
- Space Complexity: — storing all patterns
Code
from collections import defaultdict
from itertools import combinations
from typing import List
class Solution:
def mostVisitedPattern(self, username: List[str], timestamp: List[int], website: List[str]) -> List[str]:
# Step 1: group visits by user, sorted by timestamp
visits = defaultdict(list)
for t, u, w in sorted(zip(timestamp, username, website)):
visits[u].append(w)
# Step 2: count each 3-sequence across users
# set() ensures same pattern counted once per user even if visited multiple times
pattern_count = defaultdict(int)
for sites in visits.values():
for pattern in set(combinations(sites, 3)):
pattern_count[pattern] += 1
# Step 3: highest count, lexicographically smallest on tie
# sort key: (-count, pattern) → highest count first, lex smallest on tie
ranked = sorted(pattern_count, key=lambda p: (-pattern_count[p], p))
return list(ranked[0])Method 2 - Sort + Manual triple loop
Key
Same logic as Method 1 but replaces
itertools.combinationswith explicit triple nested loopsi < j < k. Thesetstill deduplicates patterns per user. Identical complexity — just more verbose and easier to trace manually.
Approach
- Sort events by timestamp, group by user
- For each user, iterate all index triples
(i, j, k)wherei < j < kto build 3-sequences - Use a
setper user to deduplicate, then incrementpattern_count - Sort by
(-count, pattern)and return the first
Complexity
- Time Complexity: — same as Method 1
- Space Complexity:
Code
class Solution:
def mostVisitedPattern(self, username: List[str], timestamp: List[int], website: List[str]) -> List[str]:
combine = sorted(zip(timestamp, username, website))
visited = defaultdict(list)
for t, u, web in combine:
visited[u].append(web)
pattern_count = defaultdict(int)
for web in visited.values(): # e.g. ['home', 'about', 'career']
n = len(web)
seen = set()
for i in range(n):
for j in range(i + 1, n):
for k in range(j + 1, n):
seen.add((web[i], web[j], web[k]))
for path in seen:
pattern_count[path] += 1
res = sorted(pattern_count.keys(), key=lambda x: (-pattern_count[x], x))[0]
return list(res)