[leetcode 雙周賽 6] 1152 用戶網站訪問行為分析


1152 Analyze User Website Visit Pattern 用戶網站訪問行為分析

描述

為了評估某網站的用戶轉化率,我們需要對用戶的訪問行為進行分析,並建立用戶行為模型。
日志文件中已經記錄了用戶名訪問時間以及頁面路徑

為了方便分析,日志文件中的 N 條記錄已經被解析成三個長度相同且長度都為 N 的數組,分別是:用戶名 username,訪問時間 timestamp 和 頁面路徑 website。第 i 條記錄意味着用戶名是 username[i] 的用戶在 timestamp[i] 的時候訪問了路徑為 website[i] 的頁面。

我們需要找到用戶訪問網站時的 『共性行為路徑』,也就是有最多的用戶都 至少按某種次序訪問過一次 的三個頁面路徑。需要注意的是,用戶 可能不是連續訪問 這三個路徑的。

『共性行為路徑』是一個 長度為 3 的頁面路徑列表,列表中的路徑 不必不同,並且按照訪問時間的先后升序排列。

如果有多個滿足要求的答案,那么就請返回按字典序排列最小的那個。
(頁面路徑列表 X 按字典序小於 Y 的前提條件是:X[0] < Y[0] 或 X[0] == Y[0] 且 (X[1] < Y[1] 或 X[1] == Y[1] 且 X[2] < Y[2]))

題目保證一個用戶會至少訪問 3 個路徑一致的頁面,並且一個用戶不會在同一時間訪問兩個路徑不同的頁面。

  • 示例:

輸入:username = ["joe","joe","joe","james","james","james","james","mary","mary","mary"],
timestamp = [1,2,3,4,5,6,7,8,9,10],
website = ["home","about","career","home","cart","maps","home","home","about","career"]
輸出:["home","about","career"]
解釋:
由示例輸入得到的記錄如下:
["joe", 1, "home"]
["joe", 2, "about"]
["joe", 3, "career"]
["james", 4, "home"]
["james", 5, "cart"]
["james", 6, "maps"]
["james", 7, "home"]
["mary", 8, "home"]
["mary", 9, "about"]
["mary", 10, "career"]
有 2 個用戶至少訪問過一次 ("home", "about", "career")。
有 1 個用戶至少訪問過一次 ("home", "cart", "maps")。
有 1 個用戶至少訪問過一次 ("home", "cart", "home")。
有 1 個用戶至少訪問過一次 ("home", "maps", "home")。
有 1 個用戶至少訪問過一次 ("cart", "maps", "home")。

  • 提示:

3 <= N = username.length = timestamp.length = website.length <= 50
1 <= username[i].length <= 10
0 <= timestamp[i] <= 10^9
1 <= website[i].length <= 10
username[i] 和 website[i] 都只含小寫字符

思路

暴力枚舉每個用戶的順序網頁訪問路徑(有三個頁面)
選出訪問路徑出現最多次數的那個 或者 字典序排列最小的那個

代碼實現

重要存儲結構示意圖如下:

暴力枚舉每一用戶訪問路徑並投票

class Solution {
    public List<String> mostVisitedPattern(String[] username, int[] timestamp, String[] website) {
        // utwRecords 根據用戶名username組合三個數組 <username, <timestamp, website>>
        // 注意內部使用TreeMap 是為了排序 時間戳timestamp的按順序排列
        HashMap<String, TreeMap<Integer, String>> utwRecords = new HashMap<>();
        for (int i = 0; i < username.length; i++) {
            if (!utwRecords.containsKey(username[i])) {
                utwRecords.put(username[i], new TreeMap<Integer, String>());
            }
            utwRecords.get(username[i]).put(timestamp[i], website[i]);
        }

        // uwRecords 提取utwRecords中除時間戳timestamp的數據 
        // 用戶名username以及對應訪問的網頁website(按時間戳排序)
        HashMap<String, ArrayList<String>> uwRecords = new HashMap<>();
        for (String name : utwRecords.keySet()) {
            uwRecords.put(name, new ArrayList<String>());
            for (Integer time : utwRecords.get(name).keySet()) {
                uwRecords.get(name).add(utwRecords.get(name).get(time));
            }
        }

        // cntWP 存儲所枚舉的每一條網頁訪問路徑 並計錄其出現的次數
        // <網頁訪問路徑(3個網頁名稱合成1條字符串), 出現次數>
        HashMap<String, Integer> cntWP = new HashMap<>();
        // maxCnt 網頁訪問路徑出現最多次數為
        int maxCnt = 0;
        // res 最多次數的網頁訪問路徑(3個網頁名稱合成1條字符串)
        String res = new String();
        for (String name : uwRecords.keySet()) {
            // len 當前用戶所訪問的網頁數
            int len = uwRecords.get(name).size();
            // single 存儲當前用戶所訪問網頁的訪問路徑 並去重
            HashSet<String> single = new HashSet<>();
            for (int i = 0; i < len-2; i++) {
                for (int j = i+1; j < len-1; j++) {
                    for (int k = j+1; k < len; k++) {
                        // 網頁訪問路徑格式: A-->B-->C
                        String cur = (new StringBuilder()).append(uwRecords.get(name).get(i))
                        .append("->")
                        .append(uwRecords.get(name).get(j))
                        .append("->")
                        .append(uwRecords.get(name).get(k)).toString();
                        single.add(cur);
                    }
                }
            }

            // 遍歷當前用戶所訪問網絡的路徑 存儲並給訪問路徑計數
            for (String str : single) {
                if (!cntWP.containsKey(str)) {
                    cntWP.put(str, 0);
                }
                cntWP.put(str, cntWP.get(str)+1);

                int curCnt = cntWP.get(str);
                // 當該訪問路徑出現次數curCnt大於最大訪問次數maxCnt 
                //      那么結果路徑res就是該路徑
                // 或者
                // 當該訪問路徑出現次數curCnt等於最大訪問次數maxCnt 且字典序小於原出現次數最多的路徑res 
                //      那么結果路徑res就是該路徑
                if (curCnt > maxCnt | (curCnt == maxCnt && str.compareTo(res) < 0)) {
                    maxCnt = curCnt;
                    res = str;
                }
            }
        }

        // ans 存儲所求結果訪問路徑的3個網頁
        // 其實也可以使用 Arrays.asList(res.split("->"))
        ArrayList<String> ans = new ArrayList<>();
        for (String str : res.split("->")) {
            ans.add(str);
        }

        return ans;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM