• [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;
        }
    }
    
  • 相关阅读:
    移动端疫情展示
    第五周学习进度
    第四周学习进度
    结队开发-四则运算
    第三周学习进度
    全球疫情可视化第一阶段
    第二周学习进度
    面试题 02.07. 链表相交 做题小结
    剑指 Offer 35. 复杂链表的复制 做题小结
    LeetCode 452. 用最少数量的箭引爆气球 做题小结
  • 原文地址:https://www.cnblogs.com/slowbirdoflsh/p/11349461.html
Copyright © 2020-2023  润新知