1152. Analyze User Website Visit Pattern

T: O(n^3)

S: O(n)

class Solution {
    class WebData {
        String website;
        int timestamp;
        WebData(String website, int timestamp) {
            this.website = website;
            this.timestamp = timestamp;
        }
        
    }
    public List<String> mostVisitedPattern(String[] username, int[] timestamp, String[] website) {
        int n = username.length;
        Map<String, List<WebData>> map = new HashMap<>();
        for (int i = 0; i < n; i++) {
            map.putIfAbsent(username[i], new ArrayList<>());
            map.get(username[i]).add(new WebData(website[i], timestamp[i]));
        }
        
        Map<String, Integer> countMap = new HashMap<>();
        String res = "";
        for (String name : map.keySet()) {
            // why set, ๅ› ็‚บไธ€ๆจฃ็š„ name, ๅฆ‚ๆžœๅ‡บ็พไธ€ๆจฃ็š„ pattern, ๅช่ƒฝ็ฎ—ไธ€ๆฌก, ๆ‰€ไปฅๅŒไธ€ๅ€‹ name ๅœจ่จˆ็ฎ—ๆ™‚, ้ฟๅ…ไธ€ๆจฃ็š„ pattern ่ขซ้‡่ค‡่จˆ็ฎ—
            // ๅˆฐไธ‹ๅ€‹name ๆ™‚, set ๅฐฑ้‡็ฝฎไบ†
            Set<String> set = new HashSet<>();
            List<WebData> list = map.get(name);
            Collections.sort(list, (a, b) -> a.timestamp - b.timestamp); // ้‚„ๆ˜ฏ้œ€่ฆๆŽ’ๅบ, ๆธฌ่ณ‡timstampๅฏ่ƒฝไธๆœ‰ๅบ
            
            // ๅ› ็‚บ pattern ๆ˜ฏไธ‰ๅ€‹website็ต„ๆˆ็š„, ๆ‰€ไปฅๅƒ james ๆœ‰ 4ๅ€‹็ถฒ็ซ™ "home","cart","maps","home"
            // ้€™ๆจฃ่ฆ 4ๅ–3ๅŽปๆŽ’ๅˆ—็ต„ๅˆๅ‡บไพ†ๆ‰€ๆœ‰ๅฏ่ƒฝ็š„ pattern, naive ๅฐฑๆ˜ฏ่ท‘ n^3
            for (int i = 0; i < list.size(); i++) {
                for (int j = i+1; j < list.size(); j++) {
                    for (int k = j+1; k < list.size(); k++) {
                        String pattern = list.get(i).website + " " + list.get(j).website + " " + list.get(k).website;
                        if (!set.contains(pattern)) {
                            countMap.put(pattern, countMap.getOrDefault(pattern, 0)+1); // ไธๅŒname, ไธ€ๆจฃ็š„ pattern count++ 
                            set.add(pattern); //้ฟๅ…ไธ€ๆจฃname, ไธ€ๆจฃ็š„pattern ่ขซ้‡่ค‡่จˆ็ฎ—
                        }
                        // res ้‚„ๆฒ’ๅ€ผๆ™‚, ็ตฆๅ€‹pattern
                        // ๆ–ฐ็š„ pattern count ๆฏ”่ผƒๅคงๆ™‚, ๆ›ดๆ–ฐ
                        // count ไธ€ๆจฃ็š„ๆ™‚ๅ€™ ็”จ lexicographically smallest such pattern
                        if ("".equals(res) || countMap.get(pattern) > countMap.get(res) || 
                           (countMap.get(pattern) == countMap.get(res) && res.compareTo(pattern) > 0)) {
                            res = pattern;
                        }
                    }
                }
            }
        }
        
        return Arrays.asList(res.split(" ")); // ๅ›žๅ‚ณ้€™ๅ”ฏไธ€็š„ pattern
        
    }
}

/*
["joe","home",1],["joe","about",2],["joe","career",3],["james","home",4],["james","cart",5],["james","maps",6],["james","home",7],["mary","home",8],["mary","about",9], and ["mary","career",10].


home about career
"home","cart","maps","home"
"home","about","career"

map
<name, pattern list>

-> pattern list should sort by timestamp

for each name
get list by name
build pattern use loop n^3 (exclude deplicate pattern count in same name), if another name deplicate pattern count is ok


at last if count is same, use lexicographically smallest such pattern


at last, only one pattern is the output

T: O(n^3)
*/

```java
class Solution {
    private record WebHistory(String website, int timestamp) {};
    public List<String> mostVisitedPattern(String[] username, int[] timestamp, String[] website) {
        Map<String, List<WebHistory>> nameToHistory = new HashMap<>();
        Map<String, Integer> visitedCount = new HashMap<>();
        for (int i = 0; i < username.length; i++) {
            nameToHistory.computeIfAbsent(username[i], k -> new ArrayList<>()).add(new WebHistory(website[i], timestamp[i]));
        }

        String maxPattern = "";
        int max = 0;
        for (String name : nameToHistory.keySet()) { // worst 1 (if only one name
            List<WebHistory> history = nameToHistory.get(name);
            history.sort((a, b) -> a.timestamp - b.timestamp); // worst nlogn (only one name, time len are n)
            
            Set<String> set = new HashSet<>(); // remember don't count duplicated pattern for same name
            for (int i = 0; i < history.size()-2; i++) { // O(n^3)
                for (int j = i+1; j < history.size()-1; j++) {
                    for (int k = j+1; k < history.size(); k++) {

                        StringBuilder websites = new StringBuilder();
                        websites.append(history.get(i).website).append(" ")
                            .append(history.get(j).website).append(" ")
                            .append(history.get(k).website);
                        String pattern = websites.toString();
                        if (!set.contains(pattern)) {
                            visitedCount.put(pattern, visitedCount.getOrDefault(pattern, 0)+1);   
                            set.add(pattern);                
                        }
                        // compare immideiatly is faster than sort all later
                        if ("".equals(maxPattern) || visitedCount.get(pattern) > max
                            || visitedCount.get(pattern) == max && maxPattern.compareTo(pattern) > 0) {
                            maxPattern = pattern;
                            max = visitedCount.get(pattern);
                        }
                    }
                }
            }
        }

        // List<String> result = new ArrayList<>(visitedCount.keySet());
        // result.sort((a, b) -> {
        //     if (visitedCount.get(a) == visitedCount.get(b)) {
        //         return a.compareTo(b);
        //     }
        //     return visitedCount.get(b) - visitedCount.get(a);
        // });
        List<String> res = new ArrayList<>();
        for (String str : maxPattern.split(" ")) {
            res.add(str);
        }
        return res;
    }
}

/***
T: O(nlogn + n^3..) 
S: O(n)

name pattern_list

pattern_list_3, count

 */
```

Last updated